C++17中嵌套函数模板与类型模板的实现疑问
解决C++17中嵌套模板函数的适配问题
当你把add和diff改成模板函数后,原来的combine模板写法失效的核心原因是:模板函数本身不是可直接传递的编译期实体,只有它的具体实例(比如add<double>)才是真正的函数对象。原来的combine试图将模板函数作为非类型模板参数,这不符合C++的规则。
以下是几种可行的修改方案:
方案一:使用C++17的auto非类型模板参数(推荐)
利用C++17引入的auto非类型模板参数,可以自动推导传入的函数实例类型,写法最简洁:
template <typename T> T add(T x, T y) { return x + y; } template <typename T> T diff(T x, T y) { return x - y; } // 用auto接收具体的函数实例,参数用auto推导类型 template <auto fn1, auto fn2> auto combine(auto x, auto y) { return fn1(x, y) + fn2(x, y); } // 调用示例 int main() { double x = 3.5, y = 1.2; auto z_double = combine<add<double>, diff<double>>(x, y); float a = 2.3f, b = 1.1f; auto z_float = combine<add<float>, diff<float>>(a, b); int c = 5, d = 2; auto z_int = combine<add<int>, diff<int>>(c, d); return 0; }
如果希望combine的两个参数类型必须一致,可以调整为:
template <auto fn1, auto fn2, typename T> T combine(T x, T y) { return fn1(x, y) + fn2(x, y); } // 调用时可省略T,编译器会自动推导 auto z = combine<add<double>, diff<double>>(x, y);
方案二:显式指定函数指针类型作为模板参数
这种方式更贴近你最初的写法,需要明确指定函数指针的类型:
template <typename T> T add(T x, T y) { return x + y; } template <typename T> T diff(T x, T y) { return x - y; } // 模板参数依次为类型T,以及两个T类型的函数指针 template <typename T, T(*fn1)(T, T), T(*fn2)(T, T)> T combine(T x, T y) { return fn1(x, y) + fn2(x, y); } // 调用时需指定T和具体的函数实例 int main() { double x = 3.5, y = 1.2; auto z = combine<double, add<double>, diff<double>>(x, y); return 0; }
方案三:改用仿函数与模板模板参数
如果愿意调整add和diff的实现方式,改为仿函数(函数对象),可以用模板模板参数来实现更灵活的适配:
// 把add和diff改为模板仿函数 template <typename T> struct add { T operator()(T x, T y) const { return x + y; } }; template <typename T> struct diff { T operator()(T x, T y) const { return x - y; } }; // 模板模板参数接收add/diff这类模板,再指定T类型 template <template <typename> typename Fn1, template <typename> typename Fn2, typename T> T combine(T x, T y) { return Fn1<T>{}(x, y) + Fn2<T>{}(x, y); } // 调用时无需显式指定T,编译器会自动推导 int main() { double x = 3.5, y = 1.2; auto z = combine<add, diff>(x, y); return 0; }
内容的提问来源于stack exchange,提问作者stefanJonB
相关产品推荐
相关产品推荐

