samedi 22 juin 2019

Rvalues, lvalues and formal definitions

A lot of people are confused when they hear that in

int&& x

x is an rvalue reference and x is an lvalue. Misunderstanding stems from the fact that identifiers and expressions are different things, and so are types and value categories. Moreover, types of expressions are "adjusted prior to any further analysis", and the words "rvalue" and "lvalue" can appear both in type name and in value category name.

I want to clarify formal definitions. Suppose we have a function:

void f(int&& x) {
    ... = x;
    ... = std::move(x);
}

Are the following statements correct?

  1. In the line 1, x is an identifier (id-expression) that names a function parameter. Its type is int&&, and this is the type that decltype(x) returns. x is not an expression and has no value category.
  2. In the line 2, x is an expression. Before type adjustment its type is int&&, and after the type becomes int. The value category is lvalue.
  3. In the line 3, std::move(x) is an expression. Its type before adjustment is int&&, after - int. The value category is xvalue.
  4. When we say that x has rvalue reference type, we refer either to the type of x as an identifier, or to the type of x as an expression before type adjustment.
  5. The word "type" in the statement "Each expression has some non-reference type, and each expression belongs to exactly one of the three primary value categories" at cppreference.com refers to the type after type adjustment.
  6. When Scott Meyers writes "If the type of an expression is an lvalue reference (e.g., T& or const T&, etc.), that expression is an lvalue." he refers of the type before adjustment, and the second word "lvalue" refers to the value category.

Aucun commentaire:

Enregistrer un commentaire