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

如何将带不同参数的std::function传入同一函数以合并重复逻辑

统一处理不同参数类型std::function的try/catch执行逻辑

你遇到的情况正好是C++模板大展身手的场景——既然三个函数的核心逻辑(try/catch包裹执行)完全一致,只是std::function的参数列表和传入的实参不同,我们可以用可变参数模板把这部分重复逻辑抽成一个通用函数,一次编写处处复用。

原问题场景回顾

假设你原来的三个函数大概长这样:

#include <functional>
#include <iostream>
#include <stdexcept>

// 无参版本
void executeNoArgs(std::function<void()> func) {
    try {
        func();
    } catch (const std::exception& e) {
        std::cerr << "Exception caught: " << e.what() << std::endl;
    } catch (...) {
        std::cerr << "Unknown exception caught" << std::endl;
    }
}

// 单int参数版本
void executeSingleArg(std::function<void(int)> func, int arg) {
    try {
        func(arg);
    } catch (const std::exception& e) {
        std::cerr << "Exception caught: " << e.what() << std::endl;
    } catch (...) {
        std::cerr << "Unknown exception caught" << std::endl;
    }
}

// 双int参数版本
void executeDoubleArgs(std::function<void(int, int)> func, int arg1, int arg2) {
    try {
        func(arg1, arg2);
    } catch (const std::exception& e) {
        std::cerr << "Exception caught: " << e.what() << std::endl;
    } catch (...) {
        std::cerr << "Unknown exception caught" << std::endl;
    }
}

显然,这三个函数除了std::function的类型和传入参数,逻辑完全重复,维护起来很麻烦。

统一解决方案:可变参数模板

我们可以写一个通用的模板函数,它能接受任意类型的可调用对象(包括各种参数的std::function)和对应的参数包,把try/catch逻辑封装进去:

C++17及以上版本(推荐)

用std::invoke可以更优雅地处理各种可调用类型(不仅限于std::function,还支持lambda、普通函数指针等):

#include <functional>
#include <iostream>
#include <stdexcept>
#include <utility> // 用于std::forward
#include <functional> // 用于std::invoke

template<typename Func, typename... Args>
void executeWithTryCatch(Func func, Args&&... args) {
    try {
        // 完美转发参数,高效调用可调用对象
        std::invoke(func, std::forward<Args>(args)...);
    } catch (const std::exception& e) {
        std::cerr << "Exception caught: " << e.what() << std::endl;
    } catch (...) {
        // 捕获所有未预期的异常
        std::cerr << "Unknown exception caught" << std::endl;
    }
}

C11/C14版本

如果你的项目还在用C++17之前的标准,直接调用函数即可(std::function的调用运算符是明确的):

template<typename Func, typename... Args>
void executeWithTryCatch(Func func, Args&&... args) {
    try {
        func(std::forward<Args>(args)...);
    } catch (const std::exception& e) {
        std::cerr << "Exception caught: " << e.what() << std::endl;
    } catch (...) {
        std::cerr << "Unknown exception caught" << std::endl;
    }
}

使用示例

现在不管是无参、单int还是双int的std::function,都可以用同一个函数处理:

int main() {
    // 无参std::function
    std::function<void()> noArgFunc = []() {
        std::cout << "Executing no-argument function\n";
        // throw std::runtime_error("Oops from no-arg function"); // 测试异常
    };
    executeWithTryCatch(noArgFunc);

    // 单int参数std::function
    std::function<void(int)> singleArgFunc = [](int num) {
        std::cout << "Executing single-argument function with value: " << num << "\n";
        // throw std::invalid_argument("Invalid number"); // 测试异常
    };
    executeWithTryCatch(singleArgFunc, 42);

    // 双int参数std::function
    std::function<void(int, int)> doubleArgFunc = [](int a, int b) {
        std::cout << "Executing double-argument function with values: " << a << ", " << b << "\n";
        // throw std::out_of_range("Value out of bounds"); // 测试异常
    };
    executeWithTryCatch(doubleArgFunc, 10, 20);

    return 0;
}

方案优势

  1. 消除重复代码:异常处理逻辑只写一次,后续修改只需要维护这一个函数。
  2. 灵活性高:不仅支持std::function,还直接兼容lambda、普通函数、成员函数等所有可调用类型。
  3. 高效传递参数:用std::forward实现完美转发,避免不必要的参数拷贝,保证性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:39:38