27

これは右辺値参照です。

void foo(int&& a);

左辺値にはバインドしません。

int i = 42;
foo(i);   // error

これは普遍的な参照です:

template<typename T>
void bar(T&& b);

右辺値にバインドし、左辺値にもバインドします。

bar(i);   // okay

これは右辺値参照です。

template<typename T>
struct X
{
    void baz(T&& c);
};

左辺値にはバインドしません。

X<int> x;
x.baz(i);   // error

ユニバーサル参照が右辺値参照と同じ構文を使用するのはなぜですか? それは不必要な混乱の元ではありませんか? T&&&委員会は、 、T&*T@またはT&42(最後のものは冗談です) のような代替構文を検討したことがありますか? もしそうなら、代替構文を拒否する理由は何でしたか?

4

3 に答える 3

22

オブジェクト型」または「参照型」であるとT&&推測できるユニバーサル参照T

あなたの例では、右辺値が渡されたときのTように推測できるため、関数パラメーターはです。または、左辺値が渡されたときのように推測できます。intint&&Tint&int&std::add_rvalue_reference<int&>::typeint&

T(あなたの例のように)関数呼び出しによって推定されない場合X::baz、それは推定できないint&ため、参照はユニバーサル参照ではありません。

したがって、私見では、新しい構文は本当に必要ありません。テンプレート引数の推定と参照の折りたたみルールにうまく適合し、テンプレートパラメーターを参照型として推定できるという小さな調整があります (C++03 では、型の関数テンプレートパラメーターTまたは、常にオブジェクト型としてT&推測します。)T

これらのセマンティクスとこの構文は、転送の問題の解決策として右辺値参照と引数演繹規則の微調整が提案された当初から提案されていました。 N1385を参照してください。この構文を使用して完全な転送を提供することは、移動セマンティクスの目的で右辺値参照を提案することと並行して提案されました。N1377は N1385 と同じメールに含まれていました。代替構文が真剣に提案されたことはないと思います。

とにかく、代替構文は実際にはもっと混乱するでしょう。ユニバーサル参照の構文があっtemplate<typename T> void bar(T&@)たが、現在と同じセマンティクスを使用している場合bar(i)、テンプレート パラメーターを呼び出すときにorTとして推定でき、関数パラメーターはor ... 型であり、どちらも " " ではありません (その型が何であれ.) したがって、宣言子は実際には常に他の型 (または.int&intint&int&&T&@T&@int&int&&

少なくとも、私たちが得た構文では型T&&は実数型であり、参照の折りたたみ規則はユニバーサル参照を使用する関数テンプレートに固有のものではなく、テンプレートの外側の型システムの残りの部分と完全に一致しています:

struct A {} a;
typedef A& T;
T&& ref = a;    // T&& == A&

または同等:

struct A {} a;
typedef A& T;
std::add_rvalue_reference<T>::type ref = a;    // type == A&

T左辺値参照型の場合もT&&同様です。新しい構文は必要ないと思います。ルールはそれほど複雑でもなく、ややこしいものでもありません。

于 2013-01-13T14:03:50.037 に答える
0

C++ の経験が数年しかない開発者として、私はユニバーサル リファレンスが混乱を招くことに同意しなければなりません。Scott Meyers を読んだり、YouTube で関連する講演を見たりせずに積極的に使用することは言うまでもなく、このようなことを理解することは完全に不可能であるように私には思えます。

&& が右辺値参照または「ユニバーサル参照」のいずれかになるだけでなく、参照の種類を区別するためにテンプレートが使用される方法です。あなたがソフトウェア開発に携わる普通のエンジニアだと想像してみてください。あなたは次のようなものを読みます:

template <typename T>
void foo (T&& whatever) {...}

次に、foo の関数本体は、入力パラメーターが、社内ライブラリーで定義された非常に特殊なクラス型でなければならないことを示しています。素晴らしいと思いますが、テンプレートは現在のソフトウェア バージョンでは廃止されており、おそらく以前の開発の残り物なので、削除しましょう。

コンパイル エラーで頑張ってください…</p>

これを明確に学ばなかった人は、ここで関数テンプレートとして foo を実装して、テンプレート演繹規則を採用し、たまたま一致する折りたたみ規則を参照して、いわゆる「完全な転送」を実現するとは思わないでしょう。何よりも汚いハックのように見えます。ユニバーサル リファレンス用の構文を作成すれば、物事はより簡単になると思います。古いコード ベースで作業していた開発者は、ここでググる必要がある何かがあることを少なくとも知っているでしょう。ちょうど私の2セント。

于 2020-12-17T13:10:35.000 に答える