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

时间:2015-04-16 17:01:25

标签: 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

  4. 所以强制性问题是哪一个是正确的? :)

    (我强烈倾向于clang版本而且msvc方式在仅仅通过技术改变类型后停止声明变量它的typedef似乎有点奇怪)

2 个答案:

答案 0 :(得分:91)

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将它误解为函数式转换表达式,创建一个临时Cy作为构造函数参数;并且Clang将其误解为一个名为y C的变量的声明。

答案 1 :(得分:16)

G ++是正确的,因为它会出错。因为没有new运算符,无法以这种格式直接调用构造函数。虽然您的代码调用C::C,但它看起来像构造函数调用。但是,根据C ++ 11标准3.4.3.1,这不是合法的函数调用,也不是类型名称(see Mike Seymour's answer)。

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

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