0xe3aad

0xe3aad

C++ パーフェクトフォワーディング

完全転送の必要性#

以下はクラスのファクトリ関数の例です:

上記の例では、引数オブジェクトargは値渡しで渡されていますが、これにより余分な一時オブジェクト1が生成されるため、参照渡しに変更します:

しかし、この実装では右辺値引数をバインドすることはできません。例えば、factory<X>(42)はコンパイルエラーになります。さらに、定数参照を使用して次のように変更します:

この実装では移動セマンティクスをサポートできないという問題があります。右辺値参照を使用することで、完全転送の問題を解決できます。

参照の折り畳み#

C++11以前では、参照型をさらに参照することはできませんでしたが、右辺値参照の登場により、この方法が緩和2され、参照の折り畳み規則が生まれました。これにより、参照を参照することができ、左参照と右参照の両方が可能になりました。ただし、次の規則に従います:

関数の形式引数の型実引数の型推論後の関数の形式引数の型
T&左参照T&
T&右参照T&
T&&左参照T&
T&&右参照T&&

テンプレートパラメータの型推論#

関数テンプレートtemplate<typename T>void foo(T&&);に対して、上記の参照の折り畳み規則を適用すると、次の結論が得られます:

  • 実引数が型 A の左値の場合、テンプレートパラメータ T の型はA&であり、形式引数の型もA&です。
  • 実引数が型 A の右値の場合、テンプレートパラメータ T の型はA&&であり、形式引数の型もA&&です。

これは、クラステンプレートのメンバ関数テンプレートの型推論にも同様に適用されます:

関数テンプレートの形式引数は T&& の形式でなければならず、型推論が必要です。const T&& の形式で宣言された場合でも、文字通りに使用するだけであり、型推論は必要ありません。

完全転送#

以下は上記のコードの完全転送バージョンの実装です:

ここで、std::forwardは標準ライブラリ<utility>に定義されているテンプレート関数です:

std::remove_referenceは、標準ライブラリ<type_traits>に定義されているクラステンプレートであり、型の参照を削除するために使用されます。ここで定義されている type は参照の基本型です。

  • 実引数のデータ型が左値参照型S&の場合 (T = S&)、tの型はS&であり、static_cast<S& &&>(t)static_cast<S&>(t)に折り畳まれます。
  • 実引数のデータ型が右値参照型S&&の場合 (T = S&&)、tの型はS&&であり、static_cast<S&& &&>(t)static_cast<S&&>(t)に折り畳まれます。

参考文献#

https://zh.wikipedia.org/zh-cn/%E5%8F%B3%E5%80%BC%E5%BC%95%E7%94%A8

Footnotes#

  1. 一時オブジェクトのライフサイクルは 1 つの文の時間だけです。

  2. ここで「緩和」という言葉を使用するのは、参照の参照を間接的に定義できるのは、型エイリアスとテンプレートパラメータの場合だけだからです。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。