C++相当于 C# 产量
本文关键字:产量 相当于 C++ | 更新日期: 2023-09-27 18:06:53
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++ 中获得相同的语法?
看看 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();
}
您始终可以手动编写代码。说实话,对我来说,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
显然,由于您确切地决定了存储什么状态,因此您可以决定是否所有状态都是预先计算的,或者部分(或全部(是延迟计算的,可能是缓存的,可能是多线程的,以及......你的想法:)
程自 C++20 年以来就在标准库中,并使用 co_yield
而不是 yield
。
另请参阅:C++20 中的协程是什么?
第一个链接中有一些示例用法:(第二个可能是您要查找的(
使用
co_await
运算符暂停执行,直到恢复task<> tcp_echo_server() { char data[1024]; while (true) { 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; }
在 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;
};
}();
现场示例可在 http://ideone.com/SQZ1qZ
这是ASM"滚动你自己的"版本: http://www.flipcode.com/archives/Yield_in_C.shtml
#include <stdio.h
#include <conio.h
#include <iostream.h
//
// marks a location in the program for resume
// does not return control, exits function from inside macro
//
// yield( x, ret )
// x : the 'name' of the yield, cannot be ambiguous in the
// function namespace
// ret : the return value for when yield() exits the function;
// must match function return type (leave blank for no return type)
#define yield(x,ret) '
{ '
/* store the resume location */ '
__asm { '
mov _myStaticMkr,offset label_##x '
} '
'
/* return the supplied value */ '
return ret; '
} '
/* our offset in the function */ '
label_##x:
//
// resumes function from the stored offset, or
// continues without notice if there's not one
// stored
//
// resume()
// <void
#define resume() '
/* our stored offset */ '
static _myStaticMkr=0; '
'
/* test for no offset */ '
if( _myStaticMkr ) '
{ '
/* resume from offset */ '
__asm '
{ '
jmp _myStaticMkr '
} '
}
// example demonstrating a function with an int return type
// using the yield() and resume() macros
//
// myFunc()
// <void
int myFunc()
{
resume();
cout << "1'n";
yield(1,1);
cout << "2'n";
yield(2,1);
cout << "3'n";
yield(3,1);
cout << "4'n";
return 0;
}
// main function
//
// main()
// <void
void main( void )
{
cout << "Yield in C++'n";
cout << "Chris Pergrossi'n'n";
myFunc();
do
{
cout << "main()'n";
cout.flush();
} while( myFunc() );
cout.flush();
getch();
}
/*
// example demonstrating a function with no return type
// using the yield() and resume() macros
//
// myFunc()
// <void
void myFunc()
{
resume();
cout << "1'n";
yield(1);
cout << "2'n";
yield(2);
cout << "3'n";
yield(3);
cout << "4'n";
return;
}
// main function
//
// main()
// <void
void main( void )
{
cout << "Yield in C++'n";
cout << "Chris Pergrossi'n'n";
myFunc();
for( int k = 0; k < 4; k ++ )
{
cout << "main()'n";
cout.flush();
myFunc();
}
cout.flush();
getch();
}
*/
如果你所需要的只是类似 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;
};
}
现场演示
如果您需要一点协程"幂",那么您可以尝试无堆栈协程。
或者,如果您需要全功率 - 则可以使用堆叠协程。有 Boost.Coroutine 库,它为不同的平台实现了堆叠的协程。
尝试在 c++ 协程中实现 yield
如果你写static unsigned int checkpoint = 0;
,让你所有的变量static
,switch (checkpoint)
,将每个case: goto
设置为某个标签,在每个return
上方将检查点设置为唯一值,在下面定义标签,在函数末尾将检查点设置为零,将所有静态变量设置为默认值,最后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;
}
}
上述程序生成以下输出:
阿拉伯数字 4 8 16 32 64 128 256 2 4 8 16
在 C++17 中提出了类似的东西,并且在 Visual C++ 2015 中已经有一个实验性实现。这是该提案的主要作者之一Gor Nishanov的一个很好的概述演讲。
#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);
}
刚刚开始工作; 现在看起来很简单,尽管我有一些错误的开始:)
您始终可以编写自己的迭代器,并从中返回任何您想要的内容,但是您为什么要这样做呢?在给定的示例中,为什么不简单地将您的值放入像 vector 这样的容器中并对其进行迭代呢?