VS2010部分支持C ++ 11。我在VS2010 RTM中编译下面的代码。我很困惑为什么代码CLS()被分析为不同的含义。在“decltype(CLS())obj1;”行中,CLS()表示类对象实体。但是在“CLS obj2(CLS());”行中,CLS()表示一个函数指针,它返回没有参数的CLS对象。是否有预期的行为?它是在标准中描述的吗?
struct CLS
{
int mi;
};
int _tmain(int argc, _TCHAR* argv[])
{
decltype(CLS()) obj1;
obj1.mi = 10;
CLS obj2(CLS());
obj2.mi = 10; // error C2228: left of '.mi' must have class/struct/union
return 0;
}
更新12/8/2011
Per C ++ 11 7.1.6.2/1,括号中的预期字符串是表达式。编译器只需要检查字符串是否可以解析为有效表达式。如果是,则代码格式正确。所以对于代码“decltype(CLS())obj1;”,“CLS()”被视为一个有效的表达式,表示对象的定义。
decltype-specifier:
decltype ( expression )
更新1/3/2012
Potatoswatter解释了为什么“CLS obj2(CLS());”是对象定义以外的声明。
任何可能被解释为表达式或声明的东西都是声明,但它可能是不寻常的。 CLS obj2(CLS());声明一个函数,其参数类型CLS()是一个没有返回CLS的参数的函数,其返回类型是CLS。
答案 0 :(得分:2)
预期:是的
它被称为“most vexing parse”。
CLS obj2(CLS()); // function forward declaration.
CLS obj2 = CLS(); // Creates object zero initialized.
CLS obj2; // Creates object default initialized.
答案 1 :(得分:1)
在decltype
的参数中,预期表达式。将CLS()
解释为表达式的唯一方法是将其解析为CLS
类型的默认构造对象。
然而,在CLS obj2(CLS())
(BTW在C ++ 03中以相同的方式工作)中,有两个可能的解析:一个作为函数声明,一个作为对象定义。作为函数声明,外括号形成参数列表,并且期望内容通过给出类型和可选名称来指定参数(或它们的列表)。在该解析中,CLS()被解释为函数类型。
另一个有效的解析是对象的定义。对于该解析,当然在括号中必须有一个表达式(或它们的列表),将CLS()
的解释赋予CLS
类型的默认构造对象。
现在在C ++中有一条规则,如果可以将某些内容解析为声明和定义,它将被解析为声明。也就是说,在这种情况下,将使用第一种解释。
这当然引起了为什么选择第一种解释的问题,当我们在这里明确期望第二种解释时。答案是否则会破坏C兼容性(在某些情况下甚至是我们的期望)。例如,请查看以下行:
int f();
现在你会同意这声明一个函数不带参数并返回int
,对吧?但它也可以解析为int
类型的默认初始化变量的定义。由于上面提到的规则,它确实声明了一个返回int
的函数。
一条规则总是给出一个人所期望的结果,在最好的情况下会很复杂,但很可能是不可能的。
请注意,在C ++ 03中,为自动变量避免使用它的一种简单方法是使用auto
为定义添加前缀:由于函数声明永远不会以auto
开头,因此会强制执行编译器将其解释为变量定义。由于{C} 11中删除了auto
的旧含义,因此不再有效(对于非自动变量,它从未工作过。)
答案 2 :(得分:1)
正如其他人所说,这是最令人烦恼的解析。任何可能被解释为表达式或声明的东西都是声明,但它可能是不寻常的。 CLS obj2( CLS() );
声明一个函数,其参数类型CLS()
是一个没有返回CLS的参数的函数,其返回类型是CLS。
例如,
CLS obj2( CLS() ); // forward declaration
CLS obj2( CLS fun() ) { // definition
return fun(); // use unusual functional argument
}
CLS foo() { // define a function to use as unusual argument
return CLS();
}
int main() {
CLS obj2( CLS() ); // still a forward declaration, even in this context!
CLS x = obj2( foo );
}
解决方案是使用C ++ 11的统一初始化:
CLS obj2{ CLS() };
或只是
CLS obj2{};