介绍
模板作为C++泛型编程的基础十分重要,其使得一份代码能用于处理多种数据类型。而有些时候,我们会希望对一些特定的数据类型执行不同的代码,这时就需要使用模板特例化(template specialization)。
函数模板特例化
首先说一个重要的,函数模板的特例化并不是函数重载,每一个特例化实际上是提供了另一个模板定义式,因此特例化不影响函数匹配。
特例化一个函数模板时,必须为模板中的每个参数都给出实参,关键字template后跟一个<>
template<typename T,typename P>
void test(T, P) {
}
template<>
void test(int a){
/*错误,没有提供模板中的每个参数*/
}
template<>//一个函数模板特例化
void test(string a,int b) {
cout << a << endl;
}
template<>//又一个函数模板特例化
void test(int a,char b) {
cout << a << ' ' << b <<endl;
}
{
string s{ "abc" };
test(1, 1);//调用非特例化模板test(T,P)
test(s, 1);//调用特例化版本test(string,int)
test(1, 'a');//调用特例化版本test(int,char)
}
类模板特例化
类模板中,提供所有实参时叫做全特化,类模板的全特化和函数模板的特例化上没有什么不同(除了一个是类模板一个是函数模板:D)
与函数模板必须为每个模板参数提供实参不同,类模板支持部分特例化,也叫偏特化(partial specialization),STL源码分析中引用了两个对其的定义:
[Austern99]:“所谓偏特化(partial specialization)的意思是提供另一个模板(template)定义式,其本身仍为模板化基类(templatized)”。
《泛型思维》:“针对(任何)模板参数更进一步的条件限制设计出来的一个特化版本”。
当定义类模板的偏特化版本时,模板参数只需包含原模板中那些还未确定类型的模板参数,在类名之后需要添加<>,且需要按对应位置填入实参。
template<typename T, typename P>
class test {
public:
test() { cout << "这是未特化的类模板\n"; }
};
template<typename P>//T被特化为bool类型,template<>中无需typename T
class test<bool,P> {
public:
test() { cout << "这是bool偏特化的类模板\n"; }
};
template<>//全特化,template<>可以为空
class test<int*, int*> {
public:
test(){ cout << "这是接受两个指针类型的全特化的类模板\n"; }
};
{
test<int*, int> t1;//会调用未特化的类模板
test<bool,int> t2;//会调用bool偏特化
test<int*, int*> t3;//全特化版本
}