如何让std::function支持带默认参数的函数调用?能否用函数指针实现?
问题背景
以下代码中,std::function无法支持原函数的默认参数调用:
#include <iostream> #include <functional> using MyFunctionAlias = std::function<void(int, double)>; void exampleFunction(int value, double value2 = 3.14) {} void exampleFunction2(int value, double value2) {} int main() { MyFunctionAlias func = exampleFunction; // 正常调用 func(10, 2); // 编译错误:std::function声明不支持默认参数,必须传入所有参数 func(10); return 0; }
我的场景是把MyFunctionAlias作为不同类的成员变量,实现通用类型适配多种场景。部分绑定的函数带有可选参数,目前只能传入占位值调用,但希望能直接省略默认参数调用。请问能否通过函数指针实现这个需求?
注:此前有类似方案,但仅适用于绑定固定函数的场景——我需要根据运行时输入切换func指向的函数(比如func = exampleFunction2、func = exampleFunction3等)。
解决方案
关键结论:函数指针无法解决该问题
函数指针的签名是固定的(比如void(*)(int, double)),调用时必须传足参数。默认参数是编译期针对函数名的特性,通过指针或std::function调用时,编译器不会自动填充默认值,因此函数指针和std::function一样无法支持省略参数的调用。
可行方案1:自定义包装器类
创建一个包装类,内部封装std::function<void(int, double),同时提供两个重载的调用运算符:一个接受单个int参数(使用预设默认值),另一个接受完整参数列表直接转发。支持运行时切换绑定的函数,且调用方式符合预期。
示例代码:
#include <iostream> #include <functional> class MyFunctionWrapper { private: std::function<void(int, double)> m_func; double m_default_val; public: template<typename Callable> MyFunctionWrapper(Callable&& func, double default_val = 3.14) : m_func(std::forward<Callable>(func)), m_default_val(default_val) {} // 单参数调用:使用默认值 void operator()(int value) { m_func(value, m_default_val); } // 双参数调用:直接转发 void operator()(int value, double value2) { m_func(value, value2); } }; void exampleFunction(int value, double value2 = 3.14) { std::cout << "exampleFunction: " << value << ", " << value2 << "\n"; } void exampleFunction2(int value, double value2) { std::cout << "exampleFunction2: " << value << ", " << value2 << "\n"; } int main() { MyFunctionWrapper func1(exampleFunction); func1(10); // 输出: exampleFunction: 10, 3.14 func1(10, 2.0); // 输出: exampleFunction: 10, 2.0 MyFunctionWrapper func2(exampleFunction2); func2(20, 5.0); // 输出: exampleFunction2: 20, 5.0 func2(20); // 输出: exampleFunction2: 20, 3.14(使用预设默认值) // 运行时切换函数 MyFunctionWrapper func = func1; func(15); // 输出: exampleFunction: 15, 3.14 func = func2; func(15, 7.0); // 输出: exampleFunction2: 15, 7.0 return 0; }
可行方案2:用std::variant存储多签名可调用对象
如果需要严格区分“支持单参数调用”和“必须双参数调用”的函数,可以用std::variant存储不同签名的std::function,通过辅助函数处理不同调用场景,避免非法调用。
示例代码:
#include <iostream> #include <functional> #include <variant> using FuncWithDefault = std::function<void(int)>; using FuncWithoutDefault = std::function<void(int, double)>; using MyFunctionVariant = std::variant<FuncWithDefault, FuncWithoutDefault>; // 单参数调用逻辑 void call(MyFunctionVariant& var, int value) { if (std::holds_alternative<FuncWithDefault>(var)) { std::get<FuncWithDefault>(var)(value); } else { std::cerr << "错误:该函数需要传入double类型参数\n"; // 若允许默认值,可替换为:std::get<FuncWithoutDefault>(var)(value, 3.14); } } // 双参数调用逻辑 void call(MyFunctionVariant& var, int value, double value2) { if (std::holds_alternative<FuncWithoutDefault>(var)) { std::get<FuncWithoutDefault>(var)(value, value2); } else { std::get<FuncWithDefault>(var)(value); // 忽略多余参数 } } void exampleFunction(int value, double value2 = 3.14) { std::cout << "exampleFunction: " << value << ", " << value2 << "\n"; } void exampleFunction2(int value, double value2) { std::cout << "exampleFunction2: " << value << ", " << value2 << "\n"; } int main() { MyFunctionVariant func; // 绑定带默认参数的函数 func = FuncWithDefault([](int val) { exampleFunction(val); }); call(func, 10); // 输出: exampleFunction: 10, 3.14 call(func, 10, 2.0); // 输出: exampleFunction: 10, 3.14 // 运行时切换到无默认参数的函数 func = FuncWithoutDefault(exampleFunction2); call(func, 20, 5.0); // 输出: exampleFunction2: 20, 5.0 call(func, 20); // 输出错误提示 return 0; }
内容的提问来源于stack exchange,提问作者Mathieu
相关产品推荐
相关产品推荐

