左值的 decltype 括号语法

decltype parenthesis syntax for a lvalue

我试图更好地理解 decltype 以确定编译时表达式的类型。比方说我用一个双变量来做:

#include <iostream>
#include <type_traits>

int main(){
    double a;
    typedef decltype(a) a_type;
    typedef decltype((a)) ref_a_type;
    typedef decltype(a)& o_ref_a_type;

    a_type b;
    ref_a_type c = b;
    o_ref_a_type d = b;

  if (std::is_same<decltype(b), double>::value) std::cout << "b is double\n";
  if (std::is_same<decltype(c), double&>::value) std::cout << "c is double&\n";
  if (std::is_same<decltype(d), double&>::value) std::cout << "d is double&\n";
}

如果我没有理解错的话,这些观点应该是正确的:

  1. decltype(a) returns double& 如果 a 是左值,否则 double
  2. decltype 推导表达式的类型,除非它应用于变量,在这种情况下它推导该变量的类型。
  3. 如果变量被括号括起来,它就成为一个左值表达式。

因此,decltype((a))decltype(a)& 在这种情况下是等价的,但并不总是等价的,例如,如果 a 不是变量:

typedef decltype((5)) ref_a_type;
typedef decltype(5)& o_ref_a_type;

则两种类型不等价(ref_a_typeinto_ref_a_typeint&,因为在这种情况下额外的括号是无用的)。有人可以对此做出更好的解释吗?我应该使用第一种还是第二种方式? 在我看来,第二种方式比第一种方式更具可读性和可理解性。

就 C++ 标准而言,decltype(e) 的规则非常清楚,所以我将复制它们(来自 [dcl.type.simple]):

For an expression e, the type denoted by decltype(e) is defined as follows:
(4.1) — 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;
(4.2) — otherwise, if e is an xvalue, decltype(e) is T&&, where T is the type of e;
(4.3) — otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;
(4.4) — otherwise, decltype(e) is the type of e.

因此请按顺序查看您的示例:

  1. decltype(a): a 是一个未加括号的 id-expression, 所以这只是 a 的类型: double.
  2. decltype((a)):现在有括号,所以我们跳过第一个项目符号。 a 不是一个 xvalue,它是一个 lvalue,所以这是 double&
  3. decltype(a)&:又是第一种情况,所以是double&
  4. decltype((5)):这既不是 id-expression(带括号或其他)、xvalue 或 lvalue - 它是 prvalue,所以我们转到获取表达式类型的最后一个项目符号:int.
  5. decltype(5)&:与最后一点相同,只是现在您明确添加了一个 &,因此 int&.

Should I use the first or the second way?

这取决于您实际想要获得的类型。这两种方式的含义不同 - 您应该使用能够解决您要解决的直接问题的任何一种方式。

更一般地说,由于引用折叠规则,decltype(expr)&总是左值引用。

decltype((expr)) 可以是非引用纯右值(如 decltype((5)))、左值引用(如 decltype((a)))或右值引用(如 decltype((std::move(a)))).