CTTCG 附录 B Value Categories

对于变量而言,其括号表达式的值类别是左值引用。但由于 decltype 有特殊效果,直接对变量 x 使用 decltype(x) 并不遵循这一点,为此可以按照下面说的使用 decltype((x))

With the keyword decltype (introduced in C++11), it is possible to check the value category of any C++ expression. For any expression x, decltype((x)) (note the double parentheses) yields:

  • type if x is a prvalue
  • type& if x is an lvalue
  • type&& if x is an xvalue

The double parentheses in decltype((x)) are needed to avoid producing the declared type of a named entity in case where the expression x does indeed name an entity (in other cases, the paren-theses have no effect). For example, if the expression x simply names a variable v, the construct without parentheses becomes decltype(v), which produces the type of the variable v rather than a type reflecting the value category of the expression x referring to that variable.

例子:

#include <iostream>

template<typename T>
struct value_category {
    static constexpr auto value = "prvalue";
};

template<typename T>
struct value_category<T&> {
    static constexpr auto value = "lvalue";
};

template<typename T>
struct value_category<T&&> {
    static constexpr auto value = "xvalue";
};

// Get value category of an expression
#define VALUE_CATEGORY(expr) value_category<decltype((expr))>::value
#define PRINT(expr) printf("(%s) : %s\n", #expr, VALUE_CATEGORY(expr))

int main() {
    PRINT(4);   // prvalue
    int x;
    int &y = x;
    int &&z = (int &&)x;
    PRINT(x);   // lvalue
    PRINT(y);   // lvalue
    PRINT(z);   // lvalue
    PRINT(x+1); // prvalue
}