Search code examples
c++c++11language-lawyerxvalue

What expressions create xvalues?


I'm trying to understand the C++11 concepts.

The standard draft which I have says:

An xvalue (an “eXpiring” value) also refers to an object, usually near the end of its lifetime (so that its resources may be moved, for example). An xvalue is the result of certain kinds of expressions involving rvalue references (8.3.2). [ Example: The result of calling a function whose return type is an rvalue reference is an xvalue. —end example ]

OK, so what exactly are the "certain kinds of expressions" that produce xvalues? This part of the spec does not detail a list of these expressions.

I understand lvalue and prvalue (at least I think, I understand).


Solution

  • There is a helpful non-normative note in the introduction to §5 (C++11 §5[expr]/6):

    [ Note: An expression is an xvalue if it is:

    • the result of calling a function, whether implicitly or explicitly, whose return type is an rvalue reference to object type,

    • a cast to an rvalue reference to object type,

    • a class member access expression designating a non-static data member of non-reference type in which the object expression is an xvalue, or

    • a .* pointer-to-member expression in which the first operand is an xvalue and the second operand is a pointer to data member.

    In general, the effect of this rule is that named rvalue references are treated as lvalues and unnamed rvalue references to objects are treated as xvalues; rvalue references to functions are treated as lvalues whether named or not. —end note ]

    Searching through the rest of §5, this list appears exhaustive. The list is followed by an example:

    struct A {
        int m;
    };
    
    A&& operator+(A, A);
    A&& f();
    A a;
    A&& ar = static_cast<A&&>(a);
    

    The expressions f(), f().m, static_cast<A&&>(a), and a + a are xvalues. The expression ar is an lvalue.

    There are two common ways to get an xvalue expression:

    • Use std::move to move an object. std::move performs a static_cast to an rvalue reference type and returns the rvalue reference.

    • Use std::forward to forward an rvalue. std::forward is typically used in a function template to enable perfect forwarding of a function argument.

      If the argument provided to the function template was an rvalue, the parameter type will be an rvalue reference, which is an lvalue. In this case, std::forward performs a static_cast to an rvalue reference type and returns the rvalue reference.

      (Note: If the argument provided to the function template was an lvalue, the parameter type will be an lvalue reference and std::forward will return an lvalue reference.)