第
详解C++17中的decltype类型推导
目录引子标准演进C++11C++14放宽对不完整类型的限制decltype(auto)C++17总结
引子
在编程过程中,有时我们需要根据表达式的类型来声明变量,尤其是在涉及模板编程和泛型编程时,经常会遇到这样的问题:(1)、有些泛型类型由模板参数决定,但是却很难或根本无法表示;(2)、需要在编译时确定变量的类型。
除此之外,我们知道auto在自动类型推导时,会忽略类型的修饰符。如此会导致auto推导的类型会与原表达式的类型存在不一致问题。
为了更好的解决这些问题,从C++11标准开始,C++引入了decltype关键字,其作用是让编译器在编译时识别表达式的类型,方便的的进行类型推导,同时也解决泛型编程和模板编程中变量类型表示的问题。
标准演进
decltype是declaretype的缩写。C++11标准引入了decltype的核心功能和推导规则,C++11以后的各标准都本别对C++11自定的规则进行扩容和改进。具体演进过程如下所示:
C++11:引入关键字,并引入decltype的核心功能,用于根据表达式推导出变量的类型;C++14:引入两个重要改进引入decltype(auto)语法,此语法可用于函数返回值类型的推导。基于decltype(auto)语法,函数的返回值类型可通过函数体的返回值表达式来推导,从而简化函数返回值类型的声明。放宽了对不完整类型的限制:在C++11中,如果decltype推导的表达式结果是一个不完整类型,那么会导致编译错误。而在C++14中,对不完整类型的处理更加宽松,允许使用decltype推导不完整类型的变量。C++17:decltype(atuo)支持非类型模板形参占位符。
C++11
引入关键字,并引入decltype的核心功能,用于根据表达式推导出变量的类型;当使用decltype(e)推导表达式e(类型为T)的类型时,C++11标准定义decltype的推导规则如下:
如果是一个未加括号的标识符表达式或类成员访问,那么decltype(e)的推导结果为e类型T;假如不存在这样的实体或e是一组重载函数,那么decltype(e)无法推导。而且推导过程const/volatile限定符会被忽略;如果e是一个可调用对象,那么decltype(e)推导为可调用对象返回值的类型;如果e是一个左值,decltype(e)推导为T。const/volatile限定符不能忽略;如果e是一个将亡值,decltype(e)推导为T,const/volatile限定符不可忽略;如decltype(e)无法命中上述4情况,decltype(e)将会推导为e的类型T;
为了让大家更形象的理解这5条规则,下面我们通过一些示例来说明这五条推导规则。
示例1:未加括号标识符表达式
intx=42;
decltype(x)y;//推导结果是int,满足第1条规则
示例2:加括号的标识符表达式
intx=42;
decltype((x))y=x;//推导结果是int,满足第三条规则
示例3:未加括号的类成员访问
structMyClass{
intmember;
constMyClassobj;
decltype(obj.member)result=obj.member;//推导结果是int,忽略const/volatile限定符,满足第1条规则
示例4:加括号的类成员访问
structMyClass{
intmember;
constMyClassobj;
decltype((bj.member))result=obj.member;//推导结果是constint,const/volatile限定符不能忽略,满足第3条规则
示例5:可调用对象表达式
intadd(inta,intb)
returna+b;
decltype(add(1,2))result;//推导结果是int,满足第2条规则
示例6:将亡值
intx=42;
decltype(std::move(x))result=std::move(x);//推导结果为int,std::move(x)为将亡值
示例7:右值表达式
intx=42;
decltype(x+1)result;//推导结果是int(右值表达式x+1的类型是int)
示例8:右值引用变量