web-dev-qa-db-ja.com

static_cast <T &&>の代わりにstd :: forward <T>を使用する理由

次の構造のコードが与えられた場合

_template <typename... Args>
void foo(Args&&... args) { ... }
_

ライブラリコードは、引数の転送のために関数内で_static_cast<Args&&>_を使用することがよくあります。通常、これを正当化する理由は、_static_cast_を使用すると、不要なテンプレートのインスタンス化が回避されるということです。

言語の参照の折りたたみとテンプレートの控除ルールを考えます。 _static_cast<Args&&>_で完全な転送を取得します。この主張の証拠は以下にあります(エラーマージン内で、答えが明らかになることを望んでいます)

  • 右辺値参照(または完全性- この例 のような参照修飾なし)を指定すると、結果が右辺値になるように参照を折りたたみます。使用されるルールは_&& &&_-> _&&_(上記のルール_1_)
  • 左辺値参照が指定されると、結果が左辺値になるように参照が折りたたまれます。ここで使用されるルールは_& &&_-> _&_(上記のルール_2_)

これは本質的に、上記の例でfoo()に引数をbar()に転送させることです。これは、ここで_std::forward<Args>_を使用した場合に得られる動作です。


質問-なぜこれらのコンテキストで_std::forward_を使用するのですか?余分なインスタンス化を避けることは、慣例に違反することを正当化しますか?

Howard Hinnantの論文 n2951 は、_std::forward_の実装が「正しく」動作する6つの制約を指定しました。これらが

  1. 左辺値を左辺値として転送する必要があります
  2. 右辺値を右辺値として転送する必要があります
  3. 右辺値を左辺値として転送しないでください
  4. 少ないcv修飾式をより多くのcv修飾式に転送する必要があります
  5. 派生型の式を、アクセス可能な明確なベース型に転送する必要があります
  6. 任意の型変換を転送しないでください

(1)および(2)は、上記の_static_cast<Args&&>_で正しく動作することが証明されました。 (3)-(6)ここでは当てはまりません。関数が演contextされたコンテキストで呼び出されると、これらのいずれも発生しないためです。


注:私は個人的に_std::forward_を使用することを好みますが、私が持っている正当化は純粋に慣習に従うことを好むということです。

23
Curious

ここに私の2.5がありますが、これはそれほど技術的なセントではありません。今日std::forwardが実際に単なるstatic_cast<T&&>であるという事実は、明日もまったく同じ方法で実装されることを意味しません。委員会は、std::forwardが今日達成することの望ましい振る舞いを反映するために何かを必要としていたので、どこにも転送しないforwardが存在するようになったと思います。

理論的に言えば、std::forwardの傘下で必要な動作と期待を形式化すると、将来の実装者がstd::forwardではなく、自分の実装に固有の何かとしてstatic_cast<T&&>を提供することを妨げません。重要なのはstatic_cast<T&&>の正しい使用法と動作だけであるため、実際にstd::forwardを考慮せずに.

5
Ferenc Deak