在阅读了@StoryTeller 的精彩回答后,为无聊的人补充了一些措辞,因为我不得不对此进行不同的思考。
所以在语法上,在这两行中我们定义了一个引用a,并且在这两行中我们都有一个materialization of a temporary pointer,它接受字符串文字的地址。 两者的唯一区别是第二个const只出现在这里:
const char* const & a = "hello";
不在这里:
const char*& a = "hello";
第二个const 表示此处被引用的对象a pointer in this case, is itself const,因为它不能使用此引用进行修改。
因此,因为这个字符串文字的类型是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 是一个类类型)[...]
两个表达式都是左值,但是我们的“cv1 T1”不是reference-compatible,我们的“cv2 T2”和“T2”不是一个类类型.
- (5.2) 否则,如果引用是对非 const 限定类型的左值引用或 volatile 限定,则程序格式错误
引用确实不是 const-qualified:我们的“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";
^ ~~~~~~~
关于成为 non-const lvalue reference 的部分正好是 ¶5.2 -- 在我们的例子中 lvalue 是一个指向 const 的指针,但它本身不是常量!与第一行不同。关于绑定到不相关类型的部分正好是¶5.1——我们的const char*不兼容与RHS是const char[6]或const char* const之后数组到指针的转换。
由于这个确切的原因,或者缺少这个原因,这可以无错误地编译:
char* const & a = "hello";
ISO C++11 除了警告之外,编译器会让这个通过(不应该,因为字符串文字是 'const char 6' 我们不应该放弃这是第一个const),因为引用现在是const,就其对象而言,指针。
另一个有趣的事情是一个rvalue 引用const char* && a(没有“第二个const”)可以绑定到从字符串文字实现的临时指针 em>,正如@StoryTeller 自己提供的那样。这是为什么?因为array to pointer conversion:的规则
左值或右值类型为“N T 数组” 或“未知边界数组
of T" 可以转换为类型为“pointer to T”的prvalue。
此处未提及 const 或其他 cv-qualification 措辞,但这仅在我们初始化右值 ref 时有效。