如何在编译期校验协程promise_type类型是否合规?
编译期检查合法的C++协程promise_type
当然可以通过自定义concept结合static_assert实现编译期检查,甚至能让未被使用的类型也触发错误。C++标准库确实没有内置的concept来验证promise_type的合法性,所以需要我们自行实现约束逻辑。
第一步:明确promise_type的核心要求
根据C++标准,一个合法的promise_type必须满足以下核心条件:
- 提供
get_return_object()方法,返回对应协程返回类型的实例 - 提供
initial_suspend()方法,返回可等待类型(需包含await_ready()、await_suspend()、await_resume()) - 提供
final_suspend() noexcept方法,返回可等待类型 - 提供
return_void()(无返回值协程)或return_value(T)(带返回值协程)方法 - 提供
unhandled_exception()方法处理未捕获的异常 - (可选)定义
handle_type为std::coroutine_handle<promise_type>(若未定义,编译器会自动推导生成)
第二步:自定义Concept实现约束
先定义一个辅助concept验证可等待类型,再实现检查promise_type的核心concept:
#include <coroutine> #include <concepts> #include <stdexcept> // 验证可等待类型的辅助concept template<typename Awaitable> concept Awaitable = requires(Awaitable a, std::coroutine_handle<> h) { { a.await_ready() } -> std::convertible_to<bool>; a.await_suspend(h); a.await_resume(); }; // 验证promise_type合法性的核心concept template<typename Promise> concept ValidPromiseType = requires(Promise p) { // 检查返回对象生成方法 { p.get_return_object() }; // 检查初始挂起方法 { p.initial_suspend() } -> Awaitable; // 检查最终挂起方法(必须noexcept) { p.final_suspend() noexcept } -> Awaitable; // 检查返回值处理方法(二选一) requires (requires { p.return_void(); } || requires(auto val) { p.return_value(val); }); // 检查异常处理方法 { p.unhandled_exception() }; // 可选:验证handle_type类型 typename Promise::handle_type; requires std::same_as<typename Promise::handle_type, std::coroutine_handle<Promise>>; };
第三步:触发未使用类型的编译错误
如果希望即使协程返回类型未被使用,也能触发promise_type的合法性检查,有两种常用方式:
方式1:在协程返回类型内部添加static_assert
直接在结构体定义中嵌入检查,只要类型被编译就会触发验证:
// 错误示例:空promise_type会触发编译错误 struct BadCoroResult { struct promise_type {}; // 编译时强制检查promise_type合法性 static_assert(ValidPromiseType<promise_type>, "BadCoroResult::promise_type不合法:缺少协程要求的核心方法"); }; // 正确示例:符合要求的promise_type struct GoodCoroResult { struct promise_type { GoodCoroResult get_return_object() { return {}; } std::suspend_never initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void return_void() {} void unhandled_exception() { std::terminate(); } using handle_type = std::coroutine_handle<promise_type>; }; static_assert(ValidPromiseType<promise_type>, "GoodCoroResult::promise_type不合法"); // 不会触发错误 };
方式2:用辅助模板显式实例化检查
如果不想修改原类型定义,可以用一个专门的检查模板,通过显式实例化触发验证:
template<typename CoroReturn> struct ValidateCoroPromise { static_assert(ValidPromiseType<typename CoroReturn::promise_type>, "该协程返回类型的promise_type不合法"); }; // 显式实例化,即使BadCoroResult未被使用也会触发编译错误 template struct ValidateCoroPromise<BadCoroResult>;
注意事项
- 针对带返回值的协程,可以调整concept的
requires条件,强制要求return_value()方法而非return_void() - 可根据自身需求扩展concept的检查项(比如自定义挂起逻辑的额外要求)
- 这种编译期检查能在代码运行前就发现promise_type的合规问题,避免运行时的未定义行为
内容的提问来源于stack exchange,提问作者Zitrax
相关产品推荐
相关产品推荐

