zoukankan      html  css  js  c++  java
  • vs2019 16.8更新之后的 C++20 协程co_yield用法

    由于搜索出来的帖子,都是老版本的实验协程,很多老的代码已经失去参考性,并且很复杂,所以就自己研究了一下。

     1 #include <iostream>
     2 #include <coroutine>
     3 #include <thread>
     4 
     5 template<typename _Ty>
     6 struct cocontext {
     7     struct promise_type;
     8     using _Hty = std::coroutine_handle<promise_type>;
     9     struct promise_type {
    10         // 只要一个函数的返回值是 cocontext<T>,这个函数内存在co_await co_yield co_return这3个语法糖
    11         // 就会第一时间调用 get_return_object
    12         cocontext get_return_object() { 
    13             return { _Hty::from_promise(*this) }; 
    14         }
    15 
    16         // 协程异常时抛出到这里,关于异常,见仁见智,反正我是不用的。
    17         void unhandled_exception() { std::terminate(); }
    18 
    19         // co_await co_yield co_return 之前回调,只回调一次,它在get_return_object之后回调
    20         auto initial_suspend() { return std::suspend_never{}; }
    21 
    22         // 协程函数返回之后,回调这里
    23         auto final_suspend() { return std::suspend_always{}; }
    24 
    25         // 如果函数里没有co_return,必须实现return_void,与之相对的还有一个return_value,类似yield_value
    26         void return_void() {}
    27 
    28         // 如果函数里有co_yield,必须实现yield_value,这其实并不难理解,co_yield把数据传到参数,然后我储存在_Val里而已
    29         auto yield_value(const _Ty &val) {
    30             _Val = val;
    31             return std::suspend_always{};
    32         }
    33         _Ty _Val;
    34     };
    35 
    36     // 如果 await_ready 返回true,它就会继续执行,所以理论上来说,要模拟异步场景,都只会是return false
    37     bool await_ready() const{ return false; }
    38 
    39     // await_suspend是可以有参数的,它还可以是 void await_suspend(std::coroutine_handle<cocontext> handle);
    40     // 在co_await co_yield co_return时,首先会调用这里,也就是可以根据情况直接在这里进行handle.resume();
    41     void await_suspend() {}
    42 
    43     // 下面是我自己的实现
    44     cocontext& resume() { if (!_Handle.done())_Handle.resume(); return *this; }
    45     operator _Ty() const { return _Handle.promise()._Val; }
    46 
    47     _Hty _Handle;
    48 };
    49 
    50 int main()
    51 {
    52     auto test = []()->cocontext<int> { for (int i = 0; i < 10; i++) co_yield i; };
    53     auto c = test();
    54     std::cout << (int)c << std::endl; // 0
    55     std::cout << (int)c.resume() << std::endl; // 1
    56     std::cout << (int)c.resume() << std::endl; // 2
    57     std::cout << (int)c.resume() << std::endl; // 3
    58     std::cout << (int)c.resume() << std::endl; // 4
    59 
    60     std::thread([&]() {
    61         // 协程真正有意思的地方是,它可以由不同的线程去resume,这会很有意义。
    62         std::cout << (int)c.resume() << std::endl; // 5
    63         std::cout << (int)c.resume() << std::endl; // 6
    64         std::cout << (int)c.resume() << std::endl; // 7
    65         std::cout << (int)c.resume() << std::endl; // 8
    66         std::cout << (int)c.resume() << std::endl; // 9
    67 
    68         // 这里依旧输出9,上面一个c.resume()之后,test函数已经跳出循环返回了,已经满足了_Handle.done(),不会再继续真正的_Handle.resume();
    69         std::cout << (int)c.resume() << std::endl;
    70     }).join();
    71 
    72 }
    73 
    74 /*
    75     后话:
    76     C++ 20所谓的协程,实际上在我看来,更像是语法糖内部包含了一堆回调函数
    77     并且这些回调函数得让程序员自己去完全实现,这确实是C++的风格,
    78     但说实在的,我相信搞得清楚这些东西的人,都不会太喜欢这种风格。
    79 
    80     虽然我的例子中 cocontext是基本可重用的类型,但我依旧没感觉这种形式为我的程序带来了多少便利。
    81     情况还是那个情况,这个东西用起来并不方便,程序员从一开始就要考虑到所有细节,
    82     可能最终很多细节考虑之后,用起来还是一大堆代码,到时候可能写着写着把递归逻辑搞成线性逻辑了,然后感叹一句,“我是SB,我TM用个P的协程!”。
    83 */
  • 相关阅读:
    JSON学习笔记-5
    JSON学习笔记-4
    JSON学习笔记-3
    JSON学习笔记-2
    JSON学习笔记-1
    stm32f103各个型号芯片之间程序移植(stm32的兼容问题)
    如何找回微信小程序源码?2020年微信小程序反编译最新教程 小宇子李
    git常用命令
    304 怎么办 怎么解决 缓存解决
    微信小程序 CSS border-radius元素 overflow:hidden失效问题 iPhone ios 苹果兼容问题 伪类元素
  • 原文地址:https://www.cnblogs.com/babypapa/p/14400005.html
Copyright © 2011-2022 走看看