用C ++ 0x实现生成器

时间:2011-11-16 15:04:49

标签: c++ c++11 generator

python关键字yield对我来说是一个很好的概念抽象,允许我将算法的重要部分提炼为人类可读的形式。我们之前已经讨论过:

Python generators in various languages

在C ++中给出了一个仅限Windows的库的答案。另外,我在问题中找到了另一个使用时髦宏扩展的例子:

Generators in C++ — invalid use of nonstatic data member

我的计算机科学知识的边缘告诉我,yield函数有something to do with co-routines和monad,但我并不完全符合C ++或C ++ 0x可以完成的任务。

似乎在C ++中,如果不使用宏扩展或仅使用Windows光纤(线程),则无法实现yeild。这是真的?问题是否随C ++ 0x的其他语言功能而改变?

3 个答案:

答案 0 :(得分:4)

您可以将yield python机制映射到C ++迭代器。

请参阅Boost Function Input Iterator和示例:

  

Function Input Iterator允许创建封装了一个nullary函数对象的迭代器和一个跟踪迭代器递增次数的状态对象。函数输入迭代器模拟InputIterator概念,对创建有界输入迭代器非常有用。

     

与Generator Iterator类似,Function Input Iterator采用一个模拟Generator概念的函数(基本上是一个nullary或0-arity函数对象)。函数Function Input Iterator的每个增量调用生成器函数并将值存储在迭代器中。取消引用迭代器时,将返回存储的值。

答案 1 :(得分:3)

yield基本上是一种实现限制形式的协同程序的方法。

如果你想要足够严重,你可以使用setjmplongjmp在C中实现相对完整的协同程序(就像“人们有”)。在C ++中,你可以可能做同样的事情,尽管我并不完全确定。 C ++的问题变成了决定执行什么dtors时的问题。另外,我认为答案是dtors应该不会受到coroutine使用的影响,但我并没有真正考虑过它。假设这是正确的,那么大致相同的代码应该适用于C ++和C。

C ++ 0x增加了对线程等的全面支持。虽然它可能是笨拙和/或增加开销,几乎任何你可能希望用纤维做的事情,你也可以做线程。因此,它会更直接地支持这个成语,因此实现起来会相当容易。

答案 2 :(得分:1)

嗯,我自己从未使用过生成器,但据我所知,你想要一些返回实现增量运算符++的迭代器的函数。伪代码:

int f(int x) {
    for(int i = 0; i < x; ++i) {
        yield(i);
    }
}

for(iterator it = make_generator(std::bind(f, 5));
    it != generator_end();
    ++it)
{
    do_something(*it);
}

// iterator specialized for the return type of f
template<typename T>
iterator<T> make_generator(Function<T (void)> f) {
    ...
}

您需要从指向函数f的指针构造迭代器,并且可以使用f将任何参数传递给std::bind

现在在每次迭代中,您需要在某个时刻有效地调用f并且函数yield必须执行一些堆栈操作以保存当前堆栈,返回生成的值并在函数时恢复堆栈再次被召唤。您只需要将堆栈保存到调用f的位置(不需要整个堆栈),但这可能很难实现。您可能必须在调用f之前保存堆栈指针,然后在某处复制(先前的堆栈指针...当前堆栈指针)的内容。