[Cpp基础] [07] 复杂类型和类型推断

Last Updated on 2020年4月14日

数组类型和函数类型

尽管在大部分场合中,数组类型和函数类型都被转换成某种指针使用,然而它们确实是某种类型.
这一点在类型推导中很重要,因为类型推导可以推导出数组类型/函数类型

  • T[N]型对象为数组类型,其中N必须为constexpr,称T array[N]中的arrayT[N]型的一个实例.
    • N是数组的一个属性,当N不同时,是不同类型的数组.
  • 数组类型变量可以被隐式转换为指向数组首元素的指针.
    • 转换为指针后,长度信息就丢失了.
    • 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])
  • &array类型是指向数组的指针,为T[N] *型.
  • retType (arg1Type,arg2Type...)这样的类型称为函数类型.称retType fun(arg1Type,...)中的fun为该类型的实例,后文中使用using FT= retType (arg1Type,arg2Type,...)来表示函数类型.
  • 函数对象FT fun在使用中可能会隐式的退化为指针类型FT *,例如FT * p = foo; FT * p2 = &foo

decltype和auto

类型推断相关的内容主要有decltype和auto,其中,auto是通过初始化进行推导,其行为和模板类型推断完全一致

decltype用于获得对象的精确类型.为了简化用法,仅应当对左值或左值表达式使用decltype,因为对右值的推断可能产生分歧参考Cppreference

decltype

  • 当输入是一个对象时,推断出的类型一定和输入对象完全相同.
  • 当输入是一个左值表达式时,推断的结果是一个引用,该引用可以精确绑定到输入表达式.
  • 注意:decltype用于推断数组或函数时,不会推导出指针.对于数组dectype<array> ar;会创建一个新的数组,对于函数decltype<fun> f2;会创建一个无法使用的未初始化的函数,decltype<fun> * fp;则创建了一个函数指针
  • decltype推断的结果是一个编译期可用的类型,可以用<type_traits>中的类型操作算法处理.例如remove_reference<decltype(*iter)>::type就能推断出*iter对应的类型,而不是引用

auto

auto和函数模板实参推断的行为完全一致,仅语法上形式不同,为了便于说明,本节仅用模板实参推断进行描述.

  • 模板实参推断就是通过编译器推断T的具体内容.除T &&外,推断出的RealT肯定不包含引用.
  • T ,推断结果不含const
    • 推断出的数组/函数会退化为指针
  • T &,推断结果可以包含const
    • const T &的推断结果肯定不含const
    • 推断出的数组/函数不会退化为指针
  • T &&时,推断的结果必然包含引用,且可以包含const.
    • 用左值或左值表达式进行初始化时推断结果将为左值引用.
    • 用右值初始化时,推导结果为右值引用.
// 注意:直接参与推导的部分必须是`T&&`形式的
// 这里的foo2并不是简单的`T&&`型, 这里直接参与推导的是`T`,是按照T的规则来推导的
template<class T>
 void foo2(MyType<T>&& arg){

}
  • 完美转发:将T &&std::forward配合即可
// 例如,对于`Relay(MyType())`,那么推导出的T就是`MyType &&`,此时`std::forward<T>(arg)`效果就相当于`static_cast<MyType &&>(arg)`
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];