C++11 为什么 'decltype(x)' 和 'decltype((x))' 的类型不同?

C++11 why the type of 'decltype(x)' and 'decltype((x))' are different?

我发现它们是不同的,语言标准规定了每个语句应该检索什么样的类型(变量和表达式之间的区别)。但我真的很想知道为什么这两种类型应该不同?

#include<stdio.h>
int x=0;
decltype((x)) y=x;
int main()
{
    y=2;
    printf("%d,",x);
    decltype((1+2))&z=x;//OK (1+2) is an express, but why decltype should differ?
    z=3;
    printf("%d\n",x);
    return 0;
}

运行 结果是'2,3'

那么为什么decltype((int))被设计成int&,这里C++语言设计的考虑是什么?任何需要这样设计的语法一致性? (我不想得到“这是设计使然”)

感谢您的解释。

如果您阅读例如this decltype reference你会看到

2) If the argument is an unparenthesized id-expression or an unparenthesized class member access expression, ...

3) If the argument is any other expression...

... b) if the value category of expression is lvalue, then decltype yields T&;

[强调我的]

然后再往下一点注释

Note that if the name of an object is parenthesized, it is treated as an ordinary lvalue expression, thus decltype(x) and decltype((x)) are often different types.

因为您使用带括号的表达式,所以它被视为左值,这意味着上面的 3.b 是活动的,如果 x 是 [=,decltype((x)) 给您 int& 19=].

需要注意的是,虽然参考不是权威的,但它是从规范中派生出来的,通常是可靠和正确的。


来自 C++11 规范 ISO/IEC 14882:2011,第 7.1.6.2 节 [dcl.type.simple],sub-section 4:

The type denoted by decltype(e) is defined as follows:

— if e is an unparenthesized id-expression or an unparenthesized class member access (5.2.5), decltype(e) is the type of the entity named by e. If there is no such entity, or if e names a set of overloaded functions, the program is ill-formed;

— otherwise, if e is an xvalue, decltype(e) is T&&, where T is the type of e;

— otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;

— otherwise, decltype(e) is the type of e

举个例子:

struct A { double x; };
const A* a = new A();
...
decltype((a->x)) x4 = x3; // type is const double&

基本上与之前链接的参考文献所说的完全相同。

对于您的示例,规范中的 e(x)(因为您有 declspec((x)))。现在第一种情况不适合,因为 (x) 不是未加括号的表达式。第二种情况不适合,因为 (x) 不是 xvalue。尽管第三种情况匹配,(x) 是类型 int 的左值,导致 decltype((x)) 成为 int&.

所以您查询的答案很简单:因为规范是这样说的。

好吧,我在这里看到的答案是 "the specification says so"。我查看了 stroustrup 的原始 decltype 草稿,这就是它所说的。

if expr in decltype(expr) is a variable or formal parameter the programmer can trace down the variable’s or parameter’s declaration, and the result of decltype is exactly the declared type. If expr is a function invocation, the programmer can perform manual overload resolution; the result of the decltype is the return type in the prototype of the best matching function. The prototypes of the built-in operators are defined by the standard, and if some are missing, the rule that an lvalue has a reference type applies.

看看这里的最后一句话,我想这就解释了。由于括号是built-in运算符来表示和表达。