実際、これは非常に良い質問です。これまでのところ、ユニバーサル リファレンス トリックとenable_if
ハンマーも使用してきました。ここでは、テンプレートを使用せず、代わりに左辺値キャストを使用するソリューションを紹介します。
ofstream
以下は、 C++98 では不可能な (または非常に難しい) インプレース使用の既知の例を使用して状況が発生する実際の例です(ostringstream
より明確にするために例で使用しています)。
最初に、C++98 でよく見られる左辺値参照の関数が表示されます。
#include<iostream>
#include<sstream>
struct A{int impl_;};
std::ostringstream& operator<<(std::ostringstream& oss, A const& a){
oss << "A(" << a.impl_ << ")"; // possibly much longer code.
return oss;
}
// naive C++11 rvalue overload without using templates
std::ostringstream& operator<<(std::ostringstream&& oss, A const& a){
oss << "A(" << a.impl_ << ")"; // ok, but there is code repetition.
return oss;
}
int main() {
A a{2};
{// C++98 way
std::ostringstream oss;
oss << a;
std::cout << oss.str() << std::endl; // prints "A(2)", ok"
}
{// possible with C++11, because of the rvalue overload
std::cout << (std::ostringstream() << a).str() << std::endl; //prints "A(2)", ok
}
}
C++11 でわかるように、C++98 ではできないことを実現できます。それは、ostringstream
(またはofstream
) インプレースを利用することです。ここで OP の質問が来ます。2 つのオーバーロードは非常に似ていますが、両方を 1 つに結合できますか?
1 つのオプションは、ユニバーサル参照 ( Ostream&&
) を使用し、オプションでenable_if
型を制約することです。あまりエレガントではありません。
この「実世界」の例を使用して私が見つけたのは、左辺値参照と右辺値参照に同じコードを使用したい場合、おそらく一方を他方に変換できるからです!
std::ostringstream& operator<<(std::ostringstream&& oss, A const& a){
return operator<<(oss, a);
}
これは無限再帰関数のように見えますoss
が、左辺値参照のためではありません (そうです、名前があるため左辺値参照です)。したがって、他のオーバーロードが呼び出されます。
2 つの関数を作成する必要がありますが、1 つのコードは維持する必要がありません。
要約すると、(非 const) 左辺値参照と右辺値の両方に関数を適用することが「理にかなっている」場合、それは右辺値を左辺値に変換できるため、単一の関数に転送できることも意味します。「理にかなっています」は、コンテキストと意図したコードの意味に依存することに注意してください。これは、左辺値のオーバーロードを明示的に呼び出すことによってコンパイラに「伝える」必要があるものです。
これが普遍的な参照を使用するよりも優れていると言っているのではありません。それは代替手段であり、間違いなく意図はより明確です。
ここで編集可能なコード: http://ideone.com/XSxsvY . (フィードバックは大歓迎です)