1. 定义模板
a) 假定我们希望编写一个函数比较两个值,并指出第一个值是大于、小于或是等于第二个值,我们可能会定义多个重载函数:
int compare(const string &v1,const string &v2){
if(v1<v2) return -1;
if(v2<v1) return 1;
return 0;
}
int compare(const double &v1,const double &v2){
if(v1<v2) return -1;
if(v2<v1) return 1;
return 0;
}
这两个函数唯一的差异是参数类型。对每种希望比较的类型都不得不重复定义完全一样的函数体既繁琐又容易出错还不能用在用户提供的类型上
b) 我们可以定义一个通用的函数模板,而不是为每个类型都定义一个新函数。
c) 一个函数模板就是一个公式,可用来生成针对特定类型的函数坂本
d) compare的模板坂本可能像下面这样:
template <typename T>
int compare(const T &v1,const T &v2){
if(v1<v2) return -1;
if(v2>v1) return 1;
return 0;
}
2. 函数模板:
a) 模板定义以关键字template开始,后跟一个不能为空的模板参数列表,这是一个逗号分隔的一个或多个模板参数的列表,用<>包围起来
b) 模板参数列表的作用很像函数参数列表。函数参数列表定义了若干特定类型的局部变量,但并未指出如何初始化它们。在运行时,调用者提供实参来初始化形参
c) 类似的,模板参数表示在类或函数定义中用到的类型或值。当使用模板时,我们(隐式地或显式地)指定模板实参,将其绑定到模板参数
d) compare函数声明了一个名为T的类型参数。在compare中,用名字T表示一个类型,而T表示的实际类型则在编译时根据compare的使用情况确定
3. 实例化函数模板
a) 当我们调用一个函数模板时,编译器用函数实参来为我们推断模板实参(调用compare时,编译器使用实参的类型确定绑到模板参数T的类型)。例如,下面的调用中, 实参类型是int,编译器会推断出模板实参为int,并将它绑定到模板参数T
cout<<compare(1,0)<<endl; //T为int
b) 编译器用推断出的模板参数来为我们实例化一个特定版本的函数。当编译器实例化一个模板时,它使用实际的模板实参代替对应的模板参数来创建出模板的一个新实例
//实例化出int compare(const int&,const int&)
cout<<compare(1,0)<<endl; //T为int
//实例化出int compare(const vector<int>&,const vector<int>&)
cout<<compare(vec1,vec2)<<endl; //T为vector<int>
这些编译器生成的坂本通常被称为模板的示例
4. 类模板
a) 类模板是用来生成类的蓝图的
b) 与函数模板的不同之处是,编译器不能为类模板推断模板参数类型。为了使用类模板,我们必须在模板名后的尖括号中提供额外信息(以vector为例,提供的额外信息是 vector内所存放对象的类型,如vector<int> ivec)用来代替模板参数的模板实参列表