自动推导、函数模板、类模板
目录
- 1. 自动推导出数据类型
- 2. 函数模板
- 基本概念
- 注意事项
- 函数模板的具体化
- 函数模板分文件编写
- 函数模板高级
- 函数后置返回类型
1. 自动推导出数据类型
auto关键字
linux
系统下使用的话,要在编译时 —std==c++11
注意:
- auto声明的变量必须在定义时初始化
- 初始化的右值可以是具体的数值,也可以是表达式和函数的返回值等
- auto不能作为函数的形参类型
- auto不能直接声明数组
- auto不能定义类的非静态成员
不要滥用auto,auto在编程时真正的用途如下
- 代替冗长复杂的变量声明:例如函数指针
- 在模板中,用于声明依赖模板参数的变量
- 函数模板依赖模板参数的返回值
- 用于lambda表达式中
2. 函数模板
基本概念
注意:库函数中有swap()函数,声明函数不要重名,可以首字母大写
虽然我们可以重载多个交换函数,来满足交换不同数据类型的要求,但是这种交换的方式好像不是很高明,需要很多重复代码,而且如果有新的自定义的数据类型,还需要新的交换函数
函数模板是通用的函数描述,使用任意类型(泛型)来描述函数
编译的时候,编译器推导实参的数据类型,根据实参的数据类型和函数模板,生成该类型的函数定义
生成函数定义的过程称为实例化
函数模板实例化
函数模板在实例化的过程中,编译器会在函数名中加入一些乱七八糟的东西,再用编译后的函数名替换代码中对应的函数调用。
如果不想编译器自动类型推导,可以再函数名后面加参数类型
Swap<String>(a, b);
注意事项
-
可以为类的成员函数创建模板,但不能是虚函数和析构函数
-
使用函数模板时,必须明确数据类型,确保实参与函数模板能匹配得上
都是T类型的形参,传入的实参类型应该相同
下面这里如果在调用函数的时候不明确数据类型的话就会报错
-
使用函数模板时,推导的数据类型必须适应函数模板中的代码
意思是,函数模板可以推导任意数据类型,但是函数中的代码不一定适应数据类型
例如:我们传入函数模板中一个自定义类型,但并没有重载+操作符,而在函数模板代码中又使用了相应的+操作,编译器就会报错
-
使用函数模板时,如果是自动类型推导,不会发生隐式类型转换,如果显示指定了函数模板的数据类型,可以隐式类型转换
如果传入参数的类型与显式定义的类型不同,可以隐式类型转换成显式定义的类型
-
函数模板支持多个通用数据类型的参数
模板函数可以有多个通用参数
-
函数模板支持重载,并且可以有非通用类型的参数
函数模板的具体化
可以提供一个具体化的函数定义,当编译器找到与函数调用匹配的具体化定义时,将使用该定义,不再寻找模板
就是函数模板通用化之外的一个具体化版本
有具体化定义的时候,会优先使用具体化定义
声明和定义可以分开写
语法
// template<> void 函数模板名<Gril>(参数列表)
template<> void 函数模板名(参数列表) {
// 函数体
}
使用顺序
普通函数、函数模板、具体化的函数模板以及它们的重载版本
规则
- 具体化函数先于常规模板,普通函数优先于具体化和常规模板
- 如果希望使用函数模板,可以用空模板参数强制使用函数模板
- 如果函数模板能产生更好的匹配,将优先于非模板函数
函数模板分文件编写
函数模板一般放在头文件中
如果有函数模板具体化的情况,则不同
函数模板只是函数的描述,没有实体,创建函数模板的代码放在头文件中
函数模板的具体化有实体,编译的原理和普通函数一样,所以,声明放在头文件中,定义放在源文件中
函数模板高级
decltype 关键字
auto关键字可以一定程度上解决上面提到的tmp
的类型无法确定的问题,但如果我们需要返回tmp
的话,又该怎么办?
在C++11中,**decltype
**关键字用于查询表达式的数据类型
语法:decltype(expression) var;
decltype
分析表达式并得到它的类型,不会计算执行表达式。函数调用也是一种表达式,因此不必担心在使用decltype
的时候执行了函数。
推导规则
- 如果expression是没有用括号括起来的标识符,则var的类型与该标识符相同,包括const等限定符
- 如果expression是函数调用,则var的类型与函数的返回值相同(函数不能返回void,但是可以返回void * )
- 如果expression是左值(能取地址)(要排除第一种情况)、或者用括号括起来的标识符,则var的类型是expression的引用
decltype(func()) da; decltype(func) fa; decltype((func)) da = func; decltype(a) da; // 下面中da是引用类型,需要进行初始化 decltype((a)) da = a;
- 如果上面的条件都不满足,则var的类型与expression的类型相同
在实际应用的时候,只要记住**decltype
**可以用来推导表达式的类型,返回的是表达式类型或者表达式类型的引用即可,如果报错了就多试几次
decltype
和auto
都可以用来类型推导,但是两者是不同的
- 用auto推导的时候需要初始化,
decltype
不需要 - 下面的例子中,auto会执行函数或者表达式,
decltype
不会decltype(func()) da; auto dd = func();
左值和右值的区别
函数后置返回类型
在C++11标准中,下面的两种形式是等价的
int func(int x, double y);
// 等同于
auto func(int x, double y) -> int;
这里的auto是一个占位符,C++11中给auto新增的角色,为函数返回值占了一个位置
C++14标准中,auto可以直接推导函数的返回类型,不需要再使用decltype