首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++20协程:需要一个使用co_yield的函数

C++20协程:需要一个使用co_yield的函数
EN

Stack Overflow用户
提问于 2020-06-25 05:07:10
回答 2查看 2.7K关注 0票数 1

此MCVE不能在g++10 (带有-std=c++21 -fcoroutines选项)中编译。

代码语言:javascript
复制
#include <iostream>

int f() { for (int i = 0; i < 10; ++i) co_yield i; }

int main ()
{
    for (int i : f())
        std::cout << i << ' ';

    return 0;
}

f的第一行应该是什么样子,这样我才能得到一个可工作的协程?或者需要做一些其他的事情来创建一个工作的协程?它需要是C++20 ( g++10supposed to fully support)的一部分,而不是一个附加库。

EN

回答 2

Stack Overflow用户

发布于 2020-06-26 06:02:54

这是一个使用gcc 10.1的最小工作示例,它是一个只使用co_yield而没有co_return的协程myCoroutineFunction

它使用了counted for循环。range for循环需要更多的工作来编写迭代器。

协程的返回类型是一个生成器对象,它需要一个promise对象来跟踪协程的当前值。

因为生成器和promise相互依赖,所以可以方便地使promise成为生成器的嵌套类。

每次协程产生一个值时,该值由promise维护,而协程被挂起

客户端代码与生成器交互,生成器提供访问当前协程程序值和在挂起后推进协程程序的方法

代码语言:javascript
复制
// coroutine.cpp

// g++ -ocoroutine -g -O0 -Wall -Werror -Wextra
// -std=c++20 -fcoroutines -fno-exceptions coroutine.cpp

#include <stdio.h>
#include <coroutine>

using namespace std;

struct Generator {
  struct Promise;

// compiler looks for promise_type
  using promise_type=Promise;
  coroutine_handle<Promise> coro;

  Generator(coroutine_handle<Promise> h): coro(h) {}

  ~Generator() {
    if(coro)
      coro.destroy();
  }

// get current value of coroutine
  int value() {
    return coro.promise().val;
  }

// advance coroutine past suspension
  bool next() {
    coro.resume();
    return !coro.done();
  }

  struct Promise {
// current value of suspended coroutine
    int val;

// called by compiler first thing to get coroutine result
    Generator get_return_object() {
      return Generator{coroutine_handle<Promise>::from_promise(*this)};
    }

// called by compiler first time co_yield occurs
    suspend_always initial_suspend() {
      return {};
    }

// required for co_yield
    suspend_always yield_value(int x) {
      val=x;
      return {};
    }

// called by compiler for coroutine without return
    suspend_never return_void() {
      return {};
    }

// called by compiler last thing to await final result
// coroutine cannot be resumed after this is called
    suspend_always final_suspend() {
      return {};
    }
  };

};

Generator myCoroutineFunction(int n) {

  for(int i = 0; i < n; ++i) {
    co_yield i;
  }

}
代码语言:javascript
复制
int main ()
{
  int n=10;

  Generator myCoroutineResult = myCoroutineFunction(n);

  for(int i=0; i < n; ++i) {
    myCoroutineResult.next();
    printf("%d ", myCoroutineResult.value());
  }

  return 0;
}

编译和运行

代码语言:javascript
复制
$ g++ -ocoroutine -g -O0 -Wall -Werror -Wextra \
-std=c++20 -fcoroutines -fno-exceptions coroutine.cpp
$ ./coroutine
0 1 2 3 4 5 6 7 8 9
票数 4
EN

Stack Overflow用户

发布于 2020-09-06 18:27:37

从你的问题看:

,f的第一行应该是什么样子,这样我才能得到一个工作协程?

我已经修改了你的代码如下。请特别注意f的返回类型。

代码语言:javascript
复制
Couroutine_Example_Generator<int> f() { for (int i = 0; i < 10; ++i) co_yield i; }

int main ()
{
    for (auto i = f(); i.move_next(); )
    {
        std::cout << i.current_value() << ' ';
    }

    return 0;
}

您可以看到我对您的代码所做的更改的完整的Godbolt代码。检查here

,或者是否需要做一些其他的事情才能使协程正常工作?

是。C++20规范要求提供promise_type。因此,我在一个头类中定义了生成器的模板化版本,您可以将其视为here。或者在我的repository中查看稍微不同的代码示例。

如果您感兴趣,请提供更多相关详细信息。下面是C++20规范的相关摘录

协程的promise类型是std::coroutine_traits::promise_type.协程的行为就好像它的函数体被替换为:

代码语言:javascript
复制
{
  promise-type promise promise-constructor-arguments ;
  try {
  co_await promise .initial_suspend() ;
  function-body
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62564094

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档