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 correctHowever, 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://mcmap.net/q/95065/-how-do-i-remove-code-duplication-between-similar-const-and-non-const-member-functions).
... although in more complicated cases it makes sense to have auxiliary private functions that delegate the correct behavior for the interface function.
std::move
, how aboutstatic_cast<A&&>(*this).gun()
? – Asantestd::forward<A&&>(*this).gun()
for that matter. – Interrupterrvalue()
that returns*this
as an rvalue. Then you can callthis->rvalue()->...
. – Bernadineauto rvalue()->decltype(std::move(*this)){return std::move(*this);}
? – Interrupter