C++ 2.0新特性——类型推导(auto、decltype)
一、类型推导
auto类型推导在大部分情况下就是模板类型推导,因此首先介绍模板类型的要点。
1、在模板类型推导中,具有引用类别的实参会被当成非引用类型来处理,即引用性会被忽略。(类型为指针或引用)
template<typename T>
void f(const T& param)
int x=10;
const int cx=x;
const int& rx=cx;
定义3个变量x,cx,rx分别作为函数f的参数,函数调用时,f(x)、f(cx)、f(rx),T都被推导为int,param都被推导为const int&。rx的引用性在推导时被忽略。
2、对万能引用(右值形参)形参进行推导时,左值实参会进行特殊处理,会区分实参是左值还是右值,而非万能引用不会。
template<typename T>
void f(T&& param) //param为万能引用
int x=10;
const int cx=x;
const int& rx=cx;
f(x):x是个左值,所以T类型为int&,param类型为int&
f(cx):cx是个左值,所以T类型为const int&,param类型为const int&
f(rx):rx是个左值,所以T类型为const int&,param类型为const int&
f(10):10是个右值,所以T类型为int,param类型为int&&
3、对按值传递(非指针和引用)的形参进行推导时,若实参类型中带有const或volatile修饰词时,会被当做不带const或volatile修饰词的类别来处理。
template<typename T>
void f(const T& param)
int x=10;
const int cx=x;
const int& rx=cx;
f(x)、f(cx)、f(rx)调用时,T和param的类型都被推导为int。
4、数组或函数类型的实参会退化为对应的指针,除非被用来初始化引用。
void someFunc(int,double);//函数,类型为void(int,double)
template<typename T>
void f1(T param);
template<typename T>
void f2(T& param);
f1(someFunc) :param被推导为函数指针,类型为void(*)(int,double)
f2(someFunc):param被推导为函数引用,类型为void(&)(int,double)
二、auto
1、在C++ 2.0引入auto时,与类型推导真正的区别在于:auto会假定用大括号括起来的初始化表达式代表一个initializer_list,但模版推导不会
auto x={1,2,3}; //x的类型为initializer_list<int>
template<typename T>
void f(T param);
f({1,2,3})调用时,编译无法通过,推导不出T的类型。
f(x)调用时,正常通过,T被推导为initializer_list。
2、在函数返回值或lambda表达式的形参中使用auto,意思是使用模板类型推导而非auto类型推导。
auto f()
{
return {1,2,3};//编译错误,无法完成类型推导
}
注:auto使用要点:
1、优先使用auto,而非显示类型声明。
*auto变量必须初始化,避免了未初始化的变量和啰嗦的变量声明。*
2、当auto推导的类型不符合要求时,使用显示类型声明强制auto推导出想要的类型(static_cast)。
*对于vector<bool> 的operator[]操作,auto的返回值并不是一个容器的引用,而是vector<bool>::reference类型的对象,做了一个bool的隐式转换*
三、decltype
1、绝大多数情况下,decltype会得出变量或表达式的类型而不作任何修改。
int i=0; //decltype(i) 是int
const int i=0; //decltype(i) 是const int
2、对于类型为T的左值表达式,除非该表达式仅有一个名字,decltype总是推导出T&。
vector<int> v;//decltype(v) 是vector<int>
//decltype(v[0])是int&
//容器的operator[] 返回类型取决于容器本身,一般都返回T&。
3、C++14支持decltype(auto),和auto一样,它会从其初始化表达式出发来推导类型,但是它的推导使用的是decltype的规则。
decltype(auto) f1()
{
int x=0;
return x;//decltype(x)为int,f1返回的是int
}
decltype(auto) f2()
{
int x=0;
return (x);//decltype((x))为int&,f1返回的是int&
}
f2返回的是一个局部变量的引用,因此会带来未定义行为的错误。
四、查看类型推导的结果
1、编译时,针对visual studio IDE,将鼠标悬停在某个变量、形参、函数等会显示对应的类别。
2、运行时,利用typeid(T).name也可以输出类型名。