
On Thu, Oct 11, 2012 at 2:43 PM, Oliver Kowalke <oliver.kowalke@gmx.de> wrote:
auto fn(coroutine<string(int)> c) { assert(!c.has_data()); c(10); assert(c.has_data() && c.get() == "abc"); return c; }
coroutine< int( string) > c( fn); assert(c.has_data() && c.get() == 10); c( "abc"); assert(c.terminated());
as in one of the previous examples - your example does not work if the return value depends on the arguments passed to coroutine
well, this is true only for the first yielded return. If the coroutine-fn must not yield a value without receiving one first, it will have to call c.yield() to yield without value. It is ugly, I know, it is yet another deparature from coroutines-as-functions model. Unfortunately there is no way out of this: either the caller or the calle must return the first message without seeing the other side's message. You could have two functions: make_push_coroutine() and make_pull_coroutine() (the names are terribly long, but they are just to give an idea) which allows the user to chose the preferred behaviour. Another option is allowing passing additional arbitrary parameters to the coroutine constructor, as per std::thread. The coroutine-fn may (or not) use these parameters as if they were the result of yielding. There shouldn't be any requirements that the paremeters match the coroutine signature though. As with std::thread and std::bind, and differently than operator(), the parameters are always passed by copy and need an explicit ref() to pass by reference. This prevent the dangling reference problem that was raised during review. The biggest reason for having these extra parameters is coroutine pipelining: { auto pass1 = make_coroutine([](continuation<void(int)> output) { for(int i = 0; i < 10; ++i) output(i); return output; }); auto pass2 = make_coroutine ([](coroutine<void(double)> output, coroutine<int()> input) { for(auto x: input) { output(x*2); } return output; }, std::move(pass1)); std::vector<double> ret = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 }; assert(std::equal(begin(pass2), end(pass2), ret.begin())); } You could of course acheive the same thing by explicitly calling std::bind, but the syntax become heavier. You can't unfortuantley rely on c++ [=] lambda capture because a coroutine is not copyable (and [&] doesn't really sound right). Note that from the point of view of the pass2 coroutine-fn, there isn't really much difference between the input and the output, they are just two arbitrary coroutines. -- gpd