编写程序时不知道类型的情况下,可以支持面向对象编程(OOP )和通用编程。 区别在于,OOP可以在程序运行之前应对类型未知的情况。 在通用编程中,编译时可以知道类型。
前面介绍的容器、迭代器、算法都是通用编程的例子。 编写通用程序时,要独立编写特定类型和代码。 使用通用程序时,提供程序实例可以执行的类型或值。
模板是通用编程的基础。 模板是用于创建类和函数的蓝图和公式。 使用泛型类型(如向量)或泛型函数(如find )时,提供足够的信息将蓝图转换为特定的类型函数。 此转换在编译时发生。
定义模板
假设您想要创建一个用于比较两个值的函数,并指示第一个值是小于、等于还是大于第二个值。 实际上,您可能希望定义多个函数,每个函数都比较特定类型的值。 在第一次尝试中,可以定义多个重载函数。
intcompare(conststringV1,const string v2 ) )。
{if(V1V2 )返回1; 返回0;
}intcompare(constdoubleV1,const string v2 ) )。
{if(V1V2 )返回1; 返回0;
}
这两个函数几乎相同,唯一的区别是参数的类型,函数体完全相同。
如果每个想比较的类型都必须重复定义完全相同的函数体,那就非常麻烦而且容易出错。 更麻烦的是,在编写程序时,必须确定可能进行比较的所有类型。
函数模板
可以定义公共函数模板,而不是为每种类型定义新函数。 函数模板是一个可用于生成特定类型函数版本的表达式。 比较器的模板版本可能如下所示:
模板
intcompare(constTV1,const T v2 ) )。
{if(V1V2 )返回1; 返回0;
}
模板定义以关键字template开头,后跟模板参数列表。 这是一个或多个模板参数的类表,用逗号分隔,并用小符号()括起来。
在模板定义中,模板参数列表不能为空。
模板参数列表类似于函数参数列表。 函数参数列表中定义了某些特定类型的局部变量,但未显示初始化方法。 在执行时,调用方提供用于初始化形参的实参。
同样,模板参数表示类或函数定义中使用的类型或值。 使用模板时,可以隐式或显式指定模板参数" template argument "并将其绑定到模板参数。
我们的compare函数声明了一个名为t的类型参数。 在比较中,我们用名字t表示一种类型。 t表示的实际类型是在编译时根据compare的使用状况决定的。
实例化函数模板
调用函数模板时,编译器通常使用函数参数来估计模板参数。 也就是说,调用compare时,编译器使用实参的类型来确定绑定到模板参数t的类型。 例如,在以下调用中:
出局了
实际参考类型为int。 编译器将模板参数估计为int,并绑定到模板参数t。
使用编译器估计的模板参数实例化函数的特定版本。 当编译器实例化模板时,它将使用实际模板参数而不是相应的模板参数来创建模板的新“实例”。
例如,以下调用:
实例化//int compare (常数int,常数)
出局了
实例化//int compare (常数向量,常数向量)
vector vec1(1,2,3 )、ve C2 (4,5,6 );
出局了
编译器实例化两个不同版本的compare。 在第一次调用中,编译器创建并编译compare版本。 其中,t将被int替换。
intcompare(constintV1,const int v2 ) )。
{if(V1V2 )返回1; 返回0;
}
在第二个调用中,编译器生成另一个compare版本。 其中,t被向量替换。 这些编译器生成的版本通常称为模板的实例。
模板类型参数
我们的compare函数有模板类型参数。 通常,类型参数可以视为类型说明符,可以像内置类型或类类型说明符一样使用。 特别是,类型参数可用于指定返回类型或函数的参数类型,以及在函数中用于变量声明和类型转换。
类型参数必须使用关键字class或typename。
//错误:必须在u前加上class或typename
模板调用(const U,const U );
在模板参数列表中,这两个关键字的含义相同,可以相互转换使用。 单个模板参数列表中可以同时使用这两个关键字。
//正确:在模板参数列表中,typename和class没有任何区别
模板呼叫(const U,const U );
使用关键字typename指定模板类型的参数看起来比使用class更直观。 毕竟,可以使用内置(非类)类型作为模板类型的实参。 而且,typename更明确地表示之后的名称是类型名。
非类型模板参数
除了定义类型参数外,还可以在模板定义中定义非类型参数。 非类型参数表示值,而不是类型。 使用特定类型名称而不是关键字class或typename指定非类型参数。
实例化模板后,未类型参数将替换为用户指定的值或编译器估计的值。 这些值必须是常量表达式,以便编译器可以在编译时实例化模板。