大家好,我是苏貝,本篇博客带大家了解C++的函数模板,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️
目录
- 1.模板
- 2. 函数模板
- 1 概念
- 2 函数模板的实例化
- (A) 隐式实例化:让编译器根据实参推演模板参数的实际类型
- (B) 显式实例化:在函数名后的<>中指定模板参数的实际类型
- 3 模板参数的匹配原则
1.模板
如何实现一个通用的交换函数呢?
使用函数重载虽然可以实现,但是有一下几个不好的地方:
- 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数
- 代码的可维护性比较低,一个出错可能所有的重载均出错
那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?
如果在C++中,也能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件 (即生成具体类型的代码),那将会方便许多。巧的是前人早已将树栽好,我们只需在此乘凉。
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础
2. 函数模板
1 概念
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本
函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器
格式:
注意:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)
在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。
比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。
2 函数模板的实例化
用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。
(A) 隐式实例化:让编译器根据实参推演模板参数的实际类型
编译器根据实参a和b,推演模板参数的实际类型为int。编译器根据实参c和d,推演模板参数的实际类型为char。编译器根据实参e和f,推演模板参数的实际类型为double
问:上图的3个Swap函数调用的是同一个Swap吗?
不是。编译器会根据实参的类型来判断T是哪个类型,然后生成void Swap(int&a,int&b)这样的函数。
编译器通过推出类型,用函数模板生成对应的函数,这个过程叫做模板实例化
实际上,我们以后不用写Swap函数了,因为C++库里有交换函数,我们调用就可以了。为什么C语言库里没有交换函数,C++有?因为C++有模板
问:1和2我们都知道没有错,那3呢,报错,为什么?
因为a1的类型是int,那么推出T是int。可是d1的类型是double,又推出T是double。存在歧义,因此不能这样写,那如何写才能让a1+d1呢?
- 给一个变量强制类型转化(不用解释)
- 显式实例化
(B) 显式实例化:在函数名后的<>中指定模板参数的实际类型
3 模板参数的匹配原则
- 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
问:下图的2个Add可以同时存在吗?可以
那对于Add(a1,a2),2个Add都符合,它是调用哪一个呢?
对于Add(d1,d2),第一个Add可以,第二个Add 也可以(double变量可以强制类型转化成const int),它是调用哪一个呢?
如果我们还是想让Add(a1,a2)调用模板,可以通过显式实例化来强制调用模板
模板函数不允许自动类型转换,但普通函数可以进行自动类型转换
上面的Add函数是同类型的,下面我们来写一个通用加法函数
好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️