如何在可变参数模板中使用同名重载函数作为参数?
解决重载函数作为可变参数模板参数的问题
直接传递重载函数名会因为二义性被编译器拒绝,不过不用递归也有优雅的解决办法——核心是用单一的可调用实体包裹重载函数,让它能根据参数类型自动匹配对应的重载版本,下面是两种常用方案:
方案一:泛型lambda包裹
泛型lambda的operator()会自动推导参数类型,完美适配需求,调用时直接用lambda包裹原重载函数即可:
double f(double x){ return x*x; } int f(int x){ return x*x; } template<typename F, typename ... T> auto fnc(F foo, T...args){ return (foo(args) + ...); // 折叠表达式实现求和 } int main() { // 泛型lambda自动匹配每个参数对应的f重载版本 auto result = fnc([](auto x){ return f(x); }, 1, 2, 3.5); // 计算结果:1*1 + 2*2 + 3.5*3.5 = 17.25 return 0; }
方案二:重载的函数对象
如果需要多次复用这个逻辑,可以定义一个重载了operator()的结构体,把原函数的重载调用逻辑封装进去:
double f(double x){ return x*x; } int f(int x){ return x*x; } // 封装原函数重载的函数对象 struct FWrapper { int operator()(int x) const { return f(x); } double operator()(double x) const { return f(x); } }; template<typename F, typename ... T> auto fnc(F foo, T...args){ return (foo(args) + ...); } int main() { auto result = fnc(FWrapper{}, 1, 2, 3.5); // 同样得到17.25 return 0; }
原理说明
编译器无法直接解析重载函数名(因为无法确定要选哪个版本),但lambda或函数对象是单一的类型实体,不存在歧义。当模板展开折叠表达式时,每个args的类型会触发lambda/函数对象对应的operator()重载,进而调用原函数的正确版本。
另外修正了原代码的小问题:fnc的返回值用auto自动推导更合理,因为混合int和double参数时,求和结果会是double类型,自动推导能适配不同场景。
内容的提问来源于stack exchange,提问作者MarkKwain
相关产品推荐
相关产品推荐

