In order to make this code with C++11 reference qualifiers work as expected I have to introduce a std::move(*this)
that doesn't sound right.
#include<iostream>
struct A {
void gun() const& { std::cout << "gun const&" << std::endl; }
void gun() && { std::cout << "gun&&" << std::endl; }
void fun() const& { gun(); }
void fun() && { std::move(*this).gun(); } // <-- is this correct? or is there a better option
};
int main() {
A a; a.fun(); // prints gun const&
A().fun(); // prints gun&&
}
Something doesn't sound right about it. Is the std::move
necessary? Is this a recommended use for it? For the moment if I don't use it I get gun const&
in both cases which is not the expected result.
(It seems that *this
is implicit and lvalue reference always, which makes sense but then the only way to escape to use move
)
Tested with clang 3.4
and gcc 4.8.3
.
EDIT: This is what I understand from @hvd answer:
std::move(*this)
is syntactically and conceptually correct
However, if gun
is not part of the desired interface, there no reason to overload the lv-ref and rv-ref version of it. And two functions with different names can do the same job. After all the ref-qualifiers matters at the interface level, which is generally only the public part.
struct A{
private:
void gun() const{std::cout << "gun const&" << std::endl;}
void gun_rv(){std::cout << "gun called from fun&&" << std::endl;}
public:
void fun() const&{gun();}
void fun() &&{gun_rv();} // no need for `std::move(*this)`.
};
But again, if gun
is part of the (generic) interface then std::move(*this)
is necessary, but only then. And also, even if gun
is not part of the interface there readability advantages in not splitting the function gun
as two differently named function and the cost of this is, well..., std::move(*this)
.
EDIT 2: In retrospect this is similar to the C++98 case of const
and no-const
overload of the same function. In some cases it makes sense to use const_cast
(another form of cast) to not repeat code and have the two functions with the same name (https://stackoverflow.com/a/124209/225186).
... although in more complicated cases it makes sense to have auxiliary private functions that delegate the correct behavior for the interface function.
Yes, *this
is always an lvalue, no matter how a member function is called, so if you want the compiler to treat it as an rvalue, you need to use std::move
or equivalent. It has to be, considering this class:
struct A {
void gun() &; // leaves object usable
void gun() &&; // makes object unusable
void fun() && {
gun();
gun();
}
};
Making *this
an rvalue would suggest that fun
's first call to gun
can leave the object unusable. The second call would then fail, possibly badly. This is not something that should happen implicitly.
This is the same reason why inside void f(T&& t)
, t
is an lvalue. In that respect, *this
is no different from any reference function parameter.