Чтобы заставить этот код с ссылочными квалификаторами С++ 11 работать должным образом, я должен ввести std::move(*this), который звучит неправильно.
#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&&
}
Что-то не так в этом. Нужен ли std::move? Это рекомендуемое использование? На данный момент, если я не использую его, я получаю gun const& в обоих случаях, что не является ожидаемым результатом.
(Кажется, что *this является неявным и всегда имеет ссылку на lvalue, что имеет смысл, но тогда единственный способ избежать использования move)
Протестировано с clang 3.4 и gcc 4.8.3.
РЕДАКТИРОВАТЬ: Это то, что я понимаю из ответа @hvd:
1) std::move(*this) является синтаксически и концептуально правильным
2) Однако, если gun не является частью желаемого интерфейса, нет причин перегружать его версиями lv-ref и rv-ref. И две функции с разными именами могут выполнять одну и ту же работу. В конце концов, ref-определители имеют значение на уровне интерфейса, который обычно является только публичной частью.
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)'.
};
Но опять же, если gun является частью (универсального) интерфейса, тогда std::move(*this) необходим, но только тогда. Кроме того, даже если gun не является частью интерфейса, есть преимущества читабельности, заключающиеся в том, что функция gun не разделяется на две функции с разными именами, и стоимость этого, ну..., std::move(*this).
РЕДАКТИРОВАНИЕ 2: в ретроспективе это похоже на случай С++ 98 с перегрузкой const и no- const одной и той же функции. В некоторых случаях имеет смысл использовать const_cast (другую форму приведения), чтобы не повторять код и иметь две функции с одинаковым именем (qaru.site/info/29860/...)