I have the following setup:
struct foo
{
void bar( ) & { std::cout << "lvalue\n"; }
void bar( ) && { std::cout << "rvalue\n"; }
~foo( ) { bar( ); }
};
int main( int arg, char **argv )
{
foo{ }.bar();
}
which leads to the output of
rvalue
lvalue
I do not understand the output of the dtor which is always lvalue
no matter how hard I try. While I agree that taking the address
similar to
(*this).bar( ); // sure enough this will print lvalue
calls the lvalue-overload I do not understand why I can never get an output of rvalue
for the dtor.
I find this strange since the object is an rvalue first and somehow binds to an lvalue before being destructed. What's the matter here?
this
is a prvalue, but *this
is a lvalue, naturally it will call lvalue ref-qualifiers:
§ 5.3.1 Unary operators [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.
From cppreference, this pointer:
When a non-static class member is used in any of the contexts where the this keyword is allowed (non-static member function bodies, member initializer lists, default member initializers), the implicit this-> is automatically added before the name, resulting in a member access expression (which, if the member is a virtual member function, results in a virtual function call).
Note: calling this-> is equivalent to calling (*this).
#include <iostream>
struct foo
{
void bar( ) & { std::cout << "lvalue\n"; x(); }
void bar( ) && { std::cout << "rvalue\n"; x(); }
void x( ) & { std::cout << "x lvalue\n"; }
void x( ) && { std::cout << "x rvalue\n"; }
~foo( ) { bar( ); }
};
int main( int arg, char **argv )
{
foo{ }.bar();
}
Prints:
rvalue
x lvalue
lvalue
x lvalue
If, for some reason, you really want to call a rvalue function, you could cast the this pointer to a rvalue reference:
~foo( ) { static_cast<foo&&>(*this).bar( ); }
Or using std::move
:
~foo( ) { std::move(*this).bar( ); }