![C++ 从入门到项目实践(超值版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/805/26846805/b_26846805.jpg)
4.7 推断类型auto和decltype
![](https://epubservercos.yuewen.com/F7D2C7/15289822205524706/epubprivate/OEBPS/Images/Figure-P69_10778.jpg?sign=1739255468-NLlf4zfz51G7THjkjX7tfBco7iBw4KjU-0-3dad2b4c7566babad953555fa1940ab2)
有时用户希望从表达式的类型推断出要定义的变量类型,但是不想用该表达式的值初始化变量(如果要初始化就用auto了)。为了满足这一需求,C++11新标准引入了decltype()和auto类型说明符。
1. auto
在C语言中,就有了auto关键字,它被当作是一个变量的存储类型修饰符,表示自动变量(局部变量)。它不能被单独使用,否则编译器会给出警告。在C++11标准中,添加了新的类型推导特性,使用auto定义的变量不能使用其他类型修饰符修饰,该变量的类型由编译器根据初始化数据自动确定。
(1)auto的作用。
一般来说,在把一个表达式或者函数的返回值赋给一个对象的时候,我们必须要知道这个表达式的返回类型,但是有的时候我们很难或者无法知道这个表达式或者函数的返回类型。此时,我们就可以使用auto关键字来让编译器帮助我们分析表达式或者函数所属的类型。
例如:
auto value = v1 + v2;
如果v1和v2都是int类型,那么value也是int类型,如果v1和v2是double类型,那么value就是double类型。
(2)auto和const。
auto一般会忽略顶层const(自身是const),而底层const会保存下来。
例如:
![](https://epubservercos.yuewen.com/F7D2C7/15289822205524706/epubprivate/OEBPS/Images/Figure-P69_10781.jpg?sign=1739255468-Udj8doXjQisJmGlynt60DVNvydLe6mkK-0-10f82de7d12a95ac1149be78b133fa37)
因此,如果希望推断出的类型是顶层const的,那么就需要在auto前面加上const。
例如:
const auto c = i;
(3)auto和引用。
①如果表达式是引用类型,那么auto的类型是这个引用的对象的类型。
![](https://epubservercos.yuewen.com/F7D2C7/15289822205524706/epubprivate/OEBPS/Images/Figure-P70_71864.jpg?sign=1739255468-6K1MWMoKOBfulQuncqev2lyrjpJtvEPa-0-bac6cf2023878efea7e571e6f3927fbd)
②如果要声明一个引用,就必须要加上&,如果要声明为一个指针,既可以加上“*”也可以不加“*”。
![](https://epubservercos.yuewen.com/F7D2C7/15289822205524706/epubprivate/OEBPS/Images/Figure-P70_71865.jpg?sign=1739255468-jOGLa99JdvO7FQxrK0BdIFVnvhsF2cEN-0-05d3c81314e34b46bc7e01a92d4c246f)
声明为auto的变量在编译时期就分配了内存,而不是到了运行时期,所以使用auto不再引发任何速度延迟,这也意味着使用auto的时候,这个变量不初始化会报错,因为编译器无法知道这个变量的类型。
2. decltype
(1)decltype的作用。
decltype只是为了推断出表达式的类型而不用这个表达式的值来初始化对象。
![](https://epubservercos.yuewen.com/F7D2C7/15289822205524706/epubprivate/OEBPS/Images/Figure-P70_71866.jpg?sign=1739255468-B5wsBOXRIipVBti4JcAcCNkVz0glPfCk-0-557e32ad38db31540a0377a43562bac4)
(2)decltype和const。
不论是顶层const还是底层const,decltype都会保留。
![](https://epubservercos.yuewen.com/F7D2C7/15289822205524706/epubprivate/OEBPS/Images/Figure-P70_71867.jpg?sign=1739255468-b5Xo7tp8IRW451k4BOMP1YJnu0m5l5hz-0-e5d2a2cf5fcd4033b130356c15d7d63d)
(3)decltype和引用。
①如果表达式是引用类型,那么decltype的类型也是引用。
![](https://epubservercos.yuewen.com/F7D2C7/15289822205524706/epubprivate/OEBPS/Images/Figure-P70_71868.jpg?sign=1739255468-6OsuabsgH8JuY3JPpQj8Eh7Jm3aaSgxq-0-56743dd7fcbb88ed265581fa3ea6fbcd)
②如果表达式是引用类型,但是想要得到这个引用所指向的类型,需要修改表达式:
![](https://epubservercos.yuewen.com/F7D2C7/15289822205524706/epubprivate/OEBPS/Images/Figure-P70_71869.jpg?sign=1739255468-CaBoGvlo2fAuhEWcc7qb8s5BTY35Ow0h-0-2954269c943f11e49a3cce874e030bcb)
③对指针的解引用操作返回的是引用类型。
例如:
![](https://epubservercos.yuewen.com/F7D2C7/15289822205524706/epubprivate/OEBPS/Images/Figure-P70_71870.jpg?sign=1739255468-VkX79dbriwO971exZRmz4vv8jSvkJbdY-0-607de7d2bf2695dba4fc3df13446d0ec)
④如果一个表达式的类型不是引用,但是我们需要推断出引用,那么可以加上一对括号,就变成引用类型了。
例如:
![](https://epubservercos.yuewen.com/F7D2C7/15289822205524706/epubprivate/OEBPS/Images/Figure-P70_71871.jpg?sign=1739255468-dhEfbL6ig0rzRWKfFddrNZrV4w7DB7FN-0-170b8dacd1122c7ab19e8ee3db6594d5)
decltype和auto都可以用来推断类型,但是二者有几处明显的差异:
(1)auto忽略顶层const,decltype保留顶层const。
(2)对引用操作,auto推断出原有类型,decltype推断出引用。
(3)对解引用操作,auto推断出原有类型,decltype推断出引用。
(4)auto推断时会实际执行,decltype不会执行,只做分析。
总之在使用过程中与const、引用和指针结合时需要特别小心。