
Especially if generator does not support movable-only types, I am afraid that this will be a common tripping point. Giovanni's design had the same issue which he advised to avoid by using the iterator like interface (using operator* and operator++).
It is an issue of boost.tuple - if tuples can handle moveable objects, boost.coroutine will handle it too.
Maybe we can change behavior so that generator's constructor does not invoke the generator-function, only operator() does. And change operator() to return optional<R> instead of R. The usage can then be:
gen_t g(foo); while( optional<X> val = g() ) { // use val.get() }
what would be the benefit?
I'm not really sure about what to do about is_complete() or operator unspecified-bool-type(), though. Maybe they are not needed at all?
coroutines are used like this: - 'if ( coro)' // coroutine has an coroutine-fn attached and can be used - 'coro.is_complete()' coroutine has returned and can not resumed generators: - 'if (gen) // generator is valid and has an value so that 'gen()' returns a value generators have no 'is_complete()' function (contained in the unspec_bool operator()).
I admit that this interface might be a bit quirky but if the library also provides input iterator, that can become the primary interface. Generators are used to produce sequences and iterators are the central mechanism of dealing with sequences in C++. So the iterator usage could be:
for( gen_t::iterator it = g.begin(); it != g.end(); ++it ) { X* val = *it; // no dangling pointers }
(or BOOST_FOREACH, C++11 range-based for, or for_each).
g.begin() or gen_t::iterator ctor would invoke the generator-function for the first time and ++it for all subsequent times.
Shouldn't iterators be implemented on top of generators/coroutines? Oliver