目录
1. 函数模板
我们已经了解到了C++支持函数重载,我们提前写好函数名相同,参数不同的函数,编译器会根据我们输入的参数,自动调用与之对应的函数。
比如我们的交换函数:
这已经极大的方便了我们对函数的命名,唯一的不足就是得提前编写好多组函数。c++中用模板解决了这个问题。
概念
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
格式
template<typename T1, typename T2,......,typename Tn>
T1,T2……这些都是模板参数,即类型的模板
原理
函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具
在编译器编译阶段:
当x,y两个参数都是整型时,T为int;
当x,y两个参数都是字符时,T为char;
根据参数的不同,编译器会将模板推导成对应的函数进行处理;
相当于我们为编译器提供模板,将写函数的过程交给编译器,不用我们自己写了。
函数模板的实例化
用不同类型的参数使用函数模板时,称为函数模板的实例化。
隐式实例化
显式实例化
不能通过返回值去推模板参数的类型
![]()
模板参数的匹配原则
1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
2. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数
3. 如果显示实例化,那么会调用模板函数
定义和声明分离
函数模板的声明和定义分离
模板参数在声明和定义时都要出现
2. 类模板
类模板的定义格式
template<class T1, class T2, ..., class Tn> class 类模板名 { // 类内成员定义 };
相比于之前使用过的typedef,是在实现一个结构体的情况下,对数据类型进项手动更改
如果同时存在多种数据类型的结构体,typedef是不能够支持的
要存在多个类型,只能创建多个参数类型的结构体
有了模板后,是可以同时存在多个类型的类的
类的模板实例化
显式实例化
类模板一般用的是显式实例化:
声明和定义分离
类的声明和定义分离
模板参数都需出现
定义时需要指明类域
类域需要显式实例化类的参数类型
注意
模板不支持声明和定义放在两个文件中
会出现链接错误
原因
若声明和定义分开:
在编译阶段,对于模板没办法编译,因为模板参数的类型不确定,相当于模板只是一个空壳,这就导致了在生成的符号表中没有对应地址,那么链接时就会链接不上,因此会报错
解决方法一:声明和定义放一个文件中
放在一个文件中,有些地方会将文件命名为xxx.hpp
意思是头文件声明和定义放在一起
.hpp不是必要的,.h也可以
放在一起时,头文件展开后,既有声明又有定义
解决方法二:显示实例化指定
在定义的时候,显示实例化,告诉编译器T的类型即可:
![]()
总结
1. 模板主要分为函数模板和类模板
2. 模板是蓝图,使用时是参数类型的推导替换
3. 函数模板可以和函数参数的使用比较理解,函数模板也可以向函数参数一样支持全缺省和半缺省,从右往左缺省
4. 模板声明和定义要放在一个文件中,若分开,可以在定义中指定显式实例化
5. 类模板声明定义分开,定义时要指定类域,注意要指定模板参数:<类型>