Generators in C++

As we know iterators in C++ is a good but not perfect abstraction. Concept of foreach() (D, Python, Ruby, etc.) appears as more generic solution. At least foreach() does not require artificial iterator::end() to be defined for the collection.

Abstraction foreach() can be imagined as some function/object that is returning next value of collection/sequence each time it is getting invoked. Such functions are known as generators.

Here is my version of generator() for the C++. It is based on the bright idea of Simon Tatham – “coroutines in C“.

First of all sample, here is a declaration of our generator function in C++:

#include "generator.h"

generator(descent) 
{
   int i;
   emit(int) // will emit int values. Start of body of the generator.
      for (i = 10; i > 0; i--)
         yield(i); // a.k.a. yield in Python - return next number in [1..10], reversed.
   stop(0); // stop, end of sequence. End of body of the generator.
};

Having declared such generator we can use it as:

int main(int argc, char* argv[])
{
  descent gen;
  do
    printf("next number is %d\n", gen());
  while (gen);
  return 0;
}

That is pretty simple and should be intuitively clear, no?

Here is full source of the generator.h file:

// generator/continuation for C++
// author: Andrew Fedoniouk @ terrainformatica.com
// idea borrowed from: "coroutines in C" Simon Tatham, 
//                     http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html

#ifndef __generator_h_
#define __generator_h_

struct _generator
{
  int _line;
  _generator():_line(-1) {}
  operator bool() const { return _line != 0; }
};

#define generator(NAME) struct NAME : public _generator

#define emit(T)     T operator()() { \
                     if(_line < 0) { _line=0;}\
                     switch(_line) { case 0:;

#define stop(V)     } _line = 0; return (V); }

#define yield(V)     \
        do {\
            _line=__LINE__;\
            return (V); case __LINE__:;\
        } while (0)

#endif // __generator_h_

Enjoy!