作为我之前提出的一个有趣的后续行动(虽然不具有重大的实际意义): 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);
}
使用g ++ 4.9.2进行编译会给出以下编译错误:
main.cpp:16:10: error: cannot call constructor 'C::C' directly [-fpermissive]
它与MSVC2013 / 2015成功编译并打印C (B *)
它与clang 3.5成功编译并打印C
所以强制性问题是哪一个是正确的? :)
(我强烈倾向于clang版本而且msvc方式在仅仅通过技术改变类型后停止声明变量它的typedef似乎有点奇怪)
答案 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将它误解为函数式转换表达式,创建一个临时C
,y
作为构造函数参数;并且Clang将其误解为一个名为y
C
的变量的声明。
答案 1 :(得分:16)
G ++是正确的,因为它会出错。因为没有new
运算符,无法以这种格式直接调用构造函数。虽然您的代码调用C::C
,但它看起来像构造函数调用。但是,根据C ++ 11标准3.4.3.1,这不是合法的函数调用,也不是类型名称(see Mike Seymour's answer)。
Clang错误,因为它甚至没有调用正确的函数。
MSVC是合理的,但它仍然不符合标准。