public void Consumer()
{
foreach(int i in Integers())
{
Console.WriteLine(i.ToString());
}
}
public IEnumerable<int> Integers()
{
yield return 1;
yield return 2;
yield return 4;
yield return 8;
yield return 16;
yield return 16777216;
}
有没有办法用模板技巧(或其他)在c ++中获得相同的语法?
答案 0 :(得分:24)
看一下boost :: Coroutine。它做你想要的。 http://www.crystalclearsoftware.com/soc/coroutine/index.html#coroutine.intro
教程中的示例
http://www.crystalclearsoftware.com/soc/coroutine/coroutine/tutorial.html
int range_generator(generator_type::self& self, int min, int max)
{
while(min < max)
self.yield(min++);
self.exit();
}
答案 1 :(得分:8)
您可以随时手动编码。说实话,yield
对我来说真的好像糖涂层(也是合作惯例)。
真正的协程是什么?有些州与:
捆绑在一起在C ++中,它被称为InputIterator
,可以任意胖。
所以,确实语法不会那么漂亮,但只需使用标准库就可以了:
static std::array<int, 6> const Array = {{1, 2, 4, 8, 16, 16777216}};
class Integers: public std::iterator<std::input_iterator_tag,
int, ptrdiff_t, int const*, int>
{
public:
Integers(): _index(0) {}
operator bool() const { return _index < Array.size(); }
Integers& operator++() { assert(*this); ++_index; return *this; }
Integers operator++(int) { Integers tmp = *this; ++*this; return tmp; }
int operator*() const { assert(*this); return Array[_index]; }
int const* operator->() const { assert(*this); return &Array[_index]; }
private:
size_t _index;
}; // class Integers
显然,由于你确切地确定了什么状态存储,你决定是否所有状态都是预先计算的,或者是否部分(或整个部分)被懒惰地计算,并且可能被缓存,并且可能是多 - 螺纹,......你明白了这一点:)
答案 2 :(得分:8)
在C ++ 14中,您可以通过这种方式模仿yield
:
auto&& function = []() {
int i = 0;
return [=]() mutable {
int arr[] = {1,2,4,8,16,16777216};
if ( i < 6 )
return arr[i++];
return 0;
};
}();
提供了一个实时示例
答案 3 :(得分:2)
以下是ASM“滚动您自己的”版本:http://www.flipcode.com/archives/Yield_in_C.shtml
答案 4 :(得分:1)
尝试在c ++ coroutine
中实现yield答案 5 :(得分:1)
如果您需要的只是类似于foreach的东西,那么C ++中提供了以下语法:
#define GENERATOR(name) \
struct name \
{ \
template<typename F> \
void operator()(F yield) \
/**/
#define _ };
template<typename Gen>
struct Adaptor
{
Gen f;
template<typename C>
void operator*(C cont)
{
f(cont);
}
};
template<typename Gen>
Adaptor<Gen> make_adaptor(Gen gen)
{
return {gen};
}
#define FOREACH(arg, gen) make_adaptor(gen) * [&](arg)
#include <iostream>
using namespace std;
GENERATOR(integers)
{
yield(1);
yield(2);
yield(4);
yield(8);
yield(16777216);
}_
int main()
{
FOREACH(int i, integers())
{
cout << i << endl;
};
}
如果您需要一点协程“权力”,那么您可以尝试stackless coroutines。
或者,如果你需要充足的力量 - 那么请使用堆栈协程。有Boost.Coroutine库可以为不同的平台实现堆栈协程。
答案 6 :(得分:1)
为C ++ 17提出了类似的东西,并且在Visual C ++ 2015中已经有了一个实验性的实现。以下是来自Gor Nishanov的一个很好的概述talk,这是该提案的主要作者之一。
答案 7 :(得分:1)
Coroutines are in the C++20 draft并使用co_yield
代替yield
。
另请参阅:What are coroutines in C++20?
第一个链接中有一些用法示例:(第二个可能是您要查找的内容)
使用
co_await
运算符暂停执行直到恢复执行task<> tcp_echo_server() { char data[1024]; for (;;) { size_t n = co_await socket.async_read_some(buffer(data)); co_await async_write(socket, buffer(data, n)); } }
使用关键字
co_yield
暂停执行并返回值generator<int> iota(int n = 0) { while(true) co_yield n++; }
使用关键字
co_return
完成返回值的执行lazy<int> f() { co_return 7; }
答案 8 :(得分:0)
当然,您可以随时编写自己的迭代器并根据需要从它们返回,但为什么要这样做?在给定的示例中,为什么不简单地将您的值放入像vector这样的容器中并迭代它?
答案 9 :(得分:0)
#include <setjmp.h>
class superclass
{
public:
jmp_buf jbuf;
public:
virtual int enumerate(void) { return -1; }
};
class subclass: public superclass
{
public:
int enumerate()
{
static int i;
static bool b = false;
if(b)
longjmp(jbuf, 1);
for(b = true, i = 0; i < 5; (i)++)
{
printf("\ndoing stuff: i = %d\n", i);
if(setjmp(jbuf) != 1)
return i;
}
return -1;
}
};
使用代码......
int iret;
subclass *sc;
sc = new subclass();
while((iret = sc->enumerate()) != -1)
{
printf("\nsc->enumerate() returned: %d\n", iret);
}
刚刚开始工作;现在看起来很简单,虽然我有一些错误的开头:)
答案 10 :(得分:0)
如果您撰写static unsigned int checkpoint = 0;
,请将所有变量设为static
,switch (checkpoint)
,将每个case: goto
设置为某个标签,在每个return
设置检查点上方设置为唯一value,并在下面定义label,并在函数集的末尾设置检查点为零,并将所有静态变量设置为其默认值,并在最后return
为函数的结束值。如果您完成所有这些操作,则该功能将变为可枚举和迭代。您在每个return
行的上方和下方添加的两行使return
命令的行为类似于yield return
。 goto
允许您继续并从中断的地方恢复,static
整数变量(如检查点)可帮助您记住停止的位置,继续/恢复的位置以及去向何处。您可以使用switch case
语句测试它的值。制作所有其他变量static
,就是将它们的值保存到下一个调用中,因此在下一次调用中,它们的值不会被重置!
例如:
#define PowerEnd INT_MIN
int Power(int number, int exponent)
{
static unsigned int checkpoint = 0;
static int result = 1, i = 0;
switch (checkpoint)
{
case 1: goto _1;
}
for (i = 0; i < exponent; i++)
{
result *= number;
checkpoint = 1;
return result;
_1:;
}
checkpoint = 0;
result = 1;
i = 0;
return PowerEnd;
}
void main()
{
while (true)
{
int result = Power(2, 8);
if (result == PowerEnd)
break;
cout << result << endl;
}
//to print only the first 4 results (if there are at least 4 results) then
for (int i = 0; i < 4; i++)
{
int result = Power(2, 8);
if (result == PowerEnd)
break;
cout << result << endl;
}
}
上述程序产生以下输出:
2 4 8 16 32 64 128 256 2 4 8 16