函数模板:
函数模板是函数的蓝图或处方,编译器使用它生成函数系列的新成员。新函数在第一次使用时创建。从函数模板中生成的函数称为该模板的一个实例或模板的实例化。函数模板的开头是关键字template,表示这是一个模板。其后是一对尖括号,它包含了参数列表。在使用从模板中生成的函数之前,必须确保把声明(即原型)或模板的定义放在源文件中。模板的实例化只生成一次。如果后续的函数调用需要同一个实例,就会调用已经创建好的实例,即使同一个实例在不同的源文件中生成,程序也仅会包含该实例定义的一个副本。使用时需要注意两个问题:
第一,函数模板本身不做任何工作,它是编译器用于从函数调用中创建函数定义的处方或蓝图。
第二,所有工作都在编译和链接过程中完成。编译器使用模板生成函数定义的源代码,再编译这些代码。链接程序的作用是仅把函数的一个实例链接到可执行模块上,即使几个不同的源文件调用同一个实例,也只链接一个实例。在执行程序时,源代码中是否存在模板根本不重要。
显示指定模板参数:
在调用函数时,可以显示指定模板的参数,以控制使用哪个版本的函数。编译器不再推断用于替换T的类型,只是接受指定的版本。在下列情形下,比较有用:
1、函数调用不是很确切,编译失败。此时可以使用该技巧帮助编译器去除不确定性。
2、在一些情况下,编译器不能推断出模板参数,因此无法选择要使用哪个版本的函数。
3、为了避免有太多的函数版本(从而避免过多占用内存),可以强迫函数调用使用某个版本的函数。
模板的说明:
对于某个参数值(在有多个参数的模板中,就是一组参数值),模板的说明定义了它不同于标准模板的动作。模板说明的定义必须放在原语句的声明或定义之后。如果把说明放在前面,程序就不会编译。
说明的定义以关键字template开头,但要省略参数,所以原声明中模板参数外部的尖括号就是空的。必须定义说明的参数值,而且必须放在模板函数后面的尖括号中。下面看示例:
示例:
#include <iostream> using std::cout; using std::endl; //模板声明 template<class T> T larger(T a,T b); //模板说明声明 template<> long* larger<long*>(long* a,long* b); int main(int argc,char* argv[]){ cout<<"Larger of 1.5 and 2.5 is "<<larger(1.5,2.5)<<endl; int a_int=35; int b_int=45; cout<<"Larger of "<<a_int<<" and "<<b_int<<" is " <<larger(a_int,b_int)<<endl; long a_long=9; long b_long=8; cout<<"Larger of "<<a_long<<" and "<<b_long<<" is " <<larger(a_long,b_long)<<endl; //显示指定模板参数 cout<<"Larger of "<<a_int<<" and "<<b_int<<" is " <<larger<long>(a_int,b_int)<<endl; //调用模板说明 cout<<"Larger of "<<a_long<<" and "<<b_long<<" is " <<*larger(&a_long,&b_long)<<endl; return 0; } //模板定义 template <class T> T larger(T a,T b){ cout <<"standard version"<<endl; return a>b?a:b; } //模板说明定义 template <> long* larger<long*>(long* a,long* b){ cout <<"specialized version"<<endl; return *a>*b?a:b; }