16.1 模板定义
16.1.1 函数模板
template <typename T>
int compare(const T &v1, const T &v2)
{
if (v1 < v2) return -1;
if (v1 > v2) return 1;
return 0;
}
实例化函数模板
- 调用一个函数模板时,编译器用推断出模板参数来为我们实例化一个特定版本的函数
模板类型参数
- 函数类型参数用 typename
非类型模板参数
- 表示一个值而非一个类型
- 被一个用户提供或编译器推断出的值替代
- 必须是常量表达式,在编译时实例化
template<unsigned N, unsigned M>
int compare(const char (&p1)[N], const char (&p2)[M])
{
return strcmp(p1, p2)
}
template <typename T> inline T min(const T& , const T& );
调用
compare("hi", "mom")
//相当于
// int compare(const char (&p1)[3], const char (&p2)[4])
inline和constexpr的函数模板
放在模板蚕食列表之后,返回类型之前
编写类型无关的代码
- 模板中函数是 const 引用,以保证用于不能拷贝的类型
- 类型无关和可以移植,小于可用模板库函数less
(v1, v2) 类避免类型依赖于小于号
模板编译
编译器在模板定义时并不生成代码
实例化(调用)时,编译器才生成代码
由于模板在实例化时生成代码,会影响编译器如何组织代码和错误何时检查
函数模板和类模板定义在头文件中
- 调用一个函数时,编译器只需要函数声明
- 模板实例化时,编译器需要函数模板或类模板成员函数的定义
- 综上所述,函数只需声明在头文件中,而模板需要声明和定义在头文件中
大多数编译器错误在实例化期间报告,编译器会在三个阶段报告错误
第一阶段是编译模板本时
- 编译器检查语法(分号或变量拼写等)
第二阶段是编译器遇到模板使用时
- 对于函数模板,检查实参数目,检查参数类型是否匹配等
- 对于类模板,检查用户是否提供正确数目的模板实参
第三阶段是模板实例化时
- 只有这个阶段才能发现类型相关的错误
- 依赖于编译器如何管理实例化,这类错误可能在连接时报告
详见:C++ Primer 第16章 模板和泛型编程