我正在从一本书中阅读代码片段,并找到了它:
const char* const & a = "hello"; //can compile
const char*& a = "hello"; //cannot
我所知道的是,初始化引用时,指向指针转换的数组不会发生。
const char* const &
,对const pointer
的引用,指针指向const char
。
const char*&
,对pointer
的引用,指针指向
const char
。
那么为什么要添加一个额外的const
来指示指针是const
呢?
答案 0 :(得分:37)
它本质上是遵循这个公式
T const & a = something_convertible_to_T;
其中T是const char*
。在第一种情况下,可以实现一个临时指针,为其分配文字的地址,然后将其自身绑定到该引用。在第二种情况下,由于左值引用不是const,因此不会发生。另一个例子更多
const char* && a = "hello"; // rvalue ref makes a no into a yes.
现在,临时指针已绑定到右值引用。
答案 1 :(得分:8)
在阅读了@StoryTeller的出色回答之后,一些无聊的措辞也变得无聊了,因为我不得不对此进行另外的思考。
因此,在语法上,我们两行都定义了 reference a
,并且在这两行中,我们都将有一个materialization of a temporary pointer,它使用 string文字的地址< / em>。 两者之间的唯一区别是第二个const
仅出现在此处:
const char* const & a = "hello";
而不是这里:
const char*& a = "hello";
第二个const
表示此处引用的对象 a pointer in this case, is itself const,因为无法使用此引用对其进行修改。
因此,因为此字符串文字的 type 是const char[6]
(例如,不是const char *
),所以我们的lvalue
第二行中对类型const char*
的引用不能绑定到它-但第一行中对类型const char* const
的引用可以。为什么?由于rules of reference initialization:
(5)对类型“ cv1 T1”的引用由类型“ cv2 T2”的表达式初始化,如下所示:
(5.1)如果引用是左值引用和初始值设定项表达式
- (5.1.1)是左值(但不是位字段),并且“ cv1 T1”与“ cv2 T2”具有参考兼容性,[...]
- (5.1.2)具有类类型(即T2是类类型)[...]
两个表达式都是 lvalue ,但是我们的“ cv1 T1”不是reference-compatible ,而我们的“ cv2 T2”和“ T2”不是类类型。
- (5.2)否则,如果引用是对非const限定类型或volatile限定类型的左值引用,则程序格式错误
引用确实是不是 const限定的:我们的“ T1”是const char*
,它是const 的指针,而不是 const指针。这里的实际类型是指针类型,所以很重要。
牢记第二行的Clang错误告诉我们了这一点:
error: non-const lvalue reference to type 'const char *' cannot bind to a value of unrelated type 'const char [6]'
const char*& a = "hello";
^ ~~~~~~~
关于成为非常量左值引用的部分正好是5.2 –在我们的例子中,左值是指向const
的指针不是const!不像第一行。完全绑定到不相关类型的部分是¶5.1–我们的const char*
与不兼容且RHS为const char[6]
或{ {em}指向指针数组转换后。
由于这个确切原因,或者没有这个原因,可以编译无错误的内容:
const char* const
除了 ISO C ++ 11 警告外,编译器允许一次通过(但不应该这样,因为字符串文字是'const char 6',我们不应该这样做)请先删除第一个char* const & a = "hello";
),因为关于它的对象(指针)的引用现在是const
。
另一个有趣的事情是,一个const
引用rvalue
(没有“第二个const char* && a
”)可以绑定到从< em>字符串文字,就像@StoryTeller提供的一样。这是为什么?由于array to pointer conversion:
类型为“ NT数组”的左值或右值 或“未知范围的数组” 的T“ 可以转换为”指向T的指针“的 prvalue 。
这里没有提及const
或其他 cv-qualification 措词,但这仅在我们初始化右值引用时有效。