模板
为什么要用模板
这是一个 swap 函数的例子
尽管可以使用函数重载来实现不同类型的 swap,但是每需要增加一种交换类型,就要多写一份重载函数,代码复用性低,并且容易出错
模板语法
typename 是用来定义模板参数关键字,也可以使用 class,不能使用 struct 代替
class
利用模板可以使任意参数类型调用这个 swap 函数
模板类似模具,可以在 T 位置填充你所需要的类型
参数的类型和返回值的类型都可以利用模板
模板原理
1.在编译器编译阶段,编译器根据传入的实参类型来推演生成对应类型的函数以供调用。当用 double 类型使用函数模板时,编译器通过对实参类型的推演,将 T 确定为 double 类型,然后产生一份专门处理 double 类型的代码。
2.函数模板的实例化,用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化,在这个阶段可能会产生很多份相似的代码,但是都由编译器进行处理,使用者无需处理。
显式/隐式实例化
隐式实例化
swap(a1,a2)时,编译器自动推演 a1 和 a2 的类型都是 int,判断出模板类型 T 是 int,然后对函数模板进行实例化
swap(a1,d1)时,编译器推演出 a1 是 int 类型 d1 是 double 类型,T 不能同时是两种类型,因此编译器报错
让编译器根据实参推演模板参数的实际类型称为隐式实例化
显式实例化:在函数名后的 <> 中指定模板参数的实际类型
如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。
模板参数匹配原则
同时存在模板函数和非模板函数时,若参数类型和非模板函数匹配,优先调用非模板函数,若不匹配才调用模板函数
模板函数不支持隐式类型转换,非模板函数支持隐式类型转换,优先调用在不进行隐式类型转换的情况下参数最匹配的函数(若非模板函数需要进行类型转换后参数类型才匹配,则优先调用模板函数)
类模板
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟 <>,然后将实例化的
类型放在 <> 中即可,类模板名字不是真正的类,而实例化的结果才是真正的类
例如 A 是类名,A 才是类型,实例化要使用 A
类模板实际就是一个可以在类中使用的模板类型 T
类模板中函数放在类外进行定义时,需要加模板参数列表