2014-01-10 3 views
23

C++ 11が基準修飾子に基づいてメンバ関数をオーバーロードすることが可能になる:リファレンス修飾子のメンバ関数をオーバーロードするためのユースケースは何ですか?

class Foo { 
public: 
    void f() &; // for when *this is an lvalue 
    void f() &&; // for when *this is an rvalue 
}; 

Foo obj; 
obj.f();    // calls lvalue overload 
std::move(obj).f(); // calls rvalue overload 

私はこれがどのように機能するかを理解し、それのためのユースケースは何ですか?

N2819は、標準ライブラリのほとんどの代入演算子をターゲット値に左寄せする(つまり、代入演算子に "&"参照修飾子を追加する)ことを提案しましたが、this was rejectedを提案しています。それは、委員会がそれに同行しないことを決めた潜在的なユースケースでした。だから、合理的なユースケースは何ですか?

答えて

17

あなたは、参照ゲッターを提供するクラスでは代わりに一時thisを変更することができ、REF-修飾子過負荷は、値から抽出するときに移動セマンティクスを有効にすることができます。例:

class some_class { 
    huge_heavy_class hhc; 
public: 
    huge_heavy_class& get() & { 
    return hhc; 
    } 
    huge_heavy_class const& get() const& { 
    return hhc; 
    } 
    huge_heavy_class&& get() && { 
    return std::move(hhc); 
    } 
}; 

some_class factory(); 
auto hhc = factory().get(); 

これは短い構文を持っているだけ投資する多くの労力のように見えるん

auto hhc = factory().get(); 

auto hhc = std::move(factory().get()); 

EDITと同じ効果を持っている:私はoriginal proposal paperを見つけましたそれは3つの動機付けの例を提供する:

  1. メンバーのための移動(基本的にはこの回答)
  2. 左辺値にoperator &の制約を有効に左辺値にoperator =(TemplateRexの答え)
  3. を拘束。私は、これは「ポインタ」は最終的に逆参照されたときに「指示先は、」生きている可能性が高いことを保証するために賢明であると仮定します
struct S { 
    T operator &() &; 
}; 

int main() { 
    S foo; 
    auto p1 = &foo; // Ok 
    auto p2 = &S(); // Error 
} 

私が今まで個人的にoperator&を使用していたと言うことはできません過負荷。あなたは、このようなoperator=や内部状態を変異させ、参照修飾子として&を追加することにより、voidを返す関数として呼び出されているから、一時に呼び出すことが意味的に無意味な関数を、予防するためにそれらを使用することができます一方で

+0

'huge_heavy_class && get()&&'が間違っている(ダングリング参照を引き起こし、shoukdが 'huge_heavy_class get()&&')、 'auto hhc = std :: move(factory().get());'が重複する。 – ildjarn

+0

@ildjarn左辺値参照を返すのではなく、左辺値参照を返すのはなぜですか? 1つは他のものよりもぶらぶらそうです。そして、そうです、投稿のポイントは 'std :: move(factory()。get())を書く必要を避けるために書くべきコードがたくさんあることです - 私はそれをもっと明確にする必要があると思います。 – Casey

+0

左辺値は左辺値に対してのみ返されるため、問題はありません。 – ildjarn

13

つのユースケースあなたを残して参照修飾子を使用していないのに対し、prohibit assignment to temporaries

// can only be used with lvalues 
T& operator*=(T const& other) & { /* ... */ return *this; } 

// not possible to do (a * b) = c; 
T operator*(T const& lhs, T const& rhs) { return lhs *= rhs; } 

にある2つのバッズ

 T operator*(T const& lhs, T const& rhs); // can be used on rvalues 
const T operator*(T const& lhs, T const& rhs); // inhibits move semantics 

の間の選択は、最初の選択肢は、セマンティクスを移動することができますが、ユーザーに異なる動作(int型とは異なります)。第2の選択は、アサイメントを停止するが、移動セマンティクス(例えば、行列乗算のための可能性のあるパフォーマンスヒット)を排除する。コメント欄で@dypによって

リンクはまた、あなたが(左辺値または右辺値のいずれか)の参照に割り当てにしたい場合に便利です他の(&&)オーバーロードを使用して、上の拡張の議論を提供しています。

+0

より一般的には、一時的な内部データへの参照またはポインタの公開を防ぎます。 – dyp

+0

あなたはいつ*アサインすることができますか? – Mehrdad

+2

関連:http://stackoverflow.com/q/20886466/420683 – dyp

3

Fの場合は()、本のコピーであり、変更はFooの一時を必要としながら、あなたがすることができないそう

0

。もし右辺値参照を持っているときには、戻り値としてオブジェクトのうち部材を移動させるような最適化のためにそれを使用することができる一方

、例えば機能getName基準に応じstd::string const&又はstd::string&&のいずれかを返すことができ修飾子。

Foo& operator+=(Foo&)のような元のオブジェクトへの参照を返す演算子や関数があり、代わりにrvalue参照を返すことで結果を移動可能にすることができます。これも最適化になります。

TL; DR:誤った機能の使用や最適化を防止するために使用します。

関連する問題