1

I have a producer/consumers design in my application which implement Produce/Consume functions on user types. But it doesn't work very naturally with the standard library and especially with algorithms.

In C# there is the Enumerable and Observable concepts that can be used to easily implement stuff like this and get alot of nice free functionality.

In C++ there is the ios, istream, ostream, input_iterator, output_iterator concepts which I thought might be useful. But it seems to me that all of these are for primitive character types, e.g. char, int etc... and not for user types.

Sure I could use real functions such as Produce/Consumer and std::mem_fn for algorithms. But I was hoping there was a better way.

Im looking on some best-practice advice on how to go about designing i/o similar solutions on user types in C++.

E.g. from C#

class FrameProducer : IEnumerable<Frame> // pull frames
{...}

// Some engine between

class FrameConsumer : IObserver<Frame> // push frames
{...}

I was hoping for something similar in C++ e.g. which i dont believe is possible.

class FrameProducer : istream<Frame> // pull frames
{...}

// Some engine between

class FrameConsumer : ostream<Frame> // push frames
{...}

Maybe I'm thinking to hard about it and should just go by KISS.

Thoughts?

ronag
  • 49,529
  • 25
  • 126
  • 221
  • Why are you talking about C#? This is C++, forget you know C# and start programming in C++. Saying "I'd do it this way in language X, how can I translate it into language Y" will always fail, you must learn language Y from the ground up so you know how things are done in language Y. [A good book helps](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). Oh, and I don't get the question. Whenever you bring language X into a problem about language Y, many people that know language Y need you to explain that X language feature. – GManNickG Aug 21 '10 at 20:22
  • Can you explain better what you mean for "Produce/Consume functions on user types"? – Dacav Aug 21 '10 at 20:24
  • It doesn't matter what language I'm talking about, it's not to the point. I just picked C# because it was convenient since it had the LINQ concept which is similar to C++ and its iterators and algorithms. My question is why the C++ ios concept doesn't allow for user types and what alternatives there are. – ronag Aug 21 '10 at 20:26
  • I could for example implement a producer by having it provide an input_iterator instead of having a "Producer" function and in the same way a consumer by having it provide an output_iterator. Im just looking for a best practice. – ronag Aug 21 '10 at 20:27
  • produce/consume on user types. struct MyProducer { MyNiceClass Produce(); }; struct MyConsumer { void Consume(const MyNiceClass& item); }; – ronag Aug 21 '10 at 20:28
  • How then would i implement iostream::getline on a user type? My goal is to use the infrastructure provide by stl if possible instead of making up my own. – ronag Aug 21 '10 at 20:30
  • @Dacav I guess OP meant that Producer produces class instances rather then primitive types (such as `int`, `char`, etc). – Ihor Kaharlichenko Aug 21 '10 at 20:30
  • C++ *does* allow user types to be streamed, by overloading insertion and extraction operators. (I think the problem is your question asks about a step, rather than a problem. Your comment above actually describes a problem, which can be answered.) – GManNickG Aug 21 '10 at 20:32
  • I am simply astonished people are not familiar with and therefore reject the ENTIRE body of work called COMPARATIVE ANALYSIS and the entire body of LOGIC in relation to Comparative Analysis. It’s a great way to force yourself into a barren intellectual ghetto. Enjoy the soulless rap. – JustBoo Aug 21 '10 at 20:39
  • 1
    Are you familiar with duck typing? That's generally how C++ deals with IEnumerable and the like. If you want to write to streams, then overload <<. If you want to iterate over a collection, make something that looks like an iterator. Your FrameProducer would likely provide a `begin()` and `end()` method that produces those iterators, which would allow it to be used places that expect traditional containers. – Dennis Zickefoose Aug 21 '10 at 22:39

2 Answers2

3

Th terms are "insertion operator" and "extraction operator", which insert and extract data from a stream.

Here's an example:

#include <iostream>
#include <sstream>

struct foo
{
    int x;
};

// insertion operator
std::ostream& operator<<(std::ostream& s, const foo& f)
{
    s << f.x; // insert a foo by inserting x
    return s;
}

// extraction operator
std::istream& operator>>(std::istream& s, foo& f)
{
    s >> f.x; // extract a foo by extracting x
    return s;
}

int main(void)
{
    std::stringstream ss;

    foo f1 = {5};
    ss << f1;

    foo f2;
    ss >> f2;
}

Based on your desire to do:

MyFrameProducer producer;
MyFrameConsumer consumer;
Frame frame; // frame should probably be in the while loop, since its 
while(!producer.eof()) // lifetime doesn't need to exist outside the loop
{
    producer >> frame;
    consumer << frame;
} 

You might make:

struct MyFrameProducer {}; // add an eof function
struct MyFrameConsumer {};
struct Frame {};

// producer produces a frame
MyFrameProducer& operator>>(MyFrameProducer& p, Frame& f)
{
    /* whatever it takes to make a frame */

    return p;
}

// consumer consumes a frame
MyFrameConsumer& operator<<(MyFrameConsumer& c, const Frame& f)
{
    /* whatever it takes to use a frame */

    return c;
}

Or something akin to it. (Sorry my understanding of the problem is small.) It is a bit weird to desire this interface, since it has nothing to do with streams, and you might be better off with a different interface (explicit methods).

Philipp
  • 48,066
  • 12
  • 84
  • 109
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • Not quite, what you show is how to convert a user type to a string. I was looking for something like this (which doesn't work since the stl istream/ostream seems to be character based) class MyFrameProducer : istream { } class MyFrameConsumer : ostream { } int main() { MyFrameProducer producer; MyFrameConsumer consumer; Frame frame; while(!producer.eof()) { producer >> frame; consumer << frame; } } – ronag Aug 21 '10 at 20:42
  • 1
    @ronag: I did *not* show how to convert a user type into a string, I showed how to insert it into a stream. (Only coincidentally does `stringstream` provide a way of producing a string.) Let me edit the answer to your comment snippet. – GManNickG Aug 21 '10 at 20:45
  • @Philipp: No, don't worry. I made it CW because I'm basically guessing, it wasn't your edit. And thanks. :) – GManNickG Aug 21 '10 at 21:32
2

Take a look at this producer/consumer solution. Although it is in pure C it is so elegant so I just can't resist from posting it.

Ihor Kaharlichenko
  • 5,944
  • 1
  • 26
  • 32
  • 1
    Interesting, this seems also interesting: http://www.crystalclearsoftware.com/soc/coroutine/ – ronag Aug 21 '10 at 20:43