重载函数模板:
<int*>生成的重载集包含两个函数:f<int*>(int*)和f<int*>(int**)。
f<int>生成的重载集包含两个函数:f<int>(int)和f<int>(int*)。
调用实参(int*)0的类型是int*,因此,两次调用都会匹配到f<int*>(int*)。
原则上,下面的模板和它们的实例化体可以在同个程序中同时存在:
不过f1<char, char>('a', 'b');这样的调用就会产生二义性。
只有在f1这两个模板出现在不同的翻译单元时,它们的两个实例化体才可以在同个程序中同时存在。
显式特化:
全局的类模板特化:
引入全局特化需要用到下面3个标记序列:template、< 和 >。
全局特化的实现并不需要与泛型实现有任何关联,这就允许可以包含不同名称的成员函数。实际上,全局特化只和类模板的名称有关联。
应该使用位于类外部的普通成员定义语法来定义全局类模板特化的成员,也就是说不能指定template<>前缀。
全局模板特化和由模板生成的实例化版本不能够共存于同一个程序中:
全局的函数模板特化:
与类模板特化的区别在于:函数模板特化引入了重载和实参演绎两个概念
全局函数模板特化不能包含缺省的实参值:
template<> int f(int, int = 35) { //错误
return 0;
}
对于非内联的全局函数模板特化而言,在同个程序中它的定义只能出现一次,仍然必须确保:全局函数模板特化的声明必须紧跟在模板定义的后面,以避免试图使用一个由模板直接生成的函数。
另一种解决方案是把这个特化声明为内联函数,在这种情况下,该函数的定义就可以放在头文件中。
全局成员特化:
实现特化的语法要求给每个外围类模板加上template<>前缀,如果同时要对一个成员模板进行特化,还必须加上另一个template<>前缀来说明该声明表示的是一个特化:
template<>
template<>
class Outer<char>::Inner<wchar_t> {
public:
enum { count = 1 };
};
局部的类模板特化:
表示一个局部特化的语法包括:一个模板参数列表声明和在类模板名称后面指定的模板实参列表
局部特化声明的参数列表和实参列表的一些约束
类模板局部特化的参数个数是可以和基本模板不一样的
例:针对指向成员指针的指针
小结:
类模板特化和函数模板重载的区别:
对于特化,在看到一个调用时,只会查找基本模板,在后来需要决定调用哪一个实现的时候才会考虑具体的特化模板。
对于重载函数模板进行查找的时候,所有的重载函数模板都必须放入重载集里面,而且这些重载函数模板还可以来自不同的名字空间和类。