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

C++20中如何正确接受模板化可调用对象?

解决方案:让可调用参数自动推导类型

核心问题在于你把std::function直接作为函数模板的参数类型,导致编译器无法将lambda等闭包类型隐式转换后参与模板推导。C++20下可以通过以下方式彻底解决,无需手动指定任何模板参数:

1. 重构run函数:接受任意可调用类型

放弃将std::function作为参数的强制要求,改用通用模板参数接收任意可调用对象,内部按需转换为std::function(如果需要类型擦除或存储)。利用C++20的std::invocable概念约束和std::invoke_result_t推导返回类型。

示例代码

首先假设你的Result类型定义如下(适配错误处理逻辑):

template <typename T>
struct Result {
    bool is_ok;
    T value;
    static Result<T> ok(T val) { return {true, std::move(val)}; }
    static Result<T> error() { return {false, {}}; }
};

重构后的通用run函数:

#include <functional>
#include <concepts>
#include <utility>

// 适配任意可调用对象和参数列表的通用版本
template <typename F, typename... Args>
    requires std::invocable<F, Args...>
auto run(F f, Args&&... args) -> Result<std::invoke_result_t<F, Args...>> {
    // 仅当内部需要类型擦除时,才转换为std::function
    using ReturnType = std::invoke_result_t<F, Args...>;
    using FuncType = std::function<ReturnType(Args...)>;
    FuncType func = std::move(f);

    // 示例重试逻辑:尝试3次调用
    for (int retry = 0; retry < 3; ++retry) {
        auto result = func(std::forward<Args>(args)...);
        // 这里替换为你的成功判断逻辑
        if (true) {
            return Result<ReturnType>::ok(std::move(result));
        }
    }

    return Result<ReturnType>::error();
}

2. 调整runWithRetry包装函数

直接转发参数给run即可,编译器会自动推导所有模板参数:

template <typename F, typename... Args>
auto runWithRetry(F f, Args&&... args) {
    // 可在此添加额外逻辑(如日志、前置检查),再调用run
    return run(std::forward<F>(f), std::forward<Args>(args)...);
}

3. 调用示例(无需手动指定模板参数)

int main() {
    // 无参lambda调用
    auto res1 = run([]{ return 42; });
    auto res2 = runWithRetry([]{ return std::string("操作成功"); });

    // 带参lambda调用,自动推导参数类型
    auto res3 = run([](int x) { return x * 2; }, 10);
    auto res4 = runWithRetry([](double d) { return d + 3.14; }, 2.71);
}

原理说明

  • 原来的写法中,std::function<T()>作为模板参数时,编译器无法将lambda的闭包类型隐式转换为std::function来完成推导(隐式转换发生在模板推导之后),导致必须手动指定T。
  • 重构后,模板参数F直接推导为lambda的闭包类型,std::invoke_result_t<F, Args...>自动推导返回值类型,彻底避免手动指定模板参数的需求。
  • 若内部逻辑需要std::function的类型擦除能力,仅在函数内部完成转换即可,不影响外部调用的简洁性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 19:23:21