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的其他语言功能而改变?
答案 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
基本上是一种实现限制形式的协同程序的方法。
如果你想要足够严重,你可以使用setjmp
和longjmp
在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之前保存堆栈指针,然后在某处复制(先前的堆栈指针...当前堆栈指针)的内容。