41

テンプレートにせずに、左辺値と右辺値の両方の引数を受け入れる関数を C++ で記述する方法はありますか?

たとえば、print_streamから読み取り、読み取っistreamたデータを画面などに出力する関数を作成するとします。

次のように呼び出すのが妥当だと思いますprint_stream

fstream file{"filename"};
print_stream(file);

このように:

print_stream(fstream{"filename"});

print_streamしかし、両方の使用法が機能するように宣言するにはどうすればよいでしょうか?

私がそれを次のように宣言した場合

void print_stream(istream& is);

右辺値が非 const 左辺値参照にバインドされないため、2 番目の使用はコンパイルされません。

私がそれを次のように宣言した場合

void print_stream(istream&& is);

左辺値が右辺値参照にバインドされないため、最初の使用はコンパイルされません。

私がそれを次のように宣言した場合

void print_stream(const istream& is);

から読み取ることができないため、関数の実装はコンパイルされませんconst istream

その実装を個別にコンパイルする必要があるため、関数をテンプレートにして「ユニバーサル参照」を使用することはできません。

2 つのオーバーロードを提供できます。

void print_stream(istream& is);
void print_stream(istream&& is);

2 番目の呼び出しを最初の呼び出しにしますが、それは多くの不必要なボイラープレートのように思えます。このようなセマンティクスを持つ関数を記述するたびに、これを行わなければならないのは非常に残念です。

私にできるもっと良いことはありますか?

4

6 に答える 6

27

2 つのオーバーロードを提供するか、関数をテンプレートにする以外に、まともな選択はほとんどありません。

あなたが本当に本当に醜い)代替手段を必要とするなら、あなたができる唯一の(非常識な)ことは、あなたが-修飾された型const&のオブジェクトをconstそれ(とにかくそれをサポートしたくない)。関数はconst、参照の性質をキャストすることができます。

しかし、私は個人的に 2 つのオーバーロードを作成し、一方を他方に関して定義するので、宣言は複製しますが、定義は複製しません。

void foo(X& x) 
{ 
    // Here goes the stuff... 
}

void foo(X&& x) { foo(x); }
于 2013-07-14T21:55:21.913 に答える
6

別のやや醜い代替手段は、関数をテンプレートにして、両方のバージョンを明示的にインスタンス化することです。

template<typename T>
void print(T&&) { /* ... */ }

template void print<istream&>(istream&);
template void print<istream&&>(istream&&);

これは、個別にコンパイルできます。クライアント コードには、テンプレートの宣言のみが必要です。

個人的には、Andy Prowl の提案に固執したいと思います。

于 2013-07-14T22:03:38.560 に答える