- 模板: 进行泛型编程, 让编译器根据不同的类型来生成代码(模板是一个蓝图)
- 模板的参数匹配: 优先调已经写好的, 优先调用最匹配的
- 按需实例化: 模板会根据类型去实例化, 是否使用去实例化
1.类模板与函数模板
函数模板
template<typename T>//也可以使用class
T Add(T& a, T& b)
{
return a + b;
}
类模板
template<class T>
class A
{
A(){}
};
void test2()
{
A<int> a;//使用模板必须指定类型实例化
}
2.类型模板参数与非类型模板参数
- 类型模板参数: 跟在class/typename后面的
- 非类型模板参数: 常量
3.模板的全特化与偏特化
全特化
// 原始的类模板定义
template <typename T>
class A{};
// 类模板的全特化
template <>
class A<int>{};
偏特化
template<class T1>
A<T1, int>{};
template<class T1, class T2>
A<T1, T2*>{};
4.模板不要分离编译
- 模板分离编译:编译器不知道该生成那种类型的函数或类, 不会生成汇编指令,无法实例化, 最后链接的时候找不到函数地址,报错
- 解决:
- 声明和定义放一起:头文件展开的时候, 将代码展开, 可以看到函数定义, 编译器知道生成那种类型的函数/类,可以直接找到函数地址
- 模板特化:编译器知道类型, 会生成汇编指令
分离编译
模板不分离编译:
typename的使用
- 场景: 编译器无法区分类型和变量的时候
- 模板中我们去取一个类的内嵌类型时, 它的静态成员变量和获取该类型的方式相同
- 使用typename告诉编译器xxx是一个类型, 等实例化的时候在去找
- 实例化的类不会有问题, 但是类模板会有(它不会去里面查找, 区分不出是类型还是变量)