与 C++20 中的简单有状态 lambda 相比,`co_yield` 的特殊值是什么?
What's the special value of `co_yield` in contrast to a simple stateful lambda in C++20?
来自著名的 C++ 协程库(在源文件 generator.hpp 中搜索“Don't allow any use of co_await
inside the generator coroutine.”),以及我自己的实验,我知道使用 co_yield
的协程不能同时使用 co_await
。
既然使用 co_yield
的生成器必须是同步的,那么使用 co_yield
相对于简单的有状态 lambda 有什么优势?
例如:
#include <iostream>
generator<int> g()
{
for (auto i = 0; i < 9; ++i)
{
co_yield i;
}
}
int main()
{
auto fn_gen = [i = 0] mutable { return i++; };
// Lambda way
for (auto i = 0; i < 9; ++i)
{
std::cout << fn_gen() << std::endl;
}
// co_yield way
for (auto i : g())
{
std::cout << i << std::endl;
}
}
co_yield
与 C++20 中的简单状态 lambda 相比有什么特殊价值?
请查看更新后的 MWE:https://godbolt.org/z/x1Yoen7Ys
在更新的示例中,在同一个协程中使用 co_await
和 co_yield
时,输出完全出乎意料。
对于内部状态和代码最少的普通生成器,小型仿函数或 lambda 就可以了。但是随着您的生成器代码变得越来越复杂并且需要更多的状态,它变得不那么好。您必须在仿函数类型或 lambda 说明符中添加更多成员。函数内部的代码越来越大。等等
在最极端的情况下,基于 co_yield
的生成器可以向外界隐藏 所有 其实现细节,只需将其定义放在 .cpp 中文件。有状态仿函数不能隐藏其内部状态,因为它的状态是外部世界必须看到的类型的成员。避免这种情况的唯一方法是通过类型擦除,例如 std::function
。在这一点上,你基本上没有比使用 co_yield
.
此外,co_await
可以与 co_yield
一起使用。 Cppcoro 的 generator
类型显式管理它,但 cppcoro 不是 C++20。你可以写任何你想要的生成器,那个生成器可以 .
事实上,您可以制作异步生成器,有时您可以立即产生一个值,有时您可以通过一些异步进程安排值的可用性。调用异步生成器的代码可以 co_await
从中提取值,而不是将其视为仿函数或迭代器对。
来自著名的 C++ 协程库(在源文件 generator.hpp 中搜索“Don't allow any use of co_await
inside the generator coroutine.”),以及我自己的实验,我知道使用 co_yield
的协程不能同时使用 co_await
。
既然使用 co_yield
的生成器必须是同步的,那么使用 co_yield
相对于简单的有状态 lambda 有什么优势?
例如:
#include <iostream>
generator<int> g()
{
for (auto i = 0; i < 9; ++i)
{
co_yield i;
}
}
int main()
{
auto fn_gen = [i = 0] mutable { return i++; };
// Lambda way
for (auto i = 0; i < 9; ++i)
{
std::cout << fn_gen() << std::endl;
}
// co_yield way
for (auto i : g())
{
std::cout << i << std::endl;
}
}
co_yield
与 C++20 中的简单状态 lambda 相比有什么特殊价值?
请查看更新后的 MWE:https://godbolt.org/z/x1Yoen7Ys
在更新的示例中,在同一个协程中使用 co_await
和 co_yield
时,输出完全出乎意料。
对于内部状态和代码最少的普通生成器,小型仿函数或 lambda 就可以了。但是随着您的生成器代码变得越来越复杂并且需要更多的状态,它变得不那么好。您必须在仿函数类型或 lambda 说明符中添加更多成员。函数内部的代码越来越大。等等
在最极端的情况下,基于 co_yield
的生成器可以向外界隐藏 所有 其实现细节,只需将其定义放在 .cpp 中文件。有状态仿函数不能隐藏其内部状态,因为它的状态是外部世界必须看到的类型的成员。避免这种情况的唯一方法是通过类型擦除,例如 std::function
。在这一点上,你基本上没有比使用 co_yield
.
此外,co_await
可以与 co_yield
一起使用。 Cppcoro 的 generator
类型显式管理它,但 cppcoro 不是 C++20。你可以写任何你想要的生成器,那个生成器可以
事实上,您可以制作异步生成器,有时您可以立即产生一个值,有时您可以通过一些异步进程安排值的可用性。调用异步生成器的代码可以 co_await
从中提取值,而不是将其视为仿函数或迭代器对。