目录
基础概念
函数模板(function template)
template <typename T>
int compare(const T &v1, const T &v2) {
if (v1 < v2) return -1;
if (v2 < v1) return 1;
return 0;
}
template <unsigned N, unsigned M>
int compare(const char (&p1)[N], const char (&p1)[N]) {
return strcpm(p1, p2);
}
- 类型模板参数(type parameter):类型说明符,T 为类型参数
- 非类型模板参数(nontype parameter):表示值而不是类型
- 非类型模板参数的模板实参必须是常量表达式
类模板(class template)
// Application.cc
extern template class Blob<string>; // 声明
extern template int compare(const int &, const int &); // 声明
Blob<string> sa1, sa2; // 实例化会出现在其他位置
Blob<int> a1 = {0, 1, 2, 3};
Blob<int> a2(a1); // 拷贝构造函数在本文件中实例化
int i = compare(a1[0], a2[0]); // 实例化会出现在其他位置
// templateBuild.cc
template int compare(const int &, const int &); // 定义
template class Blob<string>; // 实例化类模板的所有成员
- 编译器不能为类模板推断模板参数,因此需要在代码中提供显式模板实参(explicit template argument)列表,它们被绑定到模板参数
- 类模板的名字不是一个类型名,类模板是用来实例化类型的,而后者总是包含模板参数的
- 例外:在类模板自己的作用域中可以直接使用类模板名字(当作类型名)而不提供模板实参
- 如果类模板为其所有模板参数都提供了默认实参,并且希望使用这些默认实参,则需要在模板名之后跟一个空尖括号
- 类模板的成员函数具有和类模板相同的模板参数;默认情况下,一个类模板的成员函数只有当程序用到它时才进行实例化
- 类模板的显式实例化定义会实例化该模板类的所有成员,因此其实例化定义中所用的类型必须能用于类模板的所有成员函数
- 使用一个类模板中的类型成员,必须显式告诉编译器该名字是一个类型,如:
typename T::value_type
成员模板(member template)
- 成员模板不能是虚函数
- 类外定义类模板的成员模板时需要同时为类模板和成员模板提供模板参数列表,实例化时也同理
函数模板的声明与定义
实例分析
shared_ptr 与 unique_ptr
模板推断
模板实参推断规则,涉及尾置返回类型与类型转换、引用折叠、右值引用、万能引用、移动语义与完美转发待,待补充
重载与模板
待补充
可变参数模板(variadic template)
// Args是一个模板参数包;rest是一个函数参数包
// Args表示零个或者多个模板类型参数
// rest表示零个或多个函数参数
template <typename T, typename... Args>
void foo(const T &t, const Args& ... rest);
概念
- 可变参数模板:接受可变数目参数的模板函数或模板类
- 可变数目的参数被称为参数包
- 模板参数包
- 函数参数包
sizeof...()
运算符获取包中参数个数
包扩展
// 在print调用中对每个实参调用 debug_rep
template <typename... Args>
ostream &errorMsg(ostream &os, const Args &... rest) {
return print(os, debug_rep(rest)...); // 扩展函数参数包
}
- 扩展一个包就是将它分解为构成的元素,对每个元素应用模式,获得扩展后的列表
- 通过在模式右边放一个省略号来触发扩展操作
转发参数包
// fun 有零个或多个参数,每个参数都是一个模板参数类型的右值引用
template <typename... Args>
void fun(Args &&... args) { // 将 Args 扩展为一个右值引用的列表
// work 的实参既扩展 Args 又扩展 args
work(std::forward<Args>(args)...);
}
即组合使用可变参数模板与forward机制编写函数,实现将其实参不变地传递给其他函数
实例分析
std::bind 实现
boost::bind 实现
模板特例化
待补充
参考
《C++ Primer 第五版》