模板是C++中一个很重要的特性,写一份代码能用于多种数据类型(包括用户自定义类型)。例如,STL的sort()函数可以用于多种数据类型的排序,类stack可以用作多种数据类型的栈。但是,如果我们想对特定的数据类型执行不同的代码(而不是通用模板)呢?这种情况下就可以使用模板特例化(template specialization)。
函数模板特例化
当特例化一个函数模板时,必须为原模板中的每个模板参数都提供实参。使用关键字template后跟一个空尖括号<>,即template <>
,以指出我们正在特例化一个模板。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19template <typename T>
void fun(T a)
{
cout << "The main template fun(): " << a << endl;
}
template <> // 对int型特例化
void fun(int a)
{
cout << "Specialized template for int type: " << a << endl;
}
int main()
{
fun<char>('a');
fun<int>(10);
fun<float>(9.15);
return 0;
}
输出结果:1
2
3The main template fun(): a
Specialized template for int type: 10
The main template fun(): 9.15
对于除int型外的其他数据类型,都会调用通用版本的函数模板fun(T a)
;对于int型,则会调用特例化版本的fun(int a)
。注意,一个特例化版本的本质是一个实例,而非函数的重载。因此,特例化不影响函数匹配。
类模板特例化
除了特例化函数模板,我们还可以特例化类模板。下面是一个简单的例子:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26template <typename T>
class Test{
public:
void print(){
cout << "General template object" << endl;
}
};
template<> // 对int型特例化
class Test<int>{
public:
void print(){
cout << "Specialized template object" << endl;
}
};
int main()
{
Test<int> a;
Test<char> b;
Test<float> c;
a.print();
b.print();
c.print();
return 0;
}
输出结果:1
2
3Specialized template object
General template object
General template object
另外,与函数模板不同,类模板的特例化不必为所有模板参数提供实参。我们可以只指定一部分而非所有模板参数,这种叫做类模板的偏特化 或 部分特例化(partial specialization)。例如,C++标准库中的类vector的定义:1
2
3
4
5
6
7
8
9
10
11
12template <typename T, typename Allocator>
class vector
{
/*......*/
};
// 部分特例化
template <typename Allocator>
class vector<bool, Allocator>
{
/*......*/
};
在vector这个例子中,一个参数被绑定到bool类型,而另一个参数仍未绑定需要由用户指定。注意,一个类模板的部分特例化版本仍然是一个模板,因为使用它时用户还必须为那些在特例化版本中未指定的模板参数提供实参。