第2章 函数模板
这一章介绍函数模板。函数模板是那些被参数化的函数,它们代表的是一个函数家族。
2.1 初探函数模板
函数模板提供了一种函数行为,该函数行为可以用多种不同的类型进行调用;也就是说,函数模板代表一个函数家族。它的表示(即外形)看起来和普通的函数很相似,唯一的区别就是有些函数元素是未确定的:这些元素将在使用时被参数化。为了阐明这些概念,让我们先来看一个简单的例子。
2.1.1 定义模板
下面就是一个返回两个值中最大者的函数模板:
//basics/max.hpp
template
inline T const& max (T const& a, T const& b)
{
// 如果a < b,那么返回b,否则返回a
return a < b b : a;
}
这个模板定义指定了一个“返回两个值中最大者”的函数家族,这两个值是通过函数参数a和b传递给该函数模板的;而参数的类型还没确定,用模板参数T来代替。如例子中所示,模板参数必须用如下形式的语法来声明:
template < comma-separated-list-of-parameters >
//template < 用逗号隔开的参数列表 >
在我们这个例子里,参数列表是typename T。可以看到:我们用小于号和大于号来组成参数列表外部的一对括号,并把它们称作尖括号。关键字typename引入了所谓的类型参数T,到目前为止它是C++(www.cppentry.com)程序使用最广泛的模板参数;也可以用其他的一些模板参数,我们将在后面介绍(见第4章)。
在上面程序中,类型参数是T。你可以使用任何标识符作为类型参数的名称,但使用T已经成为了一种惯例。事实上,类型参数T表示的是,调用者调用这个函数时所指定的任意类型。你可以使用任何类型(基本类型、类等)来实例化该类型参数,只要所用类型提供模板使用的操作就可以。例如,在这里的例子中,类型T需要支持operator<,因为a和b就是使用这个运算符来比较大小的。
鉴于历史的原因,你可能还会使用class取代typename,来定义类型参数。在C++(www.cppentry.com)语言的演化过程中,关键字typename的出现相对较晚一些;在它之前,关键字class是引入类型参数的唯一方式,并一直作为有效方式保留下来。因此,模板max()还可以有如下的等价定义:
template
inline T const& max (T const& a, T const& b)
{
// 如果 a < b ,那么返回 b ,否则返回 a
return a < b b : a;
}
从语义上讲,这里的class和typename是等价的。因此,即使在这里使用了class,你也可以用任何类型(前提是该类型提供模板使用的操作)来实例化模板参数。然而,class的这种用法往往会给人误导(这里的class并不意味着只有类才能被用来替代T,事实上基本类型也可以);因此对于引入类型参数的这种用法,你应该尽量使用typename。另外还应该注意,这种用法和类的类型声明不同,也就是说,在声明(引入)类型参数的时候,不能用关键字struct代替typename。