如何将带不同参数的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; }
方案优势
- 消除重复代码:异常处理逻辑只写一次,后续修改只需要维护这一个函数。
- 灵活性高:不仅支持
std::function,还直接兼容lambda、普通函数、成员函数等所有可调用类型。 - 高效传递参数:用
std::forward实现完美转发,避免不必要的参数拷贝,保证性能。
内容的提问来源于stack exchange,提问作者Griffort
相关产品推荐
相关产品推荐

