函数模板与函数重载
函数模板与类模板是两大类主要的C++泛型编程的使用方法。
类模板可以进行模板偏特化和全特化,而函数模板只能进行全特化。但是类不同的是,函数还有一个重要的特性就是重载,如果将函数模板与函数重载的问题放在一块的时候,问题就变得比较麻烦了。
看下面的一个例子:
include <iostream>
using namespace std;
template <class T>
void f(T){
cout<<"f(T)"<<endl;
}
template <class T>
void f(T*){
cout<<"f(T*)"<<endl;
}
template<>
void f<int>(int*){
cout<<"f<int>(int*)"<<endl;
}
template<>
void f<int*>(int*){
cout<<"f<int*>(int*)"<<endl;
}
int main(){
int *p;
f(p);
}
using namespace std;
template <class T>
void f(T){
cout<<"f(T)"<<endl;
}
template <class T>
void f(T*){
cout<<"f(T*)"<<endl;
}
template<>
void f<int>(int*){
cout<<"f<int>(int*)"<<endl;
}
template<>
void f<int*>(int*){
cout<<"f<int*>(int*)"<<endl;
}
int main(){
int *p;
f(p);
}
运行该程序,会发现运行的结果是:f<int>(int*)
即调用的是第3个函数。
这儿容易让人疑惑的是,为什么不是第4个函数:template<>void f<int*>(int*) 呢?这个是template <class T>void f(T)的模板特化啊。
要理解这个就需要注意一点:带有函数模板的重载进行决议的时候,选择的规则是首先选择最优的普通函数,如果没有适合的普通函数那么就要从模板函数中选择。而进行选择的时候,是决定选择的哪个主模板函数,然后再看这个主模板函数是否存在对应的特化。所以,对于上面的选择,首先是在
template <class T>
void f(T)
和
template <class T>
void f(T*)
之间进行选择,发现第2个更加合适,这样就确定了主模板函数,然后在查找该主模板函数是否有对应的特化函数,这样正好找到了
template<>
void f<int>(int*)
它是对int的特化,所以最后选择了这个函数。
分开看是如下:
这儿容易让人疑惑的是,为什么不是第4个函数:template<>void f<int*>(int*) 呢?这个是template <class T>void f(T)的模板特化啊。
要理解这个就需要注意一点:带有函数模板的重载进行决议的时候,选择的规则是首先选择最优的普通函数,如果没有适合的普通函数那么就要从模板函数中选择。而进行选择的时候,是决定选择的哪个主模板函数,然后再看这个主模板函数是否存在对应的特化。所以,对于上面的选择,首先是在
template <class T>
void f(T)
和
template <class T>
void f(T*)
之间进行选择,发现第2个更加合适,这样就确定了主模板函数,然后在查找该主模板函数是否有对应的特化函数,这样正好找到了
template<>
void f<int>(int*)
它是对int的特化,所以最后选择了这个函数。
分开看是如下:
和
下面是一个比较全的重载决议的原则: