如何调用这些回调函数的可变参数模板版本?
解决可变参数模板替代std::function重载函数的问题
你遇到的核心问题是模板参数推导阶段不会自动将lambda/函数指针隐式转换为std::function,所以原本的可变参数模板无法匹配调用,只能走重载的非模板函数。
方案一:直接接受任意可调用对象(推荐)
不需要把第一个参数限定为std::function,直接接受任意可调用类型,通过完美转发调用即可。这种方式更简洁高效,还能支持所有可调用类型(lambda、函数指针、仿函数等):
#include <iostream> #include <functional> using namespace std; template <typename Func, typename... Args> void run_callback(Func&& func, Args&&... args) { // 完美转发可调用对象和参数,避免不必要的拷贝 std::forward<Func>(func)(std::forward<Args>(args)...); } void sum(int a, int b) { std::cout << "sum: " << a + b << '\n'; } int main() { run_callback([](){std::cout << "none" << '\n';}); run_callback([](int j){std::cout << "none1: " << j << '\n';}, 12); run_callback([](int j, int i){std::cout << "none2: " << j << ',' << i << '\n';}, 12, 17); run_callback(sum, 5, 4); }
方案二:必须使用std::function时的适配
如果业务场景要求必须用std::function(比如需要存储回调、类型擦除等),可以通过类型萃取推断可调用对象的参数类型,再构造std::function:
#include <iostream> #include <functional> #include <type_traits> #include <tuple> using namespace std; // 类型萃取工具,用于获取可调用对象的参数类型 template<typename Func> struct function_traits; // 处理std::function template<typename R, typename... Args> struct function_traits<std::function<R(Args...)>> { using return_type = R; using args_tuple = std::tuple<Args...>; }; // 处理函数指针 template<typename R, typename... Args> struct function_traits<R(*)(Args...)> { using return_type = R; using args_tuple = std::tuple<Args...>; }; // 处理lambda等仿函数 template<typename Func> struct function_traits : public function_traits<decltype(&Func::operator())> {}; // 处理const成员函数(lambda默认是const) template<typename R, typename C, typename... Args> struct function_traits<R(C::*)(Args...) const> { using return_type = R; using args_tuple = std::tuple<Args...>; }; // 可变参数模板,自动适配并构造std::function template<typename Func, typename... Args, typename = std::enable_if_t<std::is_invocable_v<Func, Args...>>> void run_callback(Func&& func, Args&&... args) { using traits = function_traits<std::decay_t<Func>>; // 构造对应的std::function std::function<void(typename std::tuple_element_t<0, typename traits::args_tuple>...)> wrapped_func(std::forward<Func>(func)); wrapped_func(std::forward<Args>(args)...); std::cout << "variadic called\n"; } void sum(int a, int b) { std::cout << "sum: " << a + b << '\n'; } int main() { run_callback([](){std::cout << "none" << '\n';}); run_callback([](int j){std::cout << "none1: " << j << '\n';}, 12); run_callback([](int j, int i){std::cout << "none2: " << j << ',' << i << '\n';}, 12, 17); run_callback(sum, 5, 4); // 直接传入std::function也支持 std::function<void(int)> f = [](int x){std::cout << "std::function: " << x << '\n';}; run_callback(std::move(f), 100); }
问题根源解释
原来的模板函数run_callback(std::function<void(FArgs...)> && func, Args && ... as)无法被匹配的原因是:
模板参数推导过程中,编译器不会自动将传入的lambda、函数指针等隐式转换为std::function类型,因此无法推导出FArgs...,只能匹配那些显式重载的非模板函数。
内容的提问来源于stack exchange,提问作者Libra
相关产品推荐
相关产品推荐

