具体template使用网上可以看到说明,在这里强调一点关于template模版实参为空的特例。 转载网络关于c++考级的要点. 知识点4:
1.1 函数模板
1.1.1 考点1:函数模板的概念和声明
函数模板是一系列相关函数的模型或样板,这些相关函数的源代码形式相同,只是所针对的数据类型不同。对于函数模板,数据类型本身成了它的参数,因而是一种参数化类型的函数。类的成员函数也可以声明为函数模板。
声明一个函数模板的格式如下:
template <模板形参表声明>
返回类型 函数名(函数形参表)
{
…… //函数体
}
其中,<模板形参表声明>是由一个或多个“模板形参”组成的,如果是多个,则要用逗号隔开。“模板形参”具有下面3种形式:
typename 参数名
class 参数名
类型修饰 参数名
这里的参数名可以是任意合法的C++标识符。前两种形式是等价的,也就是说,在声明模板形参时,关键字typename和class可以互换。用typename或class声明的参数称为虚拟类型参数;而用“类型修饰”声明的参数则称为常规参数。这里的“类型修饰”是指具体的数据类型(如int、double、char等)。函数模板的<模板形参表声明>中,一定要包含虚拟类型参数,而常规参数则可以根据实际需要选择。
<模板形参表声明>中声明的虚拟类型参数可以用做:
函数的返回值类型
函数的形参的类型
函数体内变量的类型
例1.1.1 下列是模板声明的开始部分,其中正确的是( )。
A.template <T> B.template <class T1,T2>
C.template <class T1,class T2> D.template <class T1;class T2>
答案:C
例1.1.2 下面的函数模板定义中错误的是( )。
A.template<class Q> B.template<class Q>
Q F(Q x){return Q+x;} Q F(Q x){return x+x;}
C.template<class T> D.template<class T>
T F(T x){return x*x;} bool F(T x){return x>1;}
解析:各个选项中声明的Q和T都是虚拟类型参数。函数模板形参表中声明的虚拟类型参数可以用做:
函数的返回值类型
函数的形参的类型
函数体内变量的类型
选项B、C和D符合以上三种用法。而选项A让虚拟类型参数Q直接参与运算是错误的。虚拟类型是具体类型(如int型,double型等)的抽象。我们知道,int本身并不能直接参与数学运算,但是由它定义的int型变量或int型参数可以直接参与运算。虚拟类型Q和T本身也不能直接参与运算,但是由它们定义的“T类型”或“Q类型”的参数x可以参与运算。所以,选项A中“Q+x”的表达是错误的。
答案:A
1.1.2 考点2:模板函数
函数模板中声明的函数称为模板函数。
调用一个模板函数的格式如下:
函数名 <模板实参表> (函数实参表);
或
函数名(函数实参表);
第二种格式中省略了所有的模板实参,使用这种格式是需要一定条件的(详见考点4)。
类模板的成员函数都是模板函数。
例1.1.3 以下函数模板max的功能是:返回数组a中最大元素的值。请将横线处缺失部分补充完整。
template <typename T>
T max (T a[], int n)
{
T m = a[0];
for (int i = 1; i < n; i++)
if (a[i]>m) ;
return m;
}
解析:本题考查模板函数的定义。在编写函数体时,模板函数与普通函数是一样的。根据题意,返回的m值应该是a中最大元素的值,所以当a[i]>m时,应该将较大的a[i]值赋给m。在遍历数组a[]后,最终m就保存了数组a[]中最大元素的值。
1.1.3 考点3:函数模板的实例化
在调用模板函数时,编译系统依据实际所使用的数据类型生成某个具体函数定义的过程称为函数模板的实例化。在实例化过程中,是用实际类型(如int、long等)替代虚拟类型的。
实例化的过程或结果通常是看不见的,编译系统会根据函数调用的具体情况自动传递相应的模板实参,生成相应的函数实例。每一个实例就是一个函数定义。
实例化过程中,除了可以用各种具体的C++固有数据类型取代虚拟类型,还可以用某些用户自定义类型来取代虚拟类型,这里的自定义类型包括结构体以及某些用户定义的类。
例1.1.4 下列程序的输出结果是 。
#include <iostream>
using namespace std;
template <typename T>
T fun (T a, T b) {return (a<=b)?a:b;}
int main()
{
cout<<fun(3,6)<<','<<fun(3.14F,6.28F)<<endl;
return 0;
}
解析:本题定义了一个模板函数fun,其形参a、b及函数返回类型均为T类型。函数fun的功能是返回a、b中数值较小的数。在main函数中,第一次调用fun时,实际上是调用了“int fun(int a,int b)”这个函数,故返回整型数据“3”。第二次调用时,实际上是调用了函数“float fun (float a, float b)”,返回浮点型数据“3.14”。
答案:3,3.14
1.1.4 考点4:模板实参的省略
在调用模板函数时,编译系统需要足够的信息来判别每个虚拟类型参数所对应的实际类型,可以从两个不同的渠道获得信息:从“模板实参表”(在“<”和“>”之间)或从模板“函数实参表”(在“(”和“)”之间),“模板实参表”的信息优先于“函数实参表”的信息。如果从后者得到的信息已经能够判断其中部分或全部虚拟类型参数所对应的实际类型,而且它们又正好是“模板形参表声明”中最后的若干参数,则在“模板实参表”中可以省略这几个参数。如果所有的模板实参都被省略了,则空表“<>”也可以省略。
但在以下情况中,模板实参是不能省略的。
① 从模板“函数实参表”中获得的信息有矛盾。例如,当编译系统从某一个函数实参中获得的信息是虚拟类型参数T(假设为T)对应的实际类型为int,可是从另一个函数实参中获得的信息却是虚拟类型参数T对应的实际类型为double时,就产生了矛盾。T不可能同时为
int和double型,这将导致编译器无法找到匹配的函数模板的定义,编译时报错。解决这一问题的方法之一就是显示给出虚拟类型参数T对应的模板实参,强制T对应于int或是double。
② 虚拟类型参数用做函数的返回值类型,而且函数需要返回特定类型的值,而不管函数实参的类型是什么。在这种情况下,需要用模板实参强制虚拟类型参数对应于特定类型。
③ 虚拟类型参数没有出现在模板的“函数形参表”中。此时无法从模板的“函数实参表”中获取对应的信息,因而不能省略模板实参。
④ 函数模板含有常规形参。常规参数是用具体的类型修饰符(如int、double、char*等)定义的,对应的实参必须是常量表达式。因此,常规参数的信息无法从模板的“函数实参表”中获得,调用模板函数时必须显示给出对应于常规参数的模板实参。
例1.1.5 有如下函数模板定义:
template <class T>
T func (T x, T y){ return x*x+y*y;}
在下列对func的调用中,错误的是( )。
A.func(3,5); B.func(3.0,5.5); C.func(3,5.5); D.func<int>(3,5.5);
解析:对于本题中定义的模板函数,如果用选项C中“func(3,5.5);”的形式来调用,在编译时会出现“template parameter 'T' is ambiguous,could be 'double' or 'int' ”的错误,也就是说T对应的实际类型是不明确的。编译系统从第一个参数“3”获得的信息是“T对应于int”,而从第二个参数“5.5”处获得的信息是“T对应于double”,二者相互矛盾,因而编译时产生错误。
选项D中提供了模板实参<int>,因为模板实参优先于函数实参,所以T对应的实际类型是明确的,在这里就是int型。在调用过程中,double型的参数“5.5”将被自动转换成int型。
选型A和B所提供的两个函数实参的类型是一致的,不存在矛盾。
答案:C
例1.1.6 有如下函数模板声明:
template <typename T>
T Max(T a,T b) {return (a>=b)?a:b;}
下列对函数模板Max的调用中错误的是( )。
A.Max(3.5,4.5) B.Max(3.5,4)
C.Max<double>(3.5,4.5) D.Max<double>(3.5,4)
答案:B