模板是泛型编程的基础,一个模板就是创建类或者函数的蓝图或者说公式。
1. 定义模板。我们可以定义一个通用的函数模板,而不是为每一个类型都定义一个重载函数。
template <typename T>
int compare(const T& v1, const T& v2)
{
if(v1 < v2) return -1;
if(v1 > v2) return 1;
return 0;
}
函数模板定义中,参数列表不能为空。
2. 实例化函数模板
调用一个函数模板时,编译器通常用函数的实参来为我们推断模板实参。编译器用推断出的模板参数来实例化一个特定版本的函数。例如,给定下面的调用:
cout << compare(1, 0) << endl; //实例化出 int compare(const int&, const int&);
3. 模板类型参数。
template <typename T>
T就是模板的类型参数。类型参数可以像内置类型或者类类型一样使用,可以指定为函数的返回值类型或参数类型,也可以在函数体内部声明变量或者类型转换。
类型参数前必须使用关键字class或typename,这两个关键字的含义相同,可以互换。typename看起来更为直观。
4. 非类型模板参数
非类型参数表示一个值而不是一个类型。通过一个特定的类型名而不是关键字class或者typename来指定非类型参数。模板被实例化时,非类型参数被用户提供的或者编译器推断出的值所替代。这些值必须是常量表达式,从而允许编译器在编译时实例化模板。
template <unsigned N, unsigned M>
int compare2(const char(&p1)[N], const char(&p2)[M])
{
return strcmp(p1, p2);
}
非模版类型参数的模版实参必须是常量表达式。
5. 函数模版和类模版的成员函数的定义通常放在头文件中,因为编译器实例化一个模版时,需要掌握函数模版的定义。模版函数或者类模版的成员函数必须是可见的,因此一般定义在头文件中。