概述
函数模板
使用泛型
来定义函数,其中的泛型可用具体类型替换- 函数模板并不创建任何函数,而只是告诉编译器如何定义函数
模板函数
的参数类型并非只能是模板类型,可以是非模板数据类型模板函数
可以被重载(),即函数名相同,函数特征标
不同
template <typename 泛型名称>
返回值类型 函数名(参数类型)
{
...
}
实例化与具体化
具体化
和实例化
是不同的:
(1)实例化是指编译器使用模板函数
为特定类型
生成函数定义
(2)具体化是指缩小模板函数
中模板参数
的范围,如使用具体类型替换模板参数类型
(3)具体化后仍然不是函数定义,实例化后一定是函数定义- 实例化:
(1)隐式实例化:
函数调用时由编译器创建特定的实例
(2)显式实例化:
直接命令编译器创建特定的实例- 显式实例化声明时,只有关键字
template
而不包含<>
- 显示实例化不能有函数定义,而具体化必须有函数定义
- 试图在同一个文件将同一种类型的
显式实例化
放在显式具体化
前面将出错
重载解析
重载解析:
对于函数、函数模板及其重载版本,需要一个良好的策略,来决定使用哪个定义- 对于给定的函数名,可以有
非模板函数
、模板函数
和显式具体化模板函数
以及它们的重载版本
- 一般而言,
具体化
优先于常规模板
,而非模板函数
优先于具体化
和常规模板
解析过程:
(1)创建候选函数列表:
包含与调用函数的名称相同的函数与模板函数
(2)使用候选函数类别创建可行函数列表:
参数数目正确的函数,为此有一个隐式转换序列,其中包括实参类型与相应的形参完全匹配的情况
(3)确定是否有最佳的可行函数:
如果有,则使用它,否则该函数调用出错重载解析
只考虑函数特征标,而不考虑函数返回类型- 编译器在确定哪个函数是最佳的需要查看为使函数调用参数与可行的候选函数的参数匹配所需要进行的转换,从最佳到最差的顺序如下:
(1)完全匹配
,但常规函数优先于模板
(2)提升转换:
eg:
char
转为int
(3)标准转换:
int
转为char
,long
转为double
(4)用户自定义的转换:
,如类声明中定义的转换
- 最佳匹配和完全匹配:
- 进行完全匹配时,C++允许某些“无关紧要的转换”
对于指针与引用
,指向非const
数据的指针和引用优先与非const
指针和引用参数匹配- 同为
完全匹配
,非模板函数
优先于模板函数(包括显式具体化)
- 若两个
完全匹配的函数
都是模板函数,则较为具体的模板函数优先
关键字decltype
- 使用关键字
decltype
:
语法:
decltype(expression) var;
- 类型确定:
- 若
expression
是一个没有用括号括起的标识符,则var
的类型与该标识符类型相同- 若
expression
是一个函数调用,则var
的类型与函数返回值的类型相同(并不会调用函数,而是通过查看函数原型确定)- 若
expression
是一个左值,且用()
括起时,则var
为指向其类型的引用- 若前面条件都不满足,则
var
的类型与expression
的类型相同
typedef
与decltype
:
- 若需要多次声明,可结合
typedef
与decltype
- 后置返回类型与
decltype
:
后置返回类型:
将返回类型移到了参数声明的后面auto
为一个占位符,表示后置返回类型提供的类型