「左辺値」や「右辺値」などの値カテゴリは、式のプロパティです。変数に名前を付ける式は、型右辺値参照をsome_type
持つ変数に名前を付ける場合でも、常に左辺値式です。
lvalue-reference と rvalue-references を使用して、さまざまなカテゴリの式をバインドします。慣例により、lvalue-references はlvalues にバインドされているものとして扱い、rvalue-references はrvalues にバインドされているものとして扱います。
std::forward
参照が参照していると想定するものの値カテゴリを復元することを目的としています。例えば:
int i = 42;
int& l = i;
int&& r = 21;
l // this expression is an lvalue-expression
r // this expression is an lvalue-expression, too (!)
std::forward<int& >(l) // this function-call expression is an lvalue-expression
std::forward<int&&>(r) // this function-call expression is an rvalue-expression
std::forward
は「通常の関数」であるため、引数を使用するだけでは値カテゴリを復元できません。両方の引数は左辺値式です。テンプレート引数を手動で指定して、復元する値カテゴリを指定する必要があります。
これは、右辺値参照なのか左辺値参照なのかアプリオリにわからない参照がある場合にのみ意味があります。これは、転送参照を使用して完全転送を使用する関数を作成する場合に当てはまります。
ところで、値カテゴリを復元して、受け取った引数から別の関数を移動できるようにしたいと考えています。右辺値引数を受け取った場合は、右辺値を渡して、呼び出された関数を移動できるようにします。
OPのような機能の場合:
void push(const T& item)
item
への型左辺値参照const T
があることがわかっています。したがって、必要ありませんstd::forward
:
void push(const T& item) {
// ...
queue.push_back(item); // pass the lvalue argument as an lvalue
// ...
}
別のオーバーロードを追加すると:
void push(T&& item)
std::forward
そのパラメーターの型item
は常に右辺値参照T
であるため、まだ必要ありません(参照型ではないと仮定しT
ます) :
void push(T&& item) {
// ...
queue.push_back(std::move(item)); // pass the rvalue argument as an rvalue
// ...
}
次のようなものがある場合のみ
template<typename U>
void push(forwarding_reference<U> item)
whereforwarding_reference<U>
は左辺値参照または右辺値参照のいずれかである場合、次のものが必要ですstd::forward
。
template<typename U>
void push(forwarding_reference<U> item) // not C++, read on
{
// ...
queue.push_back(std::forward<U>(item)); // pass lvalue arguments as lvalues
// and rvalue arguments as rvalues
// ...
}
実装の詳細により、上記を次のように記述する必要があります。
template<typename U>
void push(U&& item) {
// ...
queue.push_back(std::forward<U>(item)); // pass lvalue arguments as lvalues
// and rvalue arguments as rvalues
// ...
}
上記U&& item
は右辺値参照ではなく、転送参照であることに注意してください。X
転送参照を取得するには、いくつかのテンプレート型パラメーターとフォームの関数パラメーターを含む関数テンプレートが必要ですX&& x
。