偏特化
前面介绍过,模板的偏特化可以有两种形式
template<typename T, int N> struct Vec{ T v_[N]; }; template<> struct Vec<float, 4> { float v_[4]; }; template<int N> struct Vec<bool, N>{ char v_[(N+sizeof(char)-1)/sizeof(char)]; };
|
- 把所有的参数具体化,比如
T = float, N = 4
- 把部分参数具体化,比如
T = bool
需要注意的是,已经被具体化的参数就不要再出现在template<>
这里面了。如果所有的参数都被具体化的,那么template<>
这里面就什么都没有了。
比较复杂的是两种情况,也就是模板特化与模板模板参数
混在一起的时候。
#include <iostream> #include <typeinfo> using namespace std; template<class T, class U> class A { public: T t_; U u_; }; template<class U> class A<int, U> { public: short x; }; template<typename T, typename U, typename X, template<typename, typename> class V> class B { public: V<T, U> v_; void print() { cout << "B" << endl; } }; B<int, int, float, A> c; int main() { c.print(); }
|
接着再分析另外一个例子。
template<typename T, int i> class Arg; template<typename T1, typename T2, int i, template<typename, int> class CP> class Example { }; template<> class Example<int, float, 2, Arg>; template<typename T1, typename T2, int i, template<typename, int> class CP> class Example<const T1, T2, i, CP> { };
|
需要注意的是后面的那个class CP
在选择类型的时候,只能从T1/T2/i
里面选择了。
类型组合的特化
再看一个有趣的例子。
template<typename T, int i> class Example<Arg<T, i>, Arg<T, i+10>, i, Arg> { };
|
也就是说,在特化的时候,可以写成这样。
template<参数范围A> class Example<由A范围组合出按照顺序满足条件的这个具体类型即可> { };
|
那么在类里面使用Arg
的时候,可以选择的参数范围就是已知的类型。比如:
template<typename T, int i> class Arg{ }; template<typename T1, typename T2, int i, template<typename, int> class CP> class Example { }; template<typename T, int i> class Example<const T, Arg<T,i+10>, i, Arg> { public: Arg<T, i> s_; Arg<const T, i> a_; Arg<Arg<T,i>,i> b_; };
|
所以,可以看出Arg
这个模板类可以使用T,i, const T, Arg<T,i+10>, i,
都可以。
关于模板特化
- Base模板需要提前声明
- 如果模板A是模板B的子集,优先匹配A。
- 如果两个模板有交集,且不成子集关系,编译报错。
模板偏特化元编程
可以利用偏特化来实现if/else
对类型的操作。比如判断两个类型是否相等。代码如下:
#include <iostream> template<typename T1, typename T2> struct is_same { static constexpr bool value = false; }; template<typename T> struct is_same<T,T> { static constexpr bool value = true; }; template<typename T, int N> struct Example { }; int main(void) { typedef unsigned int uint; typedef uint uint2; std::cout << is_same<unsigned, uint2>::value << std::endl; std::cout << is_same<Example<unsigned, 2>, Example<uint2, 2>>::value << std::endl; std::cout << is_same<Example<int, 2>, Example<int, 3>>::value << std::endl; return 0; }
|
计算阶乘
#include <iostream> #include <stdint.h> template<int N> struct order { static constexpr int64_t value = N * order<N-1>::value; }; // 由于只有一个参数需要偏特化,所以 // 这里用template<> template<> struct order<0> { static constexpr int64_t value = 1; }; int main(void) { std::cout << order<10>::value << std::endl; return 0; }
|