与 C++20 中的简单有状态 lambda 相比,“co_yield”有什么特殊值?

xml*_*lmx 6 c++ language-design coroutine c++20 c++-coroutine

从著名的C++协程库(在源文件generator.hpp中搜索“Don'tallowanyuseof insidethegeneratorcoroutine co_await.” ),以及我自己的实验,我知道一个协程使用不能同时使用。co_yieldco_await

既然使用的生成器必须是同步的,那么与简单的有状态 lambda 相比co_yield,使用有什么优势呢?co_yield

例如:

#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;
    }
}
Run Code Online (Sandbox Code Playgroud)

与 C++20 中的简单有状态 lambda 相比,的特殊价值是什么?co_yield

请参阅更新的 MWEhttps ://godbolt.org/z/x1Yoen7Ys

在更新的示例中,在同一协程中使用co_await和时,输出完全出乎意料。co_yield

Nic*_*las 7

对于具有最少内部状态和代码的简单生成器,一个小的函子或 lambda 就可以了。但是,随着生成器代码变得更加复杂并且需要更多状态,它就会变得不那么精细。您必须在函子类型或 lambda 说明符中添加更多成员。函数内部的代码越来越大。ETC。

在最极端的情况下,co_yield基于 - 的生成器可以向外界隐藏其所有实现细节,只需将其定义放在 .cpp 文件中即可有状态函子无法隐藏其内部状态,因为其状态是外部世界必须看到的类型的成员。避免这种情况的唯一方法是通过类型擦除,例如使用std::function. 到那时,你基本上不会比仅仅使用co_yield.

另外,co_await可以与 一起使用co_yield。Cppcoro 的generator类型明确地管理它,但 cppcoro 不是 C++20。您可以编写任何您想要的生成器,并且该生成器可以支持特定用途的使用co_await

事实上,您可以制作异步生成器,有时您可以立即生成一个值,有时您可以通过某些异步过程安排值的可用性。调用异步生成器的代码可以co_await从中提取值,而不是将其视为函子或迭代器对。