I have been using yield in many of my Python programs, and it really clears up the code in many cases. I blogged about it and it is one of my site\'s popular pages.
Well, for such a trivial example as that, the only problem I see is that std::type_info::hash_code() is not specified constexpr. I believe a conforming implementation could still make it so and support this. Anyway the real problem is obtaining unique identifiers, so there might be another solution. (Obviously I borrowed your "master switch" construct, thanks.)
#define YIELD(X) do { \
constexpr size_t local_state = typeid([](){}).hash_code(); \
return (X); state = local_state; case local_state: ; } \
while (0)
Usage:
struct GeneratedFibonacci {
size_t state;
int a, b;
GeneratedFibonacci() : state (0), a (0), b (1) {}
int operator()() {
switch (state) {
case 0:
while (true) {
YIELD( a );
int c = a + b;
a = b;
b = c;
}
}
}
}
Hmm, they would also need to guarantee that the hash isn't 0. No biggie there either. And a DONE macro is easy to implement.
The real problem is what happens when you return from a scope with local objects. There is no hope of saving off a stack frame in a C-based language. The solution is to use a real coroutine, and C++0x does directly address that with threads and futures.
Consider this generator/coroutine:
void ReadWords() {
ifstream f( "input.txt" );
while ( f ) {
string s;
f >> s;
yield s;
}
}
If a similar trick is used for yield, f is destroyed at the first yield, and it's illegal to continue the loop after it, because you can't goto or switch past a non-POD object definition.