Can a member function returns a modifiable lvalue reference to an rvalue object?

Viewed 146

I have a bit confusion about this code:

struct A
{
    A& bar()&&;
};

A& A::bar()&&
{
    std::cout << "A::bar()&&\n";
    return *this;
}

int main()
{
    A{}.bar();// called by an rvalue
}

So what I understand is that bar can be called only by a modifiable-rvalue. Until this it is OK. But how can bar return a non-constant lvalue reference to that rvalue?

  • How bar() binds and returns a modifiable lvalue reference to that rvalue object?
2 Answers

The reason is that the this pointer for a class C can be either C* or const C* - not C& * or C&& * (those aren't actual types; you can't declare a C& * ptr). So, even when your method runs for an rvalue instance of class A, you get one of those two (GodBolt). And when you apply the * operator, you get an lvalue, not an rvalue.

This has to do with [expr.unary.op]/1

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. If the type of the expression is “pointer to T”, the type of the result is “T”. [ Note: Indirection through a pointer to an incomplete type (other than cv void) is valid. The lvalue thus obtained can be used in limited ways (to initialize a reference, for example); this lvalue must not be converted to a prvalue, see [conv.lval]. — end note ]

emphasis mine

So when you dereference this yo get an lvalue. It doesn't matter if this is pointing to a temporary object or not, you will always get an lvalue. Since *this is an lvalue, you are legally allowed to return an lvalue reference, the program in syntactically correct. Semantically it is not, but that is a lot harder to test for and is often not something that is diagnosed as it requires quite a bit of static analysis.


It would be cool if the language could be updated where * only yields an lvalue when applied to this in a non-rvalue qualified function.

Related