在 C++ 中,coroutine 是可暂停以及可恢复执行的函数,在定义一个函数时,如果函数体中出现了 co_yield
, co_return
或者 co_await
关键字,则该函数会被编译器视为一个 coroutine, 并且按照 coroutine 的方式来翻译,然而,在定义 coroutine 时需要注意几个限制:
一是co_yield
, co_return
, 和 co_await
这些关键字并不是能出现在任何地方;
二是 coroutine(作为函数)的返回值类型有要求,而且返回值类型不能是 auto
, decltype(auto)
这样的 type placeholder;
具体这些限制和要求我们限于篇幅不会详细讲述,但是感兴趣的读者可以参考 cppreference 上的 coroutine 资料页面。
本文是初级的并且面向初级读者,本文的目标是教会读者如何快速写好一个 coroutine 的返回值类型的定义。
这是一篇力求快速,但是极其不严谨的教程,后续如果有机会,我们会提供一篇比这个稍微严谨一些的文章做 coroutine 的原理解释,可能会从编译器如何翻译 coroutine 的角度来说,其中可能会涉及到源码/机器码分析。
我们不希望从 coroutine 的执行过程、原理或者是编译器如何翻译 coroutine 这种角度开始讲,我觉得最快的学习方式是上手去做,那么我们可以先打开 IDE(推荐 CLion),新建一个项目,C++ 标准选 C++20,然后直接在 main.cpp 文件中开始编辑。
我们注意到在 Python 中有类似这样的代码:
def my_range(n):
while True:
yield n
n = n + 1
num_limits = 10
for x in my_range(1):
print(x)
num_limits = num_limits - 1
if num_limits <= 0:
break
# 输出内容是打印前 10 个正整数
在 Python 中像 my_range
这样定义的函数称为 generator, 特点就是它的函数体中有 yield
语句。
事实上有了 C++20 引入了 coroutine 语法的支持,在 C++ 中也能实现类似的效果,我们就首先来尝试在 C++ 中实现这个 my_range
函数。
在 main.cpp 中首先定义一个结构体:
struct generator {};
这里的 generator
这个名字不是固定的,可以修改。