Pre*_*nik 116 c++ language-lawyer
作为我前一个问题的一个有趣的后续(虽然不具有重大的实际意义): 为什么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);
}
Run Code Online (Sandbox Code Playgroud)
用g ++ 4.9.2编译给出了以下编译错误:
main.cpp:16:10: error: cannot call constructor 'C::C' directly [-fpermissive]
Run Code Online (Sandbox Code Playgroud)它与MSVC2013/2015成功编译并打印 C (B *)
它与clang 3.5成功编译并打印 C
因此,强制性问题是哪一个是正确的?:)
(我强烈倾向于clang版本和msvc方式停止声明变量后,只是在技术上改变类型,其typedef似乎有点奇怪)
Mik*_*our 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
Run Code Online (Sandbox Code Playgroud)
看起来MSVC将它误解为函数式转换表达式,创建一个临时的C
with y
作为构造函数参数; 而Clang将它误解为一个名为y
type 的变量的声明C
.
Kun*_*ing 16
G ++是正确的,因为它给出了一个错误.因为在没有new
运算符的情况下无法以这种格式直接调用构造函数.虽然您的代码调用C::C
,但它看起来像构造函数调用.但是,根据C++ 11标准3.4.3.1,这不是合法的函数调用,也不是类型名称(参见Mike Seymour的回答).
Clang是错误的,因为它甚至没有调用正确的函数.
MSVC是合理的,但它仍然不符合标准.