C++协程guard_if模板编译错误:promise_type非std::coroutine_traits成员
问题分析:C++协程guard_if类模板编译失败
问题背景
实现了名为guard_if的C++类模板,用于在特定条件不满足时阻止目标函数执行。模板接受返回类型为T的std::function、参数类型为U的lambda检查包,核心逻辑通过协程实现:遍历检查lambda,若任一失败则yield无操作标记,否则调用目标函数后返回。但代码编译失败,错误提示:
'promise_type': is not a member of 'std::coroutine_traits<std::coroutine_handle<experimental::guard::guard_if<void,int>::promise_type>,experimental::guard::guard_if<void,int> &,U>'
原实现代码:
#include <functional> #include <vector> #include <coroutine> #include <iostream> namespace experimental { namespace guard { template<typename T, typename U> class guard_if { public: struct promise_type; using handle_type = std::coroutine_handle<promise_type>; guard_if(handle_type handle) : coro(handle) {} ~guard_if() { if (coro) coro.destroy(); } handle_type coro; struct promise_type { guard_if get_return_object() const noexcept{ return guard_if{ handle_type::from_promise(*this) }; } std::suspend_always initial_suspend() const noexcept { return {}; } std::suspend_always final_suspend() const noexcept { return {}; } void return_void() noexcept {} void unhandled_exception() { std::terminate(); } }; // Check if conditions pass; if not, set triggered and yield out handle_type attempt_execute(U arg) { for (const auto& check : _GuardChecks) { if (check(arg)) continue; else { _GuardTriggered = true; co_yield std::noop_coroutine(); } } // Check if still false; if so, call the executing function if (!_GuardTriggered) _ExecuteableFunction(); co_return; } private: std::function<T()> _ExecuteableFunction; std::vector<std::function<bool(U)>> _GuardChecks; bool _GuardTriggered; public: // Constructor accepting a function and a pack of guard check functions template<typename... Args> guard_if(std::function<T()> function, Args&&... checks) : _ExecuteableFunction(function), _GuardTriggered(false) { (_GuardChecks.emplace_back(std::forward<Args>(checks)), ...); } }; } } // Specialize std::coroutine_traits for guard_if namespace std { template<typename T, typename U> struct coroutine_traits<experimental::guard::guard_if<T, U>, U> { using promise_type = typename experimental::guard::guard_if<T, U>::promise_type; }; } #pragma once
使用示例:
#include <iostream> #include <functional> #include "guard.h" using namespace experimental; void print_success(void) { std::cout << "Test Passes Sucessfully\n"; } int Main(int* argc, wchar_t** argv) { auto func = []() { print_success(); }; guard::guard_if<void, int> test_guard(func, [](int x) {return x > 999; }); test_guard.attempt_execute(10); return 0; }
错误原因
- 协程成员函数的traits匹配错误:
attempt_execute是类的非静态成员函数,作为协程时,编译器会把this指针(guard_if<T,U>&)作为第一个隐式参数传递给std::coroutine_traits。但原特化的coroutine_traits只处理了返回类型和U参数,没考虑this指针,导致编译器找不到对应的promise_type。 - 协程返回类型错误:
attempt_execute声明返回handle_type(即std::coroutine_handle<promise_type>),但C++协程的返回类型应该是自定义的guard_if<T,U>,而非底层的coroutine_handle,这里混淆了协程返回对象和handle的关系。 - co_yield用法错误:
co_yield std::noop_coroutine()是错误的,co_yield需要值类型,而std::noop_coroutine()返回的是coroutine_handle,应定义专门的“无操作”标记类型。 - 构造函数冲突:类中有两个构造函数,一个接受
handle_type,一个接受目标函数和检查包,外部创建对象时存在潜在的推导歧义。
修复方案
- 修正协程返回类型:将
attempt_execute的返回类型改为guard_if<T,U>。 - 修正coroutine_traits特化:添加
this指针作为第一个参数,匹配成员函数的协程参数列表。 - 调整co_yield逻辑:定义空结构体
NO_OP作为yield标记,在promise_type中添加yield_value函数处理该标记。 - 区分构造函数:将接受
handle_type的构造函数设为私有,仅允许promise_type内部调用。 - 完善协程启动逻辑:通过返回的
guard_if对象获取协程handle,手动调用resume()启动协程。
修复后的完整代码
#include <functional> #include <vector> #include <coroutine> #include <iostream> namespace experimental { namespace guard { // 定义无操作标记 struct NO_OP {}; template<typename T, typename U> class guard_if { public: struct promise_type; using handle_type = std::coroutine_handle<promise_type>; // 仅允许promise_type用handle构造 private: guard_if(handle_type handle) : coro(handle) {} public: ~guard_if() { if (coro) coro.destroy(); } // 获取协程handle用于启动 handle_type get_coroutine() { return coro; } struct promise_type { guard_if get_return_object() noexcept { return guard_if{ handle_type::from_promise(*this) }; } std::suspend_always initial_suspend() const noexcept { return {}; } std::suspend_always final_suspend() const noexcept { return {}; } // 处理void返回值的co_return void return_void() noexcept {} // 若T非void,需添加return_value(const T&)函数 void unhandled_exception() { std::terminate(); } // 处理co_yield NO_OP std::suspend_always yield_value(NO_OP) noexcept { return {}; } }; // 协程函数:返回类型为guard_if<T,U> guard_if<T, U> attempt_execute(U arg) { for (const auto& check : _GuardChecks) { if (!check(arg)) { _GuardTriggered = true; co_yield NO_OP{}; co_return; // 检查失败后直接退出协程 } } if (!_GuardTriggered) { _ExecuteableFunction(); } co_return; } private: std::function<T()> _ExecuteableFunction; std::vector<std::function<bool(U)>> _GuardChecks; bool _GuardTriggered = false; handle_type coro; public: // 公共构造函数:接受目标函数和检查包 template<typename... Args> guard_if(std::function<T()> function, Args&&... checks) : _ExecuteableFunction(std::move(function)) { (_GuardChecks.emplace_back(std::forward<Args>(checks)), ...); } }; } } // 特化coroutine_traits:匹配成员函数的this指针+U参数 namespace std { template<typename T, typename U> struct coroutine_traits<experimental::guard::guard_if<T, U>, experimental::guard::guard_if<T, U>&, U> { using promise_type = typename experimental::guard::guard_if<T, U>::promise_type; }; } #pragma once
修正后的使用示例
#include <iostream> #include <functional> #include "guard.h" using namespace experimental; void print_success(void) { std::cout << "Test Passes Successfully\n"; } int main(int argc, char** argv) { auto func = []() { print_success(); }; guard::guard_if<void, int> test_guard(func, [](int x) {return x > 999; }); // 获取协程handle并启动执行 auto coro = test_guard.attempt_execute(10).get_coroutine(); coro.resume(); return 0; }
额外说明
C协程和C#的yield return逻辑类似,但底层实现不同:C协程基于栈帧暂停/恢复机制,需手动管理生命周期(或通过返回对象的析构函数自动处理)。修复后的代码中,当任一检查失败时,协程会yieldNO_OP并直接退出;所有条件通过时才会执行目标函数。
内容的提问来源于stack exchange,提问作者Alex Frankland
相关产品推荐
相关产品推荐

