13

完全転送について学習するためのテスト ケースを設定しました。

std::string inner(const std::string& str ) {
return "const std::string&";
}
std::string inner(std::string& str ) {
    return "std::string&";
}
std::string inner(const std::string&& str ) {
    return "const std::string&&";
}
std::string inner(std::string&& str ) {
    return "std::string&&";
}

template <typename T> void outer(T&& t) {
  std::cout << "t: " << t << std::endl;
  std::cout << "perfect forward: " << inner(std::forward<T>(t)) << std::endl;
  std::cout << std::endl;
}

void PerfectForwarding()
{
     outer("literal");
     outer(lvalue);
     outer(constlvalue);
     outer(rvalue());
     outer(constrvalue());
}

std::forward期待どおりに動作します。ID なしで独自の forward 関数を実装すると、興味深い動作が現れます。

template <typename T> T&& MyForward(T& t)
{
   return ((T&&)t);
}

in outer に置き換えるstd::forwardと、まったく同じ結果が得られます! MyForwardこの動作は、なぜ ID が使用されるのかという疑問を投げかけます。

コンパイラ VS2010

更新 1: 型推論の防止に関して

私の知る限り、特別なタイプの控除ルールは T&& でのみアクティブになります。forward, の定義に注意してくださいforward(typename identity<T>::type& t)。引数の型には & が 1 つだけあります。実際、ID を使用するように MyForward を変更し、(T&&) キャストを省略した後、この例はコンパイルされません。表面的には、左辺値から右辺値へのキャストにより、フォワードが機能するように見えます。

更新 2: GCC 4.5 を使用して ideone.com でテスト、同じ動作。

4

2 に答える 2

14

remove_reference<T>identityドラフトの古いバージョンにありましたが、に変更されましたremove_reference)は、型の推測を防ぐために使用されます。明示的な型パラメーターでstd::forward のみ機能します。それ以外の場合、以下がコンパイルされます。

std::forward(t)

...しかし、それは正しいことをしません。

左辺値/右辺値の問題に関しては、2つのオーバーロードstd::forwardあることに注意してください。1つは左辺値用、もう1つは右辺値用です。

実際、MyForward与えられた実装はより似std::moveています:左辺値を右辺値に変換します(違いは、moveが右辺値も受け入れることです)。

于 2012-04-23T19:08:51.303 に答える
0

と の定義を VS 2010 で確認しforwardました。あなたと彼らidentityの唯一の違いは、あなたがパラメーターを使用し、彼らがパラメーターを使用することです。そして、それはただです。MyForwardforwardT&typename identity<T>::type&identity<T>::typeT

この違いの最も重要な (おそらく唯一の) 効果はforward、テンプレート引数を明示的に指定する必要がありますが、テンプレート引数MyForwardは呼び出しから推測できることです。

于 2012-04-24T03:44:15.967 に答える