c++ - 程序在 3 个主要 C++ 编译器中以不同方式编译。哪一个是对的?

标签 c++ language-lawyer

作为我上一个问题的一个有趣的后续行动(尽管实际上并不重要): Why does C++ allow us to surround the variable name in parentheses when declaring a variable?

我发现将括号中的声明与 injected class name 结合起来功能可能会导致关于编译器行为的令人惊讶的结果。

看看下面的程序:

#include <iostream>
struct B
{
};

struct C
{
  C (){ std::cout << "C" << '\n'; }
  C (B *) { std::cout << "C (B *)" << '\n';}
};

B *y = nullptr;
int main()
{
  C::C (y);
}
  1. 使用 g++ 4.9.2 编译时出现以下编译错误:

    main.cpp:16:10: error: cannot call constructor 'C::C' directly [-fpermissive]
    
  2. 用MSVC2013/2015编译成功,打印出C (B *)

  3. 用clang 3.5编译成功并打印出C

那么强制性的问题是哪一个是正确的? :)

(虽然我强烈倾向于 clang 版本,但 msvc 在更改类型后停止声明变量的方式从技术上讲它的 typedef 似乎有点奇怪)

最佳答案

GCC 是正确的,至少根据 C++11 查找规则。 3.4.3.1 [class.qual]/2 指定,如果嵌套名称说明符与类名相同,则它指的是构造函数而不是注入(inject)的类名。它给出了例子:

B::A ba;           // object of type A
A::A a;            // error, A::A is not a type name
struct A::A a2;    // object of type A

看起来 MSVC 将其误解为函数式转换表达式,创建了一个临时的 C,其中 y 作为构造函数参数;并且 Clang 将其误解为对类型为 C 的名为 y 的变量的声明。

关于c++ - 程序在 3 个主要 C++ 编译器中以不同方式编译。哪一个是对的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29681449/

相关文章:

c++ - vector 合成角度和方向

c++ - 如何从 PowerShell 获取 CreateTransaction 地址

c++ - 为什么 const 模板参数不是通用/转发引用

c++ - 当方法不修改成员时,在 const 实例上调用非常量方法是否是 UB?

shell - `for NAME do ...` 中的 NAME 后是否禁止使用分号?

c++ - 为什么在 C 和 C++ 中算术运算之前必须将 Short 转换为 int?

c++ - C++14 之前的模板元编程和条件运算符

c++ - 基于组件的游戏引擎中的序列化

c++ - `decltype` 在 lambda 体内的广义 lambda 捕获 - gcc vs clang