std:: coroutine_traits
From cppreference.net
C++
Utilities library
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Coroutine support
| Coroutine traits | ||||
|
coroutine_traits
(C++20)
|
||||
| Coroutine handle | ||||
|
(C++20)
|
||||
| No-op coroutines | ||||
|
(C++20)
|
||||
|
(C++20)
|
||||
| Trivial awaitables | ||||
|
(C++20)
|
||||
|
(C++20)
|
||||
| Range generators | ||||
|
(C++23)
|
|
定义于头文件
<coroutine>
|
||
|
template
<
class
R,
class
...
Args
>
struct coroutine_traits ; |
(C++20 起) | |
从协程的返回类型和参数类型确定承诺类型。标准库实现提供一个公开可访问的成员类型
promise_type
,当该限定标识符有效且表示类型时,该成员类型与
R::promise_type
相同。否则,不存在此成员类型。
程序定义的特化
必须定义一个可公开访问的嵌套类型
promise_type
,否则程序非良构。
目录 |
模板参数
| R | - | 协程的返回类型 |
| Args | - | 协程的参数类型,包括 隐式对象参数 (当协程为非静态成员函数时) |
嵌套类型
| 名称 | 定义 |
promise_type
|
若有效则为
R::promise_type
,否则由程序定义的特化提供
|
可能的实现
namespace detail { template<class, class...> struct coroutine_traits_base {}; template<class R, class... Args> requires requires { typename R::promise_type; } struct coroutine_traits_base <R, Args...> { using promise_type = R::promise_type; }; } template<class R, class... Args> struct coroutine_traits : detail::coroutine_traits_base<R, Args...> {}; |
注释
如果协程是非静态成员函数,那么
Args...
中的第一个类型是隐式对象参数的类型,其余的是函数的参数类型(如果有的话)。
如果
std::coroutine_traits<R, Args...>::promise_type
不存在或不是类类型,则对应的协程定义是非法的。
用户可依据程序定义类型定义
coroutine_traits
的显式或偏特化,以避免修改返回类型。
示例
运行此代码
#include <chrono> #include <coroutine> #include <exception> #include <future> #include <iostream> #include <thread> #include <type_traits> // 下面特化的 coroutine_traits 所依赖的程序定义类型 struct as_coroutine {}; // 通过使用 std::promise<T> 作为 promise 类型,启用 std::future<T> 作为协程类型 template<typename T, typename... Args> requires(!std::is_void_v<T> && !std::is_reference_v<T>) struct std::coroutine_traits<std::future<T>, as_coroutine, Args...> { struct promise_type : std::promise<T> { std::future<T> get_return_object() noexcept { return this->get_future(); } std::suspend_never initial_suspend() const noexcept { return {}; } std::suspend_never final_suspend() const noexcept { return {}; } void return_value(const T& value) noexcept(std::is_nothrow_copy_constructible_v<T>) { this->set_value(value); } void return_value(T&& value) noexcept(std::is_nothrow_move_constructible_v<T>) { this->set_value(std::move(value)); } void unhandled_exception() noexcept { this->set_exception(std::current_exception()); } }; }; // 对 std::future<void> 同理。 template<typename... Args> struct std::coroutine_traits<std::future<void>, as_coroutine, Args...> { struct promise_type : std::promise<void> { std::future<void> get_return_object() noexcept { return this->get_future(); } std::suspend_never initial_suspend() const noexcept { return {}; } std::suspend_never final_suspend() const noexcept { return {}; } void return_void() noexcept { this->set_value(); } void unhandled_exception() noexcept { this->set_exception(std::current_exception()); } }; }; // 允许通过简单地为每个 co_await 生成新线程来 co_await std::future<T> 和 std::future<void> template<typename T> auto operator co_await(std::future<T> future) noexcept requires(!std::is_reference_v<T>) { struct awaiter : std::future<T> { bool await_ready() const noexcept { using namespace std::chrono_literals; return this->wait_for(0s) != std::future_status::timeout; } void await_suspend(std::coroutine_handle<> cont) const { std::thread([this, cont] { this->wait(); cont(); }).detach(); } T await_resume() { return this->get(); }