5

Section 9.3.2.1 of the C++ standard states:

In the body of a non-static (9.3) member function, the keyword this is a prvalue expression whose value is the address of the object for which the function is called. The type of this in a member function of a class X is X*. If the member function is declared const, the type of this is const X*, if the member function is declared volatile, the type of this is volatile X*, and if the member function is declared const volatile, the type of this is const volatile X*.

So if this is a prvalue, what is the value category of *this? The following suggests that even when the object is an rvalue, *this is always an lvalue. Is this correct? Please refer to the standard, if possible.

struct F;
struct test
{
    void operator()(F &&) { std::cout << "rvalue operator()" << std::endl; }
    void operator()(F const &&) { std::cout << "const rvalue operator()" << std::endl; }
    void operator()(F &) { std::cout << "lvalue operator()" << std::endl; }
    void operator()(F const &) { std::cout << "const lvalue operator()" << std::endl; }
};

struct F
{
    void operator ()()
    {
        struct test t;
        t(*this);
    }
};

int main()
{
    struct F f;
    f();
    std::move(f)();
}

Output:

lvalue operator()
lvalue operator()
ThomasMcLeod
  • 7,603
  • 4
  • 42
  • 80
  • 1
    The result of dereferencing a pointer is always an lvalue. There are no "xvalue pointers" in C++. – Kerrek SB Jul 11 '15 at 22:02
  • @KerrekSB is that a consequence of the "if it has a name" rule? – Ami Tavory Jul 11 '15 at 22:04
  • 5
    @AmiTavory: There isn't such a rule. That's more of a rule-of-thumb, but that's not the formal specification. It's simply because the language says so. Essentially once you're able to obtain the address of something, you have have an lvalue. Note that you can't take the address of rvalues of builtin types. – Kerrek SB Jul 11 '15 at 22:05
  • 3
    If you use reference-qualified methods along with `std::move` you'll see a difference: `void operator()()&{(test(*this));} void operator()()&&{(test(std::move(*this)));}` – David G Jul 11 '15 at 22:08
  • @KerrekSB Got it, many thanks. – Ami Tavory Jul 11 '15 at 22:10
  • @0x499602D2 Interesting! – Ami Tavory Jul 11 '15 at 22:10
  • This can be helpful: http://stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues – Piotr Siupa Jul 11 '15 at 22:20

1 Answers1

5

From [basic.lval]:

An lvalue (so called, historically, because lvalues could appear on the left-hand side of an assignment expression) designates a function or an object. [ Example: If E is an expression of pointer type, then *E is an lvalue expression referring to the object or function to which E points. As another example, the result of calling a function whose return type is an lvalue reference is an lvalue. —end example ]

And from [expr.unary.op]:

The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points.

Dereferencing a pointer is an lvalue. So *this is an lvalue.

Alternatively, anything that isn't an lvalue is an rvalue. An rvalue is:

An rvalue (so called, historically, because rvalues could appear on the right-hand side of an assignment expression) is an xvalue, a temporary object (12.2) or subobject thereof, or a value that is not associated with an object.

And *this is definitely none of those things.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • @Nik-Lz I don't understand this comment. What's strange, where does cppreference say that, and why would that matter? – Barry Sep 23 '18 at 14:47
  • @Nik-Lz How does that affect what value category of `*this` is? – Barry Sep 23 '18 at 14:51