2017-02-06 9 views
1

fooは、lvalueまたはrvalue参照のいずれかをパラメータとして使用したいとします。rvalue参照またはlvalue参照のいずれかをとる関数を宣言する適切な方法は何ですか?

左辺値と右辺値参照を使って2つの過負荷に分解することができます。

void foo(int& a){/*some impl*/} // lvalue ref 
void foo(int&& a){foo(a);} // rvalue ref 
int main(){ 
    int a; 
    foo(a); // lvalue 
    foo(1); // rvalue 
} 

これは動作しますが、かなり冗長です。私はテンプレートを使用して改善することができます。

template<typename T> 
void foo(T &&a) { /*some impl*/ } 
int main(){ 
    int a; 
    foo(a); // lvalue, T = int& 
    foo(1); // rvalue, T = int 
} 

バイナリ関数の場合、テンプレートは2つのテンプレートパラメータを取る必要があります。

template<typename T1, typename T2> 
void foo(T1 &&a, T2 &&b) { /*some impl*/ } 
int main(){ 
    int a; 
    foo(a, a); // (lvalue, lvalue), T1 = int&, T2 = int& 
    foo(1, 1); // (rvalue, rvalue), T1 = int, T2 = int 
    foo(1, a); // (rvalue, lvalue), T1 = int, T2 = int& 
    foo(a, 1); // (lvalue, rvalue), T1 = int&, T2 = int 
} 

行く方法はありますか?もっと良い方法はありますか?

私はcppを使った経験はほとんどありませんが、単に "渡されたパラメータのコピーを作成しない"と言ってもこのようなトリックをする必要があるとは思われません。

gcc 5.4.0-std=c++11を使用しています。

- UPDATE 1 -

私は両方T&&パラメータを取りstreamsライブラリrange(T&& lower, T&& upper)方法を使用していたとき、私は、質問を思い付きました。私はlvalueまたはrvalueの両方のパラメータを関数に渡すことができますが、パラメータとして0some_varを渡すことができません。関数の著者の理由が何であっても、私は、著者が達成したいものを犠牲にすることなく、左辺値と右辺値の混合値を取るように宣言を拡張する方法があるのか​​疑問に思っていました。

- UPDATE 2 - パラメータが読み取り専用である場合

const &は(@RichardCritten)を使用することができます。

コピーしないでパラメータを変更または返す場合は、テンプレートまたは@Yakkのソリューションを使用できます。

@Yakk解決策は、複数のパラメータを取る関数を宣言すると良いでしょう。

たとえば、関数が2つのint l/r-value参照パラメータをとり、テンプレートを使用してint参照を返すと、乱雑な署名が導かれます。

template<typename T1, typename T2> 
int& foo(T1 &&a, T2 &&b) { 
    a += b; 
    return a; 
} 

@Yakk解決策はかなりエレガントなものを与える。その後

int& foo(any_ref<int> a, any_ref<int> b) { 
    a += b; 
    return a; 
} 
+2

練習のポイントは何ですか?なぜ、そのパラメータを昔のやり方で、値によって、または参照参照で取得する関数を持つことができないのですか? –

+3

パラメータの値を変更する必要がない場合は、 'T const&'を使用してください。 –

+2

この質問は通常、XY問題と関連しています。これについて質問した状況をより詳細に記述することができます。 –

答えて

1
template<class T> 
struct any_ref{ 
    T& t; 
    any_ref(T&in):t(in){} 
    any_ref(T&&in):any_ref(in){} 
    any_ref(any_ref const&)=default; 
    any_ref& operator=(any_ref const&)=default; 
    ~any_ref()=default; 

    operator T&()const&{return t;} 
    operator T&&()&&{return std::move(t);}// maybe 
    T& get()const{return *this;} 
}; 

void foo(any_ref<int>a, any_ref<int>b); 

はテンプレート関数ではありません。実際の参照が必要な場合は、本体でint&a=a_arg;を実行できます。

実際には、「多分アウト」パラメータが必要な場合は、int&としてください。右辺値として右辺値を渡したい発信者は、

templare<class T> 
T& as_lvalue(T&&t){return t;} 

と書くことができます。

パラメータが読み取り専用リファレンスの場合は、const&を使用してください。

+0

あなただけが 'get'関数を取り除くことができるならば。とにかく、私はそれがしたいすべてを行います。なぜ標準がそれを行うのに適切なツールを定義していないのだろうと思う。 –

+0

@MarcinKról 'as_lvalue'はおそらくそれを行うためのより良い方法です - コールサイトで左辺値として右辺値をマークアップしてください。一時的にバインドする必要がある参照パラメータを変更することは非常にまれです。私は、inパラメータと(戻り値の一部として)明白な(無視できる)outパラメータを持つ方が良いとは思えない状況はめったにありませんでした。私はそれを見ましたが、それはまれであり、まれなケースでは、 'as_lvalue'はうまくいきます。 – Yakk

関連する問題