You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

错误原因

  1. 协程成员函数的traits匹配错误:attempt_execute是类的非静态成员函数,作为协程时,编译器会把this指针(guard_if<T,U>&)作为第一个隐式参数传递给std::coroutine_traits。但原特化的coroutine_traits只处理了返回类型和U参数,没考虑this指针,导致编译器找不到对应的promise_type。
  2. 协程返回类型错误:attempt_execute声明返回handle_type(即std::coroutine_handle<promise_type>),但C++协程的返回类型应该是自定义的guard_if<T,U>,而非底层的coroutine_handle,这里混淆了协程返回对象和handle的关系。
  3. co_yield用法错误:co_yield std::noop_coroutine()是错误的,co_yield需要值类型,而std::noop_coroutine()返回的是coroutine_handle,应定义专门的“无操作”标记类型。
  4. 构造函数冲突:类中有两个构造函数,一个接受handle_type,一个接受目标函数和检查包,外部创建对象时存在潜在的推导歧义。

修复方案

  1. 修正协程返回类型:将attempt_execute的返回类型改为guard_if<T,U>。
  2. 修正coroutine_traits特化:添加this指针作为第一个参数,匹配成员函数的协程参数列表。
  3. 调整co_yield逻辑:定义空结构体NO_OP作为yield标记,在promise_type中添加yield_value函数处理该标记。
  4. 区分构造函数:将接受handle_type的构造函数设为私有,仅允许promise_type内部调用。
  5. 完善协程启动逻辑:通过返回的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 05:37:31