あなたの特定のケースでは、2番目のオーバーロードは役に立ちません。
のオーバーロードが 1 つしかない元のコードではLoad
、この関数は左辺値と右辺値に対して呼び出されます。
新しいコードでは、最初のオーバーロードが左辺値に対して呼び出され、2 番目が右辺値に対して呼び出されます。ただし、2 番目のオーバーロードは最初のオーバーロードを呼び出します。最後に、どちらかを呼び出すことの効果は、同じ操作 (最初のオーバーロードが行うものは何でも) が実行されることを意味します。
したがって、元のコードと新しいコードの効果は同じですが、最初のコードの方が単純です。
関数が値、左辺値参照、または右辺値参照のいずれによって引数を取る必要があるかの決定は、それが何をするかに大きく依存します。渡された引数を移動する場合は、右辺値参照を取るオーバーロードを提供する必要があります。ムーブ セマンチンについては参考文献がいくつかあるので、ここでは説明しません。
ボーナス:
私の要点を説明するために、この単純なprobe
クラスを検討してください。
struct probe {
probe(const char* ) { std::cout << "ctr " << std::endl; }
probe(const probe& ) { std::cout << "copy" << std::endl; }
probe(probe&& ) { std::cout << "move" << std::endl; }
};
次に、この関数を考えてみましょう:
void f(const probe& p) {
probe q(p);
// use q;
}
を呼び出すf("foo");
と、次の出力が生成されます。
ctr
copy
ここで驚くことではありません: をprobe
渡す一時的な を作成しますconst char*
"foo"
。したがって、最初の出力行です。次に、このテンポラリが にバインドされp
、 のコピーq
がp
内に作成されf
ます。したがって、2 番目の出力行です。
ここで、値による取得を検討してくださいp
。つまり、次のように変更f
します。
void f(probe p) {
// use p;
}
の出力f("foo");
は現在
ctr
この場合、コピーがないことに驚く人もいるでしょう。一般に、参照によって引数を取得し、それを関数内にコピーする場合は、値によって引数を取得することをお勧めします。この場合、一時変数を作成してコピーする代わりに、コンパイラは引数 (p
この場合) を入力 ( ) から直接構築でき"foo"
ます。詳細については、「速度が必要ですか? 」を参照してください。値渡し。デイブ・エイブラハムズ著。
このガイドラインには、コンストラクターと代入演算子の 2 つの注目すべき例外があります。
このクラスを考えてみましょう:
struct foo {
probe p;
foo(const probe& q) : p(q) { }
};
コンストラクターは、probe
const 参照を受け取り、それを にコピーしp
ます。この場合、上記のガイドラインに従ってもパフォーマンスは向上せず、probe
とにかく のコピー コンストラクターが呼び出されます。ただし、q
値を取得すると、これから説明する代入演算子を使用した場合と同様のオーバーロード解決の問題が発生する可能性があります。
クラスprobe
にスローしないswap
メソッドがあるとします。次に、その代入演算子の推奨される実装 (当面は C++03 の用語で考えます) は次のとおりです。
probe& operator =(const probe& other) {
probe tmp(other);
swap(tmp);
return *this;
}
では、上記のガイドラインに従って、このように書く方が良いでしょう
probe& operator =(probe tmp) {
swap(tmp);
return *this;
}
ここで、右辺値参照とムーブ セマンティクスを使用して C++11 に入ります。移動代入演算子を追加することにしました。
probe& operator =(probe&&);
一時的に代入演算子を呼び出すと、両方のオーバーロードが実行可能であり、どちらも優先されないため、あいまいさが生じます。この問題を解決するには、代入演算子の元の実装を使用します (const 参照によって引数を取ります)。
実際、この問題はコンストラクターと代入演算子に固有のものではなく、どの関数でも発生する可能性があります。(ただし、コンストラクターと代入演算子でそれを経験する可能性が高くなります。) たとえば、次の 2 つのオーバーロードがあるg("foo");
wheng
を呼び出すと、あいまいさが生じます。
void g(probe);
void g(probe&&);