在C ++中将lazy generator实现为forward_iterator

时间:2014-12-22 14:01:13

标签: c++ boost stl iterator boost-iterators

MyGenerator表示(可能)有限的整数序列,计算起来很昂贵。因此,我不想提前将它们全部生成并将它们放入容器中。

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

全部打印:

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

如何实现遵循forward_iterator协议的类似生成器?

boost::function_input_iterator接近,但我不知道前面的元素数量。

1 个答案:

答案 0 :(得分:3)

首先,看看boost::function_input_iterator的实现,因为你想要的是相同的,除了测试迭代器的相等性必须被修改以应对你不知道它是否是无限的事实,如果不是有多少件物品。一旦你习惯了这种风格,Boost的作者会通过他们的代码给你更好的建议: - )

那就是说,这些内容(未经测试):

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; 
};
  • 原则上,count可以换行,虽然你只需要担心使用小size_t的实现,因为64位在实践中永远不会包装。为了安全起见,您可以使用其他类型来保持计数:uint64_t或者所有其他类型都是用户定义的大整数类型。不过请参考std::iterator文档,因为一旦迭代器的运行时间超过size_t,您就想给它一个非默认的difference_type
  • 类型Generator必须是可复制的(并且副本必须与原始类型具有相同的状态,并且其后两个必须独立前进)否则您没有机会实现forward_iterator而不是存储来自发电机的潜在无限量的输出。如果您只需要input_iterator,那么您可以参考Generator参考。
  • 如果您不需要包装前一个MyGenerator,而只是想知道如何编写一个可能无限的迭代器,那么您可以摆脱模板参数,存储您喜欢的任何状态迭代器,只需将代码放在advance()中推进状态。