0. 什么是模板
C++中的模板(template),是泛型编程的基础。一个模板就是一个蓝图,用来创建类或函数的蓝图。
模板主要分为两类:
- 函数模板(function template)
- 类模板(class template)
本文主要介绍函数模板(function template)。
关于模板的全部内容,参考【C++深陷】之“模板”。
1. 定义函数模板
// 例1
template <typename T>
int compare(const T &v1, const T &v2) {
if (v1 < v2) return 1;
if (v2 < v1) return -1;
return 0;
}
// 例2
template <unsigned N, unsigned M>
int cmpchararr(const char (&p1)[N], const char (&p2)[M]) {
return strcmp(p1, p2);
}
接下来认识名词。
template
关键字是必须的。
<>
中的内容,称为模板参数列表(template parameter list),包含多个由逗号,
分隔开的模板参数(template parameter) ,类比函数的参数列表,注意不能为空。
模板参数分为两类:
- 类型参数(type parameter):指定模板中的类型
- 非类型参数(nontype parameter):指定模板中的定值
2. 类型参数
类型参数可以看作不固定形态的类型说明符(4. 定义变量),如例1。我们可以和以往使用函数一样使用函数模板:
cout << compare(1, 9) << endl; // T是int类型
上面的调用会在程序编译阶段进行模板的实例化(instantiate) ,告诉编译器我的T
是类型int
,产生一个形如下面的实例(instantiation):
int compare(const int &v1, const int &v2);
这个感觉类似于函数的形参和实参,当我们在使用模板时,会传递给模板函数模板实参(template argument),即上例中编译器根据1和9推断出的T
为int
。
3. 非类型参数
非类型参数是一个值,需要用具体的类型来指定,如例2。当我们调用时:
cmpchararr("hi", "template");
N
和M
分别被实例化为3和9,都是我们指定的unsigned int
类型:
int cmpchararr(const char (&p1)[3], const char (&p2)[9]);
// 字符数组末尾有一个'\0'
此时我们发现,可以传递数组给函数,且无需多指定数组的维度。
用来实例化非类型整型参数的模板实参必须是常量表达式,可以是以下类型:
- 整型(没有浮点型)
- 函数指针
- 指向具有静态性的对象的指针
- 绑定到具有静态性的对象的左值引用
4. 模板实参推断
此时我们发现,上述所有示例,我们并没有在代码中指定T
是什么类型。这是因为当我们调用compare(1, 9)
时,编译器进行了模板实参推断(template argument deduction),它帮我们推断出T
是int
。这种指定模板参数的方式称为隐式模板实参(implicit template argument),在类模板中,我们会接触到显示模板实参(explicit template argument)。
5. inline 与 constexpr
函数模板可以声明为inline或constexpr,放在template声明之后。
6. 名词索引
template
关键字- 模板参数列表(template parameter list)
- 模板参数(template parameter)
- 类型参数(type parameter)
- 非类型参数(nontype parameter)
- 实例化(instantiate)
- 实例(instantiation)
- 模板实参(template argument)
- 模板实参推断(template argument deduction)
- 隐式模板实参(implicit template argument)
- 显示模板实参(explicit template argument)