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

能否通过协程实现函数柯里化?C++20协程可行性探究

用C++20协程实现函数柯里化:可行方案与实操

可以用C++20协程实现函数柯里化,核心思路是利用协程的暂停/恢复机制逐步接收参数,待所有参数收集完成后再执行原函数。下面结合示例具体说明:

基础示例:二元函数的柯里化

以加法函数为例,先实现一个支持分步传参的协程版柯里化:

#include <coroutine>
#include <iostream>
#include <utility>

// 协程返回类型,用于柯里化二元函数
template<typename T>
struct CurryAdd {
    struct promise_type {
        T first;  // 存储第一个参数
        T second; // 存储第二个参数

        auto get_return_object() { return CurryAdd{*this}; }
        auto initial_suspend() { return std::suspend_always{}; }
        auto final_suspend() noexcept { return std::suspend_always{}; }
        void return_void() {}
        void unhandled_exception() { std::terminate(); }
    };

    std::coroutine_handle<promise_type> handle;

    // 接收第一个参数,恢复协程后再次暂停
    CurryAdd& operator()(T val) {
        if (!handle.done()) {
            handle.promise().first = val;
            handle.resume();
        }
        return *this;
    }

    // 接收第二个参数,执行计算并清理协程
    T operator()(T val) {
        handle.promise().second = val;
        auto result = handle.promise().first + handle.promise().second;
        handle.destroy();
        return result;
    }
};

// 生成柯里化加法器的协程函数
template<typename T>
CurryAdd<T> curried_add() {
    co_await std::suspend_always{}; // 暂停等待第一个参数
    co_await std::suspend_always{}; // 暂停等待第二个参数
}

int main() {
    auto add = curried_add<int>();
    auto add5 = add(5);
    std::cout << add5(3) << std::endl; // 输出8
    return 0;
}

代码逻辑说明

  1. curried_add是协程函数,启动后立即暂停,等待第一个参数传入;
  2. 第一次调用add(5)时,协程恢复但随即再次暂停,把参数存入promise对象;
  3. 第二次调用add5(3)时,传入第二个参数,执行加法计算,最后销毁协程句柄释放资源。

扩展到任意参数的柯里化

如果要支持任意参数个数的函数,需要结合可变参数模板和std::tuple存储已接收的参数,核心是每次接收一个参数后暂停,直到参数全部收集完成:

#include <coroutine>
#include <functional>
#include <tuple>
#include <utility>

template<typename Ret, typename... Args>
struct CurryPromise {
    std::tuple<std::decay_t<Args>...> args;
    std::function<Ret(Args...)> target_func;

    struct promise_type {
        CurryPromise* self = nullptr;

        auto get_return_object() {
            self = new CurryPromise();
            return self;
        }

        auto initial_suspend() { return std::suspend_always{}; }
        auto final_suspend() noexcept { return std::suspend_always{}; }
        void return_void() {}
        void unhandled_exception() { std::terminate(); }
    };

    // 接收单个参数,继续暂停等待剩余参数
    template<typename Arg>
    auto operator()(Arg&& arg) {
        std::get<sizeof...(Args)>(args) = std::forward<Arg>(arg);
        return *this;
    }

    // 无参调用时,执行目标函数并返回结果
    Ret operator()() {
        auto result = std::apply(target_func, args);
        delete this;
        return result;
    }
};

// 柯里化包装函数,适配任意函数
template<typename Func>
auto curry(Func&& func) {
    using FuncType = std::decay_t<Func>;
    // 注:std::function_traits需自行实现,用于提取函数的返回值和参数类型
    using Ret = decltype(std::declval<FuncType>()(std::declval<typename std::function_traits<FuncType>::args>()...));
    using Args = typename std::function_traits<FuncType>::args;

    auto coro = []() -> CurryPromise<Ret, Args...> {
        co_return;
    };

    auto promise = coro();
    promise->target_func = std::forward<Func>(func);
    return promise;
}

注意事项

  • 上述代码中的std::function_traits不是标准库组件,需要自行实现(或使用第三方库)来提取函数的返回值和参数类型;
  • 协程版柯里化会有运行时开销(协程句柄管理、内存分配),而boost::hana::curry是编译期模板元编程实现,无额外运行时成本。

与boost::hana::curry的对比

  • 通用性:boost的curry能自动适配任意参数个数的函数,无需手动编写特定的协程返回类型;
  • 性能:boost实现完全在编译期完成,无运行时开销;协程版因暂停/恢复机制和内存操作,存在一定性能损耗;
  • 适用场景:协程版适合需要结合异步流程的柯里化需求(比如参数异步传入),而boost版更适合纯同步、追求性能的场景。

内容的提问来源于stack exchange,提问作者Enlico

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 22:02:54