一、类模板的泛化
与函数模板一样,类模板的泛化就是普通的模板,不具有特殊性的模板。
以下的类模板为泛化的版本
//类模板的泛化
template<typename T,typename U>
struct TC {//静态成员变量static int static_varible; //声明TC() {std::cout << "TC泛化版本的构造函数\n";}void func1(); void func2();
};//类外实现func1
template<typename T,typename U>
void TC<T, U>::func1() {std::cout << "func1的泛化版本\n";
}//类外实现func2
template<typename T, typename U>
void TC<T, U>::func2() {std::cout << "func2的泛化版本\n";
}template<typename T,typename U>
int TC<T, U>::static_varible = 50; //定义(初始化)
这里采用的类内声明,类外定义的方法
二、类模板的全特化
1.类模板的全特化
我们可以在有泛化版本的前提下,加入一个全特化的版本,如下所示:
//类模板的全特化
template<>
struct TC<int,int> { //<>符号是必要的TC() {std::cout << "TC<int,int>的特化版本构造函数\n";}void func1() {std::cout << "TC<int,int>的特化版本func1函数\n";}void func2();//添加泛化版本中没有的函数void func3();
};
注意,我们在类外实现函数的时候不能加入 t e m p l a t e < > template<> template<>,否则会编译失败。
//类外实现func2
//注意全特化版本类外实现不能加template<>//template<>
void TC<int, int>::func2() {std::cout << "TC<int,int>的特化版本func2函数\n";}//类外实现fun3
void TC<int, int>::func3() {std::cout << "TC<int,int>的特化版本func3函数\n";
}
由于全特化版本的类已经和泛化版本的类区分开来了,因此可以添加上泛化版本没有的内容。
如我们在成员函数上增加了 f u n c 3 func3 func3函数。
2. 普通成员函数的全特化
我们这里以全特化 f u n c 1 func1 func1函数为例:
//普通成员函数的全特化
template<> //这里可加可不加
void TC<double, int>::func1() { //全特化func1成员函数std::cout << "普通成员函数TC<double,int>::func1的全特化\n";
};
成员函数的全特化可以忽略 t e m p l a t e < > template<> template<>,也可以使用。
注意,如果我们先对泛化版本添加了成员函数的全特化版本,那么我们就无法对泛化版本添加相同的全特化的类模板,因为类模板的成员函数已经被占用了。
如图:
template<>
struct TC<double,int> { //此时TC的<double,int>版本部分内容已经被占用了TC();void func1();void func2();};
会编译失败
3.静态成员变量的全特化
对于静态成员函数的全特化,我们首先必须在类外定义静态成员函数的泛化版本,然后再加入全特化版本。
泛化版本的定义:
template<typename T,typename U>
int TC<T, U>::static_varible = 50; //定义(初始化)
加入全特化版本的静态成员变量:
//静态成员变量的全特化
template<> //这里可加可不加
int TC<double, int>::static_varible = 100;
对于静态成员变量的全特化,与普通成员函数一样,已经占有了就不能再加入相同版本的全特化类模板了。
三、类模板的偏特化
函数模板不具有偏特化,而类模板可以进行偏特化。
1. 模板参数数量上的偏特化
我们可以指定类模板的某些参数类型,特殊对其进行偏特化:
下面是 T C TC TC类模板在参数数量上的偏特化版本:
//模板参数数量上的偏特化
template<typename U>
struct TC<float, U> {TC() {std::cout << "TC<float,U>偏特化版本的构造函数\n";}void fun1();
};
//类外实现
template<typename U>
void TC<float, U>::fun1() {std::cout << "TC<float,U>偏特化版本的func1函数\n";
}
通过调用,我们发现使用了偏特化版本
void Test() {TC<float,int>t;
}
如图所示:
2.模板参数范围上的偏特化
有时,对于一些特殊的类型参数我们要进行特殊处理,如
∗ ( 指针 ) , & ( 左值引用 ) , & & ( 右值引用 ) , c o n s t ( 常变量 ) *(指针),\&(左值引用),\&\&(右值引用),const(常变量) ∗(指针),&(左值引用),&&(右值引用),const(常变量)
因此,我们就可以对这些变量加入偏特化版本:
下面实现一个偏特化的 T C < c o n s t T , U ∗ > TC<const \ T,U*> TC<const T,U∗>的版本:
//模板参数范围上的偏特化
template<typename T,typename U>
struct TC<const T, U*> { //限定T为const类型,U为指针TC() {std::cout << "TC<const T,U*>偏特化版本的构造函数\n";}void func1();
};//类外实现
template<typename T,typename U>
void TC<const T, U*>::func1() {std::cout << "TC<const T,U*>偏特化版本的func1函数\n";
}
而这样就能缩小范围,在调用时优先调用偏特化版本。
如下图所示:
优先使用了偏特化版本的构造函数。
当然,如果去掉了这个偏特化版本,将会调用泛化版本。
注释掉偏特化版本后,运行得到:
由于找不到全特化版本和偏特化版本,因此最终调用了泛化版本
3.其他
最后,对于偏特化版本的话,不存在对成员函数或静态成员变量的偏特化。
以下代码无法通过编译:
//不存在对成员函数的偏特化
template<typename U>
void TC<double, U>::func2() {std::cout << "TC<double,U>偏特化版本的func2函数\n";
}