c++booststliteratorboost-iterators

Implement lazy generator as forward_iterator in C++


MyGenerator represents a (possibly) finite sequence of integers, that is expensive to compute. So I don't want to generate them all upfront and put them into a container.

struct MyGenerator{
  bool HasNext();
  int Next();
}

To print them all:

MyGenerator generator;
while (generator.HasNext()) {
  std::cout << generator.Next() << std::endl;
}

How to implement a similar generator that follows the protocol of a forward_iterator?

boost::function_input_iterator comes close, but I do not know the number of elements upfront.


Solution

  • First off, look at the implementation of boost::function_input_iterator, since what you want is the same except that testing the equality of iterators must be modified to cope with the fact you don't know whether it's infinite and if not how many items there are. Once you get used to the style, the authors of Boost will give you better advice via their code than I will :-)

    That said, something along these lines (untested):

    template <typename Generator>
    struct generator_iterator : iterator<forward_iterator_tag, int> {
        generator_iterator(const Generator &gen, end = false) : count(0), gen(gen), last_val(0), is_end(end) {
            if (!end) advance();
        }
        void advance() {
            if (gen.HasNext()) {
                lastval = gen.Next();
            } else {
                is_end = True;
            }
            count += 1;
        }
        int operator *() {
            return lastval;
        }
        generator_iterator &operator++() {
            advance();
            return *this;
        }
        generator_iterator operator++(int) {
            generator_iterator result = *this;
            advance();
            return result;
        }
        bool operator==(const generator_iterator &rhs) {
            return (is_end && rhs.is_end) || (count == rhs.count);
        }
        bool operator!=(const generator_iterator &rhs) {
            return !(*this == rhs);
       }
    
        size_t count;
        Generator gen;
        int lastval;
        bool is_end; 
    };