函数模版
函数模版是通用的函数描述,使用泛型来定义函数,其中的泛型可用具体的类型(如int或double)来代替。通过将类型作为参数传递给模版,可使编译器生成该类型的函数。
下面演示一个最简单的函数模版:
//交换两数据的值
template<typename T>
void Swap(T &a, T &b){
T temp;
temp = a;
a = b;
b = temp;
}
如果采用以下调用:
int a=10;
int b=20;
Swap(a,b);
这将代表调用下面这个函数:
void Swap(int &a, int &b){
int temp;
temp = a;
a = b;
b = temp;
}
Swap()函数接受了两个int参数,因此编译器生成该函数的int版本,也就是说用int替换所有的T。
调用函数模版必须使用相同的类型,否则模版将无法识别不同的类型而导致编译错误
显式具体化
显式具体化也是基于函数模版的,只不过在函数模版的基础上,添加一个专门针对特定类型的、实现方式不同的具体化函数。
对于有些特殊类型,可能不适合模版实现,需要重新定义实现。此时可以使用显式具体化(explicit specialization)
以上面的Swap()模版为例,假定有如下结构体:
struct job{
char[20] name;
double salary;
};
如果采用Swap()函数模版将交换两个结构体。但如果只想交换其中的一部分,比如salary,而不交换name,则可以通过使用显式具体化。
//结构体
struct Job{
char[20] name;
double salary;
};
//函数模版
template<typename T>
void Swap(T &a, T &b){
T temp;
temp = a;
a = b;
b = temp;
}
//显式具体化
templete<> void Swap<Job>(Job &a,Job &b){
int temp;
temp = a.salary;
a.salary = b.salary;
b.salary = temp;
}
编译器会优先选择显式具体化的版本,交换结构体的salary,而非交换两个结构体。
编译器对三种原型的选择
对于交换结构体Job的非模版函数、函数模版和具体化的原型:
//非模版函数
void Swap(Job &,Job &);
//函数模版
template <typename T>
void Swap(T &,T &);
//显式具体化
template<>void Swap<Job>(Job &,Job &);
在有多个原型时,编译器在选择原型时,非模版版本优先于显式具体化和模版版本,而显式具体化优先于使用模版生成的版本。
显式实例化
当显式实例化模版时,在使用模版之前,编辑器根据显式实例化指定的类型生成模版实例。
template void Swap<int>(int&,int&);
显式实例化只需要声明,不需要重新定义。编译器会根据模版来实现实例声明和实例定义。
当然也可以直接调用 Swap<int>(a,b);
显式具体化和显式实例化的区别
//显式具体化
template<>void Swap<Job>(Job &,Job &);
//或
template<>void Swap(Job &,Job &);
//显式实例化
template void Swap<int>(int &,int &);
显式具体化不仅要声明,还要给出定义;
显式实例化只需要声明,不需要给出定义。