程序在3个主要的 C + + 编译器中被不同的编译。哪一个是正确的?

作为对我上一个问题的一个有趣的补充(虽然不是很重要的实际问题) : 为什么 C + + 允许我们在声明变量时把变量名放在括号中?

我发现将括号中的声明与 注入的类名特性相结合可能会导致关于编译器行为的惊人结果。

请看以下节目:

#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. Compiling with g++ 4.9.2 gives me the following compilation error:

    main.cpp:16:10: error: cannot call constructor 'C::C' directly [-fpermissive]
    
  2. It compiles successfully with MSVC2013/2015 and prints C (B *)

  3. It compiles successfully with clang 3.5 and prints C

So obligatory question is which one is right? :)

(I strongly swayed towards clang version though and msvc way to stop declaring variable after just changing type with technically its typedef seems kind of weird)

5005 次浏览

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

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

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

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

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