1. ホーム
  2. c++

[解決済み] std::forwardとstd::moveの使い分け

2023-07-14 11:48:12

質問

私はいつも次のように読んでいます。 std::forward はテンプレート・パラメータにのみ使用されると読んでいました。しかし、私はその理由を自問していました。次の例を見てください。

void ImageView::setImage(const Image& image){
    _image = image;
}

void ImageView::setImage(Image&& image){
    _image = std::move(image);
}

これらは基本的に同じことをする2つの関数です。1つはl値の参照を取り、もう1つはr値の参照を取ります。さて、私は std::forward は引数がl値参照であればl値参照を、引数が1つであればr値参照を返すことになっているので、このコードは次のようなものに単純化できるだろうと思いました。

void ImageView::setImage(Image&& image){
    _image = std::forward(image);
}

これは、cplusplus.com が言及している std::forward (ただ、どんなテンプレート・パラメーターもない)。私は、これが正しいかどうか、そして正しくない場合はその理由を知りたいだけです。

私はまた、正確に何が以下のように異なるのか自問していました。

void ImageView::setImage(Image& image){
    _image = std::forward(image);
}

どのように解決するのですか?

あなたは できない 使用 std::forward は、そのテンプレート引数を明示的に指定することなく これは意図的に非教育的な文脈で使用されています。

これを理解するためには、どのように転送参照( T&& に対して、推論された T が内部で動作していることを確認し、それを「魔法だ」と振り払わないようにしましょう。

template <class T>
void foo(T &&t)
{
  bar(std::forward<T>(t));
}

を呼び出すとします。 foo のようにします。

foo(42);

  • 42 は型のrvalueです。 int .
  • T は次のように推論されます。 int .
  • の呼び出しは bar であるため int のテンプレート引数として std::forward .
  • の戻り値の型は std::forward<U>U && (である(この場合、それは int && である)ので t はrvalueとして転送されます。

さて、ここで foo をこのようにします。

int i = 42;
foo(i);

  • i はlvalueで、型は int .
  • 完全な転送のための特別なルールがあるため、タイプ V を推論するのに使われます。 T 型のパラメータで T && , V & は演繹に使われる。したがって、我々の場合 T は次のように推論されます。 int & .

そのため int & をテンプレート引数として std::forward . したがって、その戻り値は " となります。 int & && となり、次のようになります。 int & . これは lvalue ですので i はlvalueとして転送されます。

概要

なぜこれがテンプレートで動作するかというと std::forward<T> , T は参照である場合(元がlvalueの場合)とそうでない場合(元がrvalueの場合)があります。 std::forward は適切なようにlvalueまたはrvalueの参照にキャストされます。

利用可能な型が1つしかないため、非テンプレートバージョンでは正確にこれを動作させることはできません。言うまでもないことですが setImage(Image&& image) は lvalue を全く受け付けません。lvalue は rvalue の参照にバインドすることができないからです。