template<typename R, typename T> R add(T a, T b) { returnstatic_cast<R>(a + b); } template < > intadd(int a, int b) { return a + b; } intmain() { int c = add<int>(1, 2); //int add(int a, int b) }
template<typename T, typename R = int> R add(T a, T b) { returnstatic_cast<R>(a + b); } template<typename R = float> R add(longlong a, longlong b) { return a + b; } template < > intadd(int a, int b) { return a + b; } intmain() { auto c = add(1ll, 2ll); }
以上,add函数优先和特化的模板函数匹配,而不是和R add(T a, T b)匹配,因为,参数1ll和2ll与特化模板函数中的long long对应上了,即R add(long long a, long long b),所以最后生成的函数是float add(long long a, long long b)。
实际上,template<typename R = float>,这个形式,本质上是一种函数模板的重载。因为,给出了参数在某些特别类型下,函数的重定义,体现了多态。总之:同一个名字,不同的形式,都叫overload。
再举一个例子_1
1 2 3 4 5
template<typename R = float> R add(longlong a, longlong* pb) { return a + *pb; }
1 2 3 4 5
intmain() { auto b = 2ll; auto c = add(1ll, &b); }
走的是R add(long long a, long long* pb)。这也是一个function template overload。
再举一个例子_2
1 2 3 4 5 6 7 8 9 10 11
template<typename R = float> R add(longlong a, longlong b) { return a + b; }
template<typename R = float> R add(longlong a, longlong& b) { return a + b; }
1 2 3 4 5
intmain() { auto b = 2ll; auto c = add(1ll, &b); }
此时,如果没有用到add(long long, long long&),是可以正常编译的。
但是,如果一旦用到了:
1 2 3 4 5
intmain() { auto b = 2ll; auto c = add(1ll, b); }
就会报错:
1 2 3 4 5
'add': ambiguous call to overloaded function
more than one instance of overloaded function "add" matches the argument list: function template "R add(long long a, long long b)" function template "R add(long long a, long long &b)"
类模板
1 2 3 4 5 6 7 8 9
template <typename R, typename T> classAddition { public: R add(T a, T b)constnoexcept { return a + b; } }
1 2 3 4 5
intmain() { Addition<int, int> addition; auto c = addition.add(1, 2); }
template<typename R, typename T = int> class Addition { public: Addition(void) { } Addition(T a, T b) : _a{ a }, _b{ b } { } R add(T a, T b) constnoexcept { return a + b; } R add(void)constnoexcept { return _a + _b; } private: T _a; T _b; };
1 2 3 4 5
intmain() { Addition addition(1, 2); // C++14标准无法编译通过 auto c = addition.add(1, 2); }
类的部分特化(偏特化)
Class Template Partial Specialization
1 2 3 4 5 6 7 8 9
template<typename R, typename T> classAddition { public: R add(T a, T b)constnoexcept { return a + b; } };
类的部分特化,定义时,要在类名后写尖括号,写入模板参数。
1 2 3 4 5 6 7 8 9
template <typename T> classAddition<T, int> { public: intadd(T a, T b)constnoexcept { return a + b; } };
1 2 3 4 5
intmain() { Addition<int, int> addition; auto c = addition.add(1, 2); }
类的实例化走的是class Addition<T, int>。
类的全特化
Class Template Full Specialization
1 2 3 4 5 6 7 8 9
template < > classAddition<int, int> { public: intadd(int a, int b)constnoexcept { return a + b; } };
1 2 3 4 5
intmain() { Addition<int, int> addition; auto c = addition.add(1, 2); }
类的实例化走的是class Addition<int, int>。
再来个例子
1 2 3 4 5 6 7 8 9
template < > classAddition<int, int*> { public: intadd(int a, int* b)constnoexcept { return a + *b; } };
1 2 3 4 5 6
intmain() { auto b = 2; Addition<int, int*> addition; auto c = addition.add(1, &b); }
template <typename T, typename R = AddTraits<T>::R> R add(T a, T b) { returnstatic_cast<R>(a) + static_cast<R>(b); }
测试:
1 2 3 4 5 6 7 8 9 10 11
intmain() { unsignedshort a = 1u; unsignedshort b = 2u; // 调用的是unsigned int add<unsigned short>(unsigned short a, unsigned short b) auto c1 = add(a, b); // 调用的是unsigned long long add<unsigned int>(unsigned int a, unsigned int b) auto c2 = add(1u, 2u); // 调用的是unsigned long long add<unsigned long>(unsigned long a, unsigned long b) auto c3 = add(1ul, 2ul); }
// T是操作数类型,R是返回类型 template <typename T, typename R = AddTraits<T>::R> class AddPolicy { public: static R calculate(T a, T b) { returnstatic_cast<R>(a) + static_cast<R>(b); } };
template <typename T, typename R = AddTraits<T>::R> class MultiplyPolicy { public: static R calculate(T a, T b) { returnstatic_cast<R>(a) * static_cast<R>(b); } };
// T是操作数类型,R是返回类型 template <typename T, typename R = AddTraits<T>::R> class AddPolicy { public: using RTNTYPE = R; static R calculate(T a, T b) { returnstatic_cast<R>(a) + static_cast<R>(b); } };
T为操作数类型;U为Policy;R为返回值类型。
1 2 3 4 5
template <typename T, U = AddPolicy<T> > U::RTNTYPE AddOperate(T a, T b) { return U::calculate(a, b); }
1 2 3 4 5 6 7
intmain() { unsignedshort a = 7u; unsignedshort b = 3u; auto c = AddOperate(a, b); std::cout << c << std::endl; }
封装抽象Operate
抽象的Operate是真正的可以传入任意的Policy参数的。
1 2 3 4 5
template <typename U, typename T> U::RTNTYPE Operate(T a, T b) { return U::calculate(a, b); }
但是,如果这样写的话,得给AddPolicy后面加具体的操作数类型才能编译通过。
1 2 3 4 5 6 7
intmain() { unsignedshort a = 3u; unsignedshort b = 7u; auto c = Operate<AddPolicy<decltype(a)> >(a, b); std::cout << c << std::endl; }
template <typename T, typename R = typename AddTraits<T>::R> class AddPolicy { public: using RTNTYPE = R; static R calculate(T a, T b) { returnstatic_cast<R>(a) + static_cast<R>(b); } };
template <typename T, typename R = typename AddTraits<T>::R> class MultiplyPolicy { public: using RTNTYPE = R; static R calculate(T a, T b) { returnstatic_cast<R>(a) * static_cast<R>(b); } };
template <template<typename, typename> classPolicy, template<typename> classTraits, typename T> typename Traits<T>::R Operate(T a, T b) { return Policy<T, typename Traits<T>::R>::calculate(a, b); }
intmain() { unsignedshort a = 3u; unsignedshort b = 7u; auto c = Operate<AddPolicy, AddTraits>(a, b); std::cout << c << std::endl; c = Operate<MultiplyPolicy, AddTraits>(a, b); std::cout << c << std::endl; }
template < > classOperationTraits<unsignedshort> { public: using R = unsignedint; };
template < > classOperationTraits<unsignedint> { public: using R = unsignedlong; };
template < > classOperationTraits<unsignedlong> { public: using R = unsignedlonglong; };
template <typename T> classAddPolicy { public: using RTNTYPE = typename OperationTraits<T>::R; static RTNTYPE calculate(T a, T b) { returnstatic_cast<RTNTYPE>(a) + static_cast<RTNTYPE>(b); } };
template <typename T> classMultiplyPolicy { public: using RTNTYPE = typename OperationTraits<T>::R; static RTNTYPE calculate(T a, T b) { returnstatic_cast<RTNTYPE>(a) * static_cast<RTNTYPE>(b); } };
template <template<typename> classPolicy, typename T> typename Policy<T>::RTNTYPE Operate(T a, T b) { return Policy<T>::calculate(a, b); }
intmain() { unsignedshort a = 3u; unsignedshort b = 7u; auto c = Operate<AddPolicy>(a, b); std::cout << c << std::endl; c = Operate<MultiplyPolicy>(a, b); std::cout << c << std::endl; }