在C++里,一个函数若是其函数体实现中包含co_await、co_yield、co_return中任何一个关键字,那么这个函数就是一个coroutine。其中:promise
一个coroutine要能被编译期识别并经过编译,在某些状况下要本身去特化coroutine_traits。下面就一个简单的coroutine来讲一说C++编译器是如何修改这个coroutine的。函数
1 // 咱们假定这个模板函数是一个coroutine 2 template <typename TRet, typename … TArgs> 3 TRet func(TArgs args…) 4 { 5 body; // body里至少包含了co_await、co_yield、co_return三者之一。 6 }
那么这个函数会被编译器改为以下形式:spa
1 // 它会被编译期展开成以下形式 2 template <typename TRet, typename ... TArgs> 3 TRet func(TArgs args...) 4 { 5 using promise_t = typename coroutine_traits<TRet, TArgs...>::promise_type; 6 7 promise_t promise; 8 auto __return__ = promise.get_return_object(); // 这个__return__会被编译器特殊处理 9 10 co_await promise.initial_suspend(); 11 12 try 13 { // co_return expr; => promise.return_value(expr); goto final_suspend; 14 body; // co_return; => promise.return_void(); goto final_suspend; 15 } // co_yield expr; => co_await promise.yield_value(expr); 16 catch (...) 17 { 18 promise.set_exception(std::current_exception()); 19 } 20 21 final_suspend: 22 co_await promise.final_suspend(); 23 }
以上是一个coroutine的基本形式。事实上看完以后会发现,一个coroutine的关键主要仍是和其关联的promise。
和coroutine promise关联的另一个概念,叫awaitable。Awaitable能够称为一个可等待对象。一个awaitable对象须要实现3个相关函数:线程
因此要让一个类型可以awaitable,有三种手段:代理
--完code
N4663对象