在尝试深入研究 this question 等案例背后的机制之后暴露了,我仍然不明白为什么下面代码中的第三行只生成警告,而第二行是错误。
int main()
{
const char* const& a = "bla"; // Valid code
const char*& a2 = "bla"; // Invalid code
char* const& a3 = "bla"; // Should be invalid but settles for a warning
return 0;
}
我知道虽然引用初始化正在将字符串文字转换为指针引用,但它不应该删除任何cv-qualifiers 对象具有,并且由于转换后的类型是 const char* const
(从字符串文字 "bla"
转换而来,即 const char[4]
) 它似乎与第二行的情况相同。唯一的区别是被删除的 const
属于 C 字符串本身而不属于指针。
在没有指定任何额外的一致性标志的情况下在 GCC 8.2 和 Clang 6.0.0 上重现。
gcc 的输出:
<source>:4:23: error: cannot bind non-const lvalue reference of type 'const char*&' to an rvalue of type 'const char*'
const char*& a2 = "Some other string literal";
^~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:5:23: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
char* const& a3 = "Yet another string literal";
为什么现在的编译器符合第一种情况而不符合第二种情况?或者,我在这里忽略了这两种情况之间的根本区别吗?
最佳答案
字符串文字是数组。 "bla"
的类型是 const char [4]
。
const char* const& a = "bla";
这是有效的,因为存在从 T []
到 T *
的转换;在这种情况下,您会得到一个 const char *
右值。这个右值可以绑定(bind)到一个引用,因为它是对 const
的引用(它使临时对象保持事件状态等)。
const char*& a2 = "bla";
无效,因为您在此处尝试将临时值绑定(bind)到非常量引用。
char* const& a3 = "bla";
这是对常量的引用,但类型错误(它是指向字符的指针,而不是指向常量字符的指针)。此转换删除了一个 const
限定符,因此它应该是无效的。出于向后兼容的原因,一些 C++ 编译器允许这样做:在 C 中,字符串文字具有非 const 限定类型(即 "bla"
将是 char [4]
),因此,将其设为硬错误会破坏大量现有代码。
即使在 C++ 中,这也曾经是合法的。在 C++11 之前,仍然允许将字符串文字分配给 char *
(不是 const char *
)变量(但已弃用)。
“双重标准”是因为从来不允许将非常量引用绑定(bind)到临时对象(C 甚至没有引用),因此不存在向后兼容性问题。该标准不区分“错误”和“警告”;对于任何给定的违反规则的情况,编译是否应该成功由编译器编写者自行决定。
关于c++ - 双重标准?为什么只对 char* const& a = "bla"发出警告?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52104917/