模板
模板是C++中泛型编程的基础。一个模板就是一个创建类或函数的蓝图或公式,在使用模板时,我们提供足够的信息将模板转换为特定的类或函数。这种转换发生在编译时。
函数模板
考虑这样一个功能的实现:交换两个静态类型相同的变量的值,编写一个swap函数。
void swap(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
上面的swap函数只能接受两个整型实参并交换它们,如果要实现更多类型变量的值交换,我们要写出很多个重载函数:swap(double &a, double &b) swap(char &a, char &b)……
在这里运用函数重载显然效率低下,我们希望定义一个通用的swap函数,能够接受多种类型的实参。用函数模板可以做到这一点:
template
void swap(T &t1, T &t2) {
T temp = t1;
t1 = t2;
t2 = temp;
}
如上,函数模板就是一个公式,可用来生成针对特定类型的函数版本。编译器(通常)根据函数实参的类型来为我们推断模板实参,并生成相对应类型的swap版本。这极大减少了代码编写的工作量,提高了开发效率。
非类型模板参数
上面的swap模板中,T属于模板类型参数。一般来说,我们可以将类型参数看作类型说明符,就像内置类型或类类型来使用:指定返回类型或函数的参数类型,以及函数体内的变量声明或类型转换等。
除了定义类型参数,还可以在模板中定义非类型参数(nontype parameter)。一个非类型参数表示一个值而非一个类型。我们通过一个特定的类型名而非关键字class或typename来指定非类型参数。
例如,编写一个处理字符串字面常量的大小比较函数。
template
int compare(const char (&p1)[N], const char (&p2)[M]) {
return strcmp(p1, p2);
}
当我们调用compare时:compare("hi", "mom") 编译器会使用字面常量的大小来代替N和M,从而实例化模板。因此编译器会实例化出如下版本:
int compare(const char (&p1)[3], const char (&p2)[4])//在字面值常量末尾自动添加空字符'