[解決済み] std::forwardとstd::moveの使い分け
質問
私はいつも次のように読んでいます。
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 の参照にバインドすることができないからです。
関連
-
[解決済み】 unsigned int vs. size_t
-
[解決済み】Visual Studio 2015で「非標準の構文; '&'を使用してメンバーへのポインターを作成します」エラー
-
[解決済み】C++エラーです。"配列は中括弧で囲まれたイニシャライザーで初期化する必要がある"
-
[解決済み】'cout'は型名ではない
-
[解決済み] 配列のベクトルを扱う正しい方法
-
[解決済み] using namespace std;」はなぜバッドプラクティスだと言われるのですか?
-
[解決済み] ムーブセマンティクスとは何ですか?
-
[解決済み] std::move()とは何ですか?また、どのような場合に使用するのですか?
-
[解決済み] const std::string & をパラメータとして渡す時代は終わったのでしょうか?
-
[解決済み】画像処理。コカ・コーラ缶」認識のためのアルゴリズム改良
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】構造体のベクター初期化について
-
[解決済み】非静的メンバ関数への参照を呼び出す必要がある
-
[解決済み】クラスのコンストラクタへの未定義参照、.cppファイルの修正も含む
-
[解決済み] gdbを使用してもデバッグシンボルが見つからない
-
[解決済み】std::cin.getline( ) vs. std::cin
-
[解決済み] to_string は std のメンバーではない、と g++ が言っている (mingw)
-
[解決済み】VC++の致命的なエラーLNK1168:書き込みのためにfilename.exeを開くことができません。
-
[解決済み】'std::cout'への未定義の参照
-
[解決済み] スタックアロケーションにより初期化されていない値が作成された
-
[解決済み] std::moveとstd::forwardの違いは何ですか?