c++ - 双重标准?为什么只对 char* const& a = "bla"发出警告?

标签 c++ compiler-errors language-lawyer compiler-warnings

在尝试深入研究 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/

相关文章:

c - 在 Visual Studio 2010 中编译 C WinSock 代码时出现结构重复错误

c++ - 指向不同类型的指针可以有不同的二进制表示吗?

css - 可见性 : hidden and visibility: collapse in flexbox? 有什么区别

c++ - ADL 与范围解析——更喜欢哪个?

c++ - Visual Studios 2010 中的 libx264 - Release Build 中的内存错误

c++ - 使用类递归创建链表,C++

c++ - 用原语 union 公共(public)初始序列

c++ - 如何处理SIGINT?

c++ - 尝试制作类模板时未命名类型错误

c - 如何在 switch 与 integer using 中使用枚举