(2)左右值初探与auto类型说明符
这篇文章的起因是下面这两段代码,出自《C++ primer 5th》中文版P62页:
auto &h =42;//错误,不能为非常量引用绑定字面值
const auto &j =42;//正确,可以为常量引用绑定字面值
一开始看到auto时,我认为不存在错误的auto语句,因为auto就是根据右值类型来匹配一个适当的类型给左值~
结果这里居然错了!我很诧异,仔细看了看是const引起的,那么问题来了,为什么必须要加const才能识别42是一个const int&?
百度了一下,找到一个知乎的回答:
https://www.zhihu.com/question/36052573?utm_source=qq&utm_medium=social
感觉里面的问题描述和我想的一样,回答里说的却没有我想要的答案:为什么必须是const引用才能绑定字面值?有什么原因么?
我又去stack overflow提问,因为英文太差,问题描述不能很好的写出来:
https://stackoverflow.com/questions/46461946/cannot-bind-a-plain-reference-to-a-literal/46464445#46464445
误打误撞,又纠正了我一些概念上的问题,接下来我来总结一下。有些东西后面学到了才用到,我会点到即止,留下问题的可能答案以后看。
首先是文章开头那两段代码,为什么第一段错第二段对?
这里要明确几个概念:
(1)编译器先判断右值的类型,再决定左值的类型,而不是先定义左值的类型再进行绑定的操作......
(2)const 引用可以绑定字面值,而且auto引用和指针变量在绑定或赋值操作时是保留底层const属性的,而一般情况下是忽略顶层const属性,才需要人为添加const来声明顶层const属性。
(1、2改动自楼上第一个知乎答案里的问题描述)
(3)auto不能推断const,其默认只保留顶层const(这里和2有雷同,但为了完整我还是写出来了);非常量左值引用不能绑定到纯右值上。
(3是上面stack overflow中问题的回答理解,截图见下面)
这里补几个专业词汇:
pure rvalue=prvalue=纯右值 lvalue=left value=左值 rvalue=right value=右值
这三者有什么区别的?我觉得这个问题里很多回答说的很好:
https://www.zhihu.com/question/39846131/answer/85277628
简单的总结,就是有地址的就是左值,没有就是右值,至于里面提到的纯右值、右值引用概念,现在没必要深究,先放着,以后学到了再说,可以参考的文章有:
http://blog.csdn.net/ylbs110/article/details/51106164(我也不知道这篇文章质量如何,以后用到再说)
最后,再重新强调几个东西,基本数据类型、限定符、声明符列表是不一样的东西!int、double等是基本数据类型,const是限定符,声明符列表包括名字和修饰符,名字就是对象名字,修饰符有*和&(目前学到的只有这两个),而auto是类型说明符,换句话说,他只能表示或者替代基本数据类型!这也是为什么const我们要自己视情况加,auto并不能帮我们确定的原因————auto是一个类型说明符,其只能代替基本类型的位置,不能代替限定符const和类型修饰符&、*之流。
好了,准备工作都弄好了,现在可以试着解释上面的问题了。
首先是第一段代码。
auto &h =42;//错误,不能为非常量引用绑定字面值
这段代码执行流程是这样的:
编译器会先判断右值的类型:“42”是一个int的字面值。
字面值里只有char类才有地址,其余都是右值!(左值是等号两边都可以放的,右值只能放等号右边,有地址的才是左值,否则是右值,姑且这样认为先),所以,这里的42是一个int型的右值。
编译器判断出这是一个int后,auto就等价于int了(注意,没有*没有&没有const,就只是等价于一个基础数据类型)
也就是说上面那段等价于:
Int &h =42;
这是一个绑定int型的引用,而规定是引用不能绑定一个纯右值,所以这里错了————我也不知道为什么,这里似乎牵扯到生命周期、纯右值,没学到,以后再说,可以参考的文章有:
https://stackoverflow.com/questions/39718268/why-do-const-references-extend-the-lifetime-of-rvalues
明白了这段代码哪里错,就能理解文章开头的第二段代码为什么对了——先死记吧,以后再说。
至此这个疑问就告一段落了,最后说一说这次查资料中自己纠正的一个错误概念:
等号两边的类型是一样的否则怎么能赋值呢。
明白上面这句话是错的,源自于上面我在stack overflow中提问的一个回答:
最后,我想强调一下auto定义的变量必须有初始值,而这正是有了他还要再有一个decltype类型指示符的原因。
有了auto是不是不需要显示声明类型了?————见:https://www.zhihu.com/question/35517805/answer/63304992
这个解释没看懂,以后再看