Last Updated on 2022年9月28日
数组类型和函数类型
尽管在大部分场合中,数组类型和函数类型都被转换成某种指针使用,然而它们确实是某种类型.
这一点在类型推导中很重要,因为类型推导可以推导出数组类型/函数类型
- 数组类型逻辑上类似于
std::array
,由T
和N
两个属性决定唯一的数组类型,称T[N]
型对象为数组类型,其中N必须为constexpr
,称T array[N]
为T[N]
的一个实例.T
和N
必须都相同才是同一个array类型.
- 数组类型可以被隐式decay为指向数组首元素的指针.
- 转换为指针后,长度信息就丢失了.
- 在
T[N]
做函数形参时,编译器一定会将形参转换为指针,从而可以接受长度不同的数组,长度信息也随之丢失.
- 数组的长度信息未丢失时,编译器及用户是可以获取到这些长度信息的.
sizeof(array)/sizeof(array[0])
就是元素数量. - 可以使用引用型形参来保留数组的长度信息,对于模板,还可以使用自动推断.
- 自动推断:
template<class T>fun(T &);
或template<class T,int N>fun(T (&array)[N])
- 手动声明:
fun(int (&array)[100])
- 自动推断:
- 由于数组是一个类型,因此尽管对于
T array[N]
,array
和&array
的物理地址相同,但二者的意义是不同的,前者是一个T[N]
数组,可以隐式decay成一个T*
,而后者则是一个指向T[N]
的指针. retType (arg1Type,arg2Type...)
这样的类型称为函数类型.称retType fun(arg1Type,...)
中的fun
为该类型的实例,后文中使用using FT= retType (arg1Type,arg2Type,...)
来表示函数类型.- 对于函数
fun
,fun
和&fun
意义上是一致的,前者是一个FT
型实例,会隐式decay成一个FT *
,而后者就是指向FT
的指针
decltype和auto
类型推断相关的内容主要有decltype和auto,其中,auto是通过初始化进行推导,其行为和模板类型推断完全一致
decltype用于获得对象的精确类型,涉及的细节较多参考Cppreference,一般来说,最好搭配std::decay
使用,保证得到的类型是一个简单类型.
decltype
- 当输入是一个对象时,推断出的类型一定和输入对象完全相同.
- 当输入是一个左值表达式时,推断的结果是一个引用,该引用可以精确绑定到输入表达式.
- 注意:decltype用于推断数组或函数时,不会推导出指针.对于数组
decltype(array) ar;
会创建一个新的数组,decltype(fun) * fp;
则创建了一个函数指针.- 尽管
decltype(fun) f2;
逻辑上是创建一个"函数对象",但是由于C++中没有办法对这样创建的函数进行初始化,所以这种场景仅相当于声明函数, 也就是说: 声明了一个名为f2
的函数,该函数的类型与fun
一致.
- 尽管
decltype()
自身就是可以作为类型使用,例如std::decay<decltype(*iter)>::type
是常见的用法,它可以保证推导出一个简单类型(不含const,不含引用).
auto
auto和函数模板实参推断的行为完全一致,仅语法上形式不同,为了便于说明,本节仅用模板实参推断进行描述.
- 当进行函数调用时,可以通过函数的实参来对模板实参进行推断,从而获得
T
的真实类型.T && arg
时,推断出的RealT
一定包含引用, 且可能包含const, 会进一步按引用折叠来决定最终的类型.- 一般没有
const T && arg
这样的用法 T arg
型形参推断的结果不含const, 推断出的数组/函数会退化为指针T & arg
,推断结果可以包含const,推断出的数组/函数不会退化成指针const T &
的推断结果肯定不含const
// 注意:直接参与推导的部分必须是`T&&`形式的才能触发引用折叠推导, 这里的`MyType<T>&& arg`并不是简单的`T&&`型, 直接参与推导的是`MyType<T>`.
// 实际的效果是: 1. 调用函数时,实参必须是MyType<T>类型的右值. 2. MyType<T> 中的T实际不需要推导,它一定和实参一致.
template<class T>
void foo2(MyType<T>&& arg){
}
- 完美转发:将
T &&
和std::forward
配合即可, 此时推导出的T
会和实参的类型完全一致,std::forward<T>(arg)
的效果和cast是类似的.
template<class T>
void Relay(T && arg){
bar(std::forward<T>(arg));
}
- 一般性举例
{ int raw; int any int &ref=raw; auto b=ref;// auto为int; auto &b1=ref;// auto为int; decltype(ref) c=any;// decltype(ref) 为 int& } { const int raw=0; const int any=0; const int &ref=raw; auto b=ref;//auto为int auto &b1=ref;//auto为const int delcytple(ref) c=any;//delcytple(ref)为 const int& } int array[10] auto p=array;//auto为 int* auto &p=array;//auto为 int[10] & decltype(array) a2;//等价为 int a2[10];