为什么CLS()在C ++ 11中有不同的含义

时间:2011-12-07 04:35:30

标签: c++ visual-c++ c++11 decltype

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。

3 个答案:

答案 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{};