文章目录
- [1. 模版参数](#1. 模版参数)
- [2. 模版的特化](#2. 模版的特化)
-
- [2.1 概念](#2.1 概念)
- [2.2 函数模版特化](#2.2 函数模版特化)
- [2.3 类模板特化](#2.3 类模板特化)
-
- [2.3.1 全特化](#2.3.1 全特化)
- [2.3.2 偏特化](#2.3.2 偏特化)
- [3. 模版的分离和编译](#3. 模版的分离和编译)
- [4. 总结](#4. 总结)
1. 模版参数
- 模版参数分为类型形参和非类型参数
- 之前我们写过的大量代码,都是用模版定义类的参数类型,跟在class和typename后面这样的参数类型就是类型形参

- 非类型形参就是指用一个常量作为类(函数)的一个参数,在类(函数)模版中可以当做常量来使用

- 注意
- 模版的非类型参数是不允许传浮点数、类对象、字符串的
- 另外模版的非类型参数必须在编译时就能确定结果,否则会报错

2. 模版的特化
2.1 概念
- 通常情况下,使用模版可以实现一些与类型无关的代码,但对于一些特殊类型可能达不到预期的结果

- 这时候就需要借助模版特化来解决这种特殊情况
- 模版特化又分为函数模版特化和类模版特化
2.2 函数模版特化
- 函数模版特化的步骤:
- 必须要有一个基础模版
- 关键字template后面+一对尖括号<>
- 函数名后跟跟一对尖括号,尖括号中要指定需要特化的类型
- 函数形参:必须要和函数模版的基础参数类型匹配,否则可能会奇怪报错

- 当然面对上述情况,还有另一种方法,那就是直接给出对应的函数

- 总结
- 对于函数模版中特殊情况,通常采用的就是直接给出对应的函数,编译器根据匹配原则会直接调用该函数,并且函数的代码可读性高,书写也方便,对于函数模版的特化,了解下即可
2.3 类模板特化
2.3.1 全特化
- 全特化就是将类模板中的所有参数都确定化

2.3.2 偏特化
- 偏特化是具有一定限制条件设定的特化版本

- 模版补充

- 模版参数类型在使用时,需要用typename告诉编译器,vector::const_iterator 这是一个类型,否则编译器就会报错,它识别时还要依靠T类型
- 一个很好的解决办法就是:使用auto,它会自动识别类型,就可以很好的避免报错

- 泛型编程
- 如果不想使用vector容器,而是想用list容器呢

3. 模版的分离和编译
- 一个程序(或项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有的目标文件链接起来形成单一的可执行文件的过程称为分离编译模式
- C/C++程序要执行,一般分为4个步骤:预处理、编译、汇编、链接
- 为了更好的理解代码执行的过程,接下来将详细介绍程序运行的4个过程

- 补充:后缀为.o的文件(Linux系统下),win系统是.obj文件
- 接下来看看模版函数的分离编译过程会出现哪些问题

- 在main.obj文件调用Add和Add时,编译器在链接时才会去找函数地址,但是这两个函数都没有实例化生成具体代码。因此就会出现链接错误
- 对于模版函数,通常采取的做法是,将函数的声明和定义放在同一个文件,另外库里面也是这样做的,这样在编译阶段,编译器直接就能得到模版函数的定义,就可以生成对应的代码,从而避免链接错误

- 当然在头文件中直接给模版函数的定义也可以
4. 总结
- 模版复用了代码,节省了资源,可以更快的迭代开发,主要是方便了我们,机器还要做大量的工作
- 增加了代码的灵活性
- 同时模版也会出现代码膨胀的问题,一个模版可能实例化出多个不同类型的对象,导致编译时间过长,这也是不可避免的问题
- 如果出现模版编译错误,报错信息会很凌乱,不易精准定位错误