一、类模板的泛化
与函数模板一样,类模板的泛化就是普通的模板,不具有特殊性的模板。
以下的类模板为泛化的版本
//类模板的泛化
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";
}