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

为什么CLS()在C++11中有不同的含义,c++,visual-c++,c++11,decltype,C++,Visual C++,C++11,Decltype,VS2010部分支持C++11。我在VS2010 RTM中编译了下面的代码。我不明白为什么代码CLS被分析成不同的含义。在decltypeCLS obj1;行中;,CLS表示类对象实体。但在CLS obj2CLS行中;,CLS表示一个函数指针,它不带参数地重新运行CLS对象。这种行为是预期的吗?标准中有描述吗 struct CLS { int mi; }; int _tmain(int argc, _TCHAR* argv[]) { decltype(CLS()) obj1;

VS2010部分支持C++11。我在VS2010 RTM中编译了下面的代码。我不明白为什么代码CLS被分析成不同的含义。在decltypeCLS obj1;行中;,CLS表示类对象实体。但在CLS obj2CLS行中;,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

根据C++11 7.1.6.2/1,括号中的预期字符串是一个表达式。编译器只需要检查字符串是否可以被解析为有效表达式。如果是,则代码格式正确。因此,对于代码“decltypeCLS obj1;”,CLS被视为表示对象定义的有效表达式

decltype-specifier:
    decltype ( expression )
更新日期:2012年1月3日

Potatoswatter解释了CLS obj2CLS的原因;是对象定义以外的声明


任何可以被解释为表达式或声明的东西都是声明,不管它有多不寻常。CLS obj2 CLS;声明一个函数,其参数类型CLS是一个没有返回CLS的参数的函数,其返回类型是CLS。

是否应为:是

它被称为

是否预期:是

它被称为

在decltype的参数中,需要一个表达式。将CLS解释为表达式的唯一方法是将其解析为CLS类型的默认构造对象

然而,在C++03中工作方式相同的CLS obj2CLS中,有两种可能的解析:一种作为函数声明,另一种作为对象定义。作为函数声明,外圆括号形成一个参数列表,内容应该通过提供类型和可选名称来指定一个参数或参数列表。在该解析中,CLS被解释为函数类型

另一个有效的解析是作为对象的定义。对于该解析,括号中当然必须有一个表达式或它们的列表,将CLS解释为CLS类型的默认构造对象


现在C++中有一个规则,如果某个事物既可以作为声明也可以作为定义解析,它将被解析为声明。也就是说,在这种情况下,将使用第一种解释

这当然会产生这样一个问题:为什么选择第一种解释,而我们显然希望在这里选择第二种解释。答案是,否则它将破坏C兼容性,在某些情况下甚至破坏我们的预期。例如,请看下面一行:

int f();
现在您会同意,这声明了一个不带参数并返回int的函数,对吗?但是它也可以被解析为int类型的默认初始化变量的定义

一条总是给出人们期望的结果的规则在最好的情况下是复杂的,但很可能是不可能的

请注意,在C++03中,避免自动变量使用auto的简单方法是在定义前加上auto:因为函数声明从不以auto开头,这将迫使编译器将其解释为变量定义。由于在C++11中删除了auto的旧含义,因此它不再适用于非自动变量,而且对于非自动变量,它也永远不会起作用。

在decltype的参数中,需要一个表达式。将CLS解释为表达式的唯一方法是将其解析为CLS类型的默认构造对象

然而,在C++03中工作方式相同的CLS obj2CLS中,有两种可能的解析:一种作为函数声明,另一种作为对象定义。作为函数声明,外圆括号形成一个参数列表,内容应该通过提供类型和可选名称来指定一个参数或参数列表。在该解析中,CLS被解释为函数类型

另一个有效的解析是作为对象的定义。对于该解析,括号中当然必须有一个表达式或它们的列表,将CLS解释为CLS类型的默认构造对象


现在C++中有一个规则,如果某个事物既可以作为声明也可以作为定义解析,它将被解析为声明。也就是说,在这种情况下,将使用第一种解释

这当然会产生这样一个问题:为什么选择第一种解释,而我们显然希望在这里选择第二种解释。答案是,否则它将破坏C兼容性,在某些情况下甚至破坏我们的预期。例如,请看下面一行:

int f();
现在您会同意,这声明了一个不带参数并返回int的函数,对吗?但是它也可以被解析为int类型的默认初始化变量的定义

一条总是给出人们期望的结果的规则在最好的情况下是compl 是的,但很可能是不可能的


请注意,在C++03中,避免自动变量使用auto的简单方法是在定义前加上auto:因为函数声明从不以auto开头,这将迫使编译器将其解释为变量定义。由于在C++11中删除了auto的旧含义,因此它不再起作用,对于非自动变量,它无论如何也不会起作用。

正如其他人所说,这是最令人烦恼的解析。任何可以被解释为表达式或声明的东西都是声明,不管它有多不寻常。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 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 obj3obj1;obj3.mi=10;可以成功编译。为什么选择CLS obj2CLS;被视为函数声明,但CLS obj3obj1;是否被视为对象定义?它们有相似的形式。为什么不在CLS obj2CLS中使用CLS;因为C++语法很复杂:请参阅这里:@杰夫瑞:因为Obj1是一个变量,CLS是一种类型。obj3.mi=10;可以成功编译。为什么选择CLS obj2CLS;被视为函数声明,但CLS obj3obj1;是否被视为对象定义?它们有相似的形式。为什么不在CLS obj2CLS中使用CLS;因为C++语法很复杂:这里请参见:杰夫瑞:因为Obj1是一个变量,CLS是一种类型。现在C++中有一条规则,如果某事物可以作为声明和定义来解析,它将被解析为声明。也就是说,在这种情况下,将使用第一种解释。->错误由于函数声明从不以auto开头,这将迫使编译器将其解释为变量定义。->错误但它也可以被解析为int.->error类型的默认初始化变量的定义。现在C++中有一个规则,如果某个事物既可以作为声明也可以作为定义解析,它将被解析为声明。也就是说,在这种情况下,将使用第一种解释。->错误由于函数声明从不以auto开头,这将迫使编译器将其解释为变量定义。->错误但它也可以被解析为int.->error类型的默认初始化变量的定义。请更正。任何可以解释为表达式或声明的内容都是声明。在约翰的评论中,他说这是错误的。我想再跟你确认一下,对吗?如果是,你能指出C++规则中定义了什么规则吗?我同意。C++ 11语法避免了这种混淆。@杰夫瑞:不,Celtsk的错误陈述是关于声明和定义之间的歧义。将定义更改为表达式将是Johannes正在寻找的更正。任何可以解释为表达式或声明的内容都是声明。在约翰的评论中,他说这是错误的。我想再跟你确认一下,对吗?如果是,你能指出C++规则中定义了什么规则吗?我同意。C++ 11语法避免了这种混淆。@杰夫瑞:不,Celtsk的错误陈述是关于声明和定义之间的歧义。将定义更改为表达式将是Johannes所寻求的更正。