函数重载通常用于执行相似的操作,这些操作涉及作用于不同数据类型上的不同程序逻辑。如果对于每种数据类型程序逻辑和操作都是相同的,那么使用函数模板可以使重载执行起来更加紧凑方便。
程序员需要编写单个函数模板定义。只有在这个模板函数调用中提供了实参类型,c++就会自动生成独立的函数模板特化来恰如其分地处理每种类型的调用。这样,定义一个函数模板实质上就是定义了一整套重载的函数。
1.函数模板不编译
函数模板本身不是函数,编译器用模板产生指定的函数的特定类型版本,产生模板特定类型的过程称为函数的模板实例化。模板实例化发生在编译期。在使用函数模板时,编译器需要根据传入的实参类型,推演生成对应类型的函数来使用。
2.模板的作用域只在当前(单文件)
函数模板只在当前文件管用,因为模板实例化是在编译期,而编译是单文件的,所以函数模板在一个文件里定义,在另一个文件了实例化的话会发生错误。
3.函数模板的显示实例化和隐式实例化,如下:
template <typename T>
void Swap(T &a, T &b)
{
T temp;
temp = a;
a = b;
b = temp;
}
int main()
{
int a = 1;
int b = 2;
//隐式实例化
Swap(a, b);
//显示实例化
Swap<int>(a, b);
return\;
}
4.函数模板的特例化
上文提到:如果对于每种数据类型程序逻辑和操作都是相同的,那么使用函数模板会十分方便,但是存在一种情况:对于绝大多数数据类型程序和操作都是相同的,只有个别类型程序的操作不同,是否函数模板就不能用了呢?答案是否定的,c++提供了函数模板的特例化机制,即对于特殊的类型做与模板定义所不同的操作。
例如:有一个比较大小的函数,可以定义一个模板,对于int、double、char等类型均可用相同的操作,但是对于字符串char*类型的数据就不可以直接比较大小,因此需要特例化一个与其他类型不同的操作。如下:
template<typename T>//函数模板
bool compare(const T a, const T b)
{
cout << "bool compare(const T a, const T b)" << typeid(T).name() << endl;
return a > b;
}
typedef char* CharPtr;
template<>//函数模板的特例化
bool compare<CharPtr>(const CharPtr a, const CharPtr b)
{
cout << "bool compare(CharPtr)(const CharPtr a, const CharPtr b)" << typeid(a).name();
return strcmp(a, b) > 0;
}
5.函数模板的重载
函数模板的重载和普通函数的重载是相同的。如下:
template<typename T>//函数模板
bool compare(const T a,const T b)
{
cout << "bool compare(T a, T b) " << typeid(T).name() << endl;
return a > b;
}
template<typename T>//函数模板的重载
bool compare(T *arr1,int len1,T *arr2,int len2)
{
cout << "bool compare(T *arr1,int len1,T *arr2,int len2) " << typeid(arr1).name()<<endl;
int i, j;
for ( i = 0, j = 0; i < len1&&j < len2; i++, j++)
{
if (arr1[i] > arr2[j])
{
return true;
}
}
if (i == len1)
{
return false;
}
return true;
}
6.调用的优先级
函数调用的顺序是:非模板函数->模板特例化->模板
由此可见,只有在没有对应的非模板函数和特例化的时候才会调用函数模板。