说明:本笔记是参考《C++ Primer(3rd)》中文版
函数模板提供了一种机制,通过它可以保留函数定义和函数调用的语义(在一个程序位置上封装了一段代码,确保在函数调用之前实参只被计算一次),而无需象宏方案那样绕过C++的强类型检查。如:
template <class Type>
Type min(Type a,Type b)
{
return a<b ? a : b;
}
关键字template总是放在模板的定义与声明的最前面。关键字后面是用逗号分隔的模板参数表,它用尖括号(<>)括起来。该列表是模板参数表,不能为空。模板参数分为:(1) 模板类型参数,代表一种类型;(2) 模板非类型参数,代表一个常量表达式。
模板类型参数由关键字class或typename后加一个标识符构成。在函数的模板参数表中,这两个关键字的意义相同。它们表示后面的参数名代表一个潜在的内置或用户定义的类型。
模板非类型参数由一个普通的参数声明构成。模板非类型参数表示该参数名代表了一个潜在的值,而该值代表了模板定义中的一个常量。如:
template <class Type,int size>
Type min(Type (&arr)[size]);
规则:
1. 如果在全局域中声明了与模板参数同名的对象、函数或类型,则该全局名将被隐藏。
2. 在函数模板定义中声明的对象或类型不能与模板参数同名。
3. 模板类型参数名可以被用来指定函数模板的返回位。
4. 模板参数名在同一模板参数表中只能被使用一次,但可在多个函数模板声明或定义之间被重复使用。
通过将关键字typename引入到C++中,我们可以对模板定义进行分析。为了分析模板定义,编译器必须能够区分出是类型以及不是类型的表达式。如(Parm代表一个类):
template <class Parm,class U>
Parm minus(Parm* array,U value)
{
Parm::name * P; // 这是一个指针声明还是乘法?答案是乘法
}
编译器不知道name是否为一个类型,因为它只有在模板被实例化之后才能找到Parm表示的类的定义。为了让编译器能够分析模板定义,用户必须指示编译器哪些表达式是类型表达式。告诉编译器一个表达式是类型表达式的机制是在表达式前加上关键字typename。如:
template <class Parm,class U>
Parm minus(Parm* array,U value)
{
typename Parm::name * P; // 这是指针声明
}
函数模板也可被声明为inline或extern。但应把指示符放在模板参数表后面,而不是在template前面:
template <typename Type>
inline
Type min(Type,Type);