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

Program being compiled differently in 3 major C++ compilers. Which one is right?

作为我之前问题的一个有趣的跟进(虽然没有太大的实际意义):

我发现将括号中的声明与 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 更改类型后似乎有点奇怪)

G++ 是正确的,因为它给出了一个错误。因为没有 new 运算符,无法以这种格式直接调用构造函数。尽管您的代码调用了 C::C,但它看起来像是构造函数调用。但是,根据C++11标准3.4.3.1,这不是合法的函数调用,也不是类型名().

Clang 是错误的,因为它甚至没有调用正确的函数。

MSVC 是合理的,但仍然不符合标准。

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

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 的变量的声明