1. C++ 中主要有哪两种形式的模板,它们分别如何进行特化?
C++中有类模板与函数模板之分。这两种模板的工作方式并不完全一样,最明显的区别在于重载,普通C++类是不能重载的,因此类模板也不能够重载。另一方面,普通的C++函数如果名字相同(且函数签名不同)就会发生重载,因而函数也允许重载。 此外类模板可以被偏特化或全特化。函数模板则只能被全特化,不过,由于函数模板可以被重载,所以我们通过重载也能够达到类似偏特化的效果。
准则:记住,函数模板不能偏特化,只能重载。写一个看似函数模板偏特化的函数模板实际上是在写一个单独的主函数模板。
以下介绍在不同情况下哪个函数将会被调用:
1。非模板函数是C++中的一等公民。如果一个普通的非模板函数跟一个函数模板在重载解析的参数匹配中表现一样好的话,编译器会选择普通函数
2。如果编译器发现没有合适的“一等公民”可选的话,那么主函数模板作为C++中的二等公心就会被纳入考虑。具体选择哪个主函数模板则取决于哪 个参数类型匹配得最好。如果还不能决定可以根据以下准则再进一步选择
(1)如果显而易见存在一个“最特化“的主函数模板的话,该主函数模板就会被选中,如果这个被选中的主函数模板碰巧又针对所使用的模板实参做了特化的话,该特化版本就会被编译器选中,否则编译器将使用以正确的类型实例化主模板。
(2)否则,如果有两个或多个”最特化“的主函数模板下相互之间不能分出那个最好的话,调用就是二义性的,因为编译器不能确定它们中哪个是更好的匹配。
(3)否则,如果没有任何主函数模板可以匹配调用的话,调用就是错误的。
例:
template<class T> //(a) 一个主模板
void f(T);
template<class T>
void f(T*) //(b) 一个主模板,重载了(a): 由于函数模板不能被偏特休,所以只能用重载来代替
template<class T>
void f<int>(int *); //(c) : (b) 的一个显式特化
//
int *p;
f(p); //调用 (c)
template<class T> //(a) 一个主模板
void f(T);
template<>
void f<int*>(int *) //(c) 显式特化,这次是对(a)进行特化
template<class T>
void f(T *) //(b) :第二个主模板,重载了(a)
int *p;
f(p); //调用 (b)
因为函数特化并不参加重载