31

Alex Stepanovは、通常の型を、コピーと同等性に関する特定のプロパティを満たす型として定義しました。C ++ 11がジェネリックプログラミングの領域に移動セマンティクスを追加したため、Stepanovの定義は完全ではなくなりました。移動セマンティクスとの相互作用を含む、通常の型に関する優れたリファレンスを探しています。

4

3 に答える 3

49

概要:

C ++ 11の場合、以下を含めます。

  • move-ctor(noexcept
  • 移動-割り当て(noexcept
  • 全順序(operator<()自然な全順序のstd::less<>場合、および自然な全順序が存在しない場合)。
  • hash<>

そして削除します:

  • swap()(非スロー)-移動操作に置き換えられました。

解説

Alexは、ElementsofProgrammingの通常の型の概念を再検討します。実際、本の多くは通常のタイプに専念しています。

タイプの計算ベースに含めることで、オブジェクトをデータ構造に配置し、アルゴリズムを使用してオブジェクトをあるデータ構造から別のデータ構造にコピーできる一連のプロシージャがあります。動作の規則性、したがって相互運用性が保証されるため、このような基準を持つタイプを規則的と呼びます。-EoPのセクション1.5

EoPで、Alexはunderstanding_typeの概念を導入しました。これにより、移動に使用できる非スロースワップアルゴリズムが提供されます。基礎となる型テンプレートは、C ++で特に有用な方法で実装することはできませんがnoexcept、合理的な近似として非スロー()move-ctorおよびmove-assignを使用できます(基礎となる型により、追加の破棄なしで一時的なものとの間で移動できます一時的)。C ++ 03では、非スローswap()を提供することが移動操作を概算するための推奨される方法でした。move-ctorとmove-assignを提供する場合は、デフォルトでstd::swap()十分です(ただし、より効率的な方法を実装することもできます)。

[ムーブ代入とコピー代入の両方をカバーするために、値を渡す単一の代入演算子を使用することをお勧めします残念ながら、型がデフォルトのmove-ctorを取得する場合の現在の言語規則により、複合型ではこれが機能しなくなります。それが言語で修正されるまで、2つの代入演算子を書く必要があります。ただし、他のシンク引数に値渡しを使用して、すべての引数の移動/コピーを処理する際の組み合わせ論を回避することはできます。]

Alexはまた、全順序付けの要件を追加します(ただし、自然な全順序付けがない場合があり、順序付けは純粋に表現的なものである場合があります)。operator<()自然な全順序付けのために予約する必要があります。私の提案は、自然な全順序付けが利用できない場合に特化std::less<>()することです。標準にはその前例がいくつかあります)。

EoPでは、Alexは平等に関する要件を緩和して、表現的平等が十分であることを可能にします。便利な改良。

通常の型も等式的に完全である必要があります(つまりoperator==()、非フレンド、非メンバー、関数として実装可能である必要があります)。等式的に完全な型もシリアル化可能です(ただし、正規のシリアル化形式がない場合、ストリーム演算子の実装はデバッグ以外にはほとんど役に立ちません)。等式的に完全な型もハッシュできます。C ++ 11(またはTR1を使用)では、の特殊化を提供する必要がありますstd::hash

通常の型のもう1つの特性はarea()、標準の構文がまだないことです。テストを除いて、実際に実装する理由はほとんどないでしょう。これは、複雑さを指定するための便利な概念です。複雑さをテストするために、頻繁に実装(または近似)します。たとえば、コピーの複雑さを、オブジェクトの領域をコピーする時間によって制限されるものとして定義します。

通常の型の概念は言語固有ではありません。新しい言語が提示されたときに私が最初に行うことの1つは、通常の型がその言語でどのように現れるかを理解することです。

于 2012-12-22T04:22:51.410 に答える
11

ジェネリックプログラミングの制約は、式の観点から最もよく表現されます。コピー可能性に対する同じ制約のより現代的な表現は、両方のステートメントが有効である必要があるということです。

T b = a;

T b = ra;

ここで、はタイプoraの左辺値であり、はタイプまたは。の右辺値です。(同様の事後条件で。)Tconst TraTconst T

この定式化は論文の精神に基づいていると私は信じています。C ++ 03はすでに左辺値や右辺値などの概念を使用していることに注意してください。そのため、私たちが表現した制約では、T source(); T b = source();有効なもの、確かに理にかなったものが必要です。

これらの制約の下では、C++11ではあまり変更されません。特に注目すべきは、そのような(病理学的)タイプは不規則であるということです。

struct irregular {
    irregular() = default;
    irregular(irregular const&) = default;
    irregular& operator=(irregular const&) = default;

    irregular(irregular&&) = delete;
    irregular& operator=(irregular&&) = delete;
};

のようなものirregular a; irregular b = a;は有効ですが、irregular source(); irregular b = source();そうではないからです。これは、ある程度コピー可能(またはコピー割り当て可能)のタイプですが、十分ではありません。[これは多少の欠陥と見なされており、C ++ 1yで変更される予定です。このようなタイプは、実際にはコピー可能です。]

さらに、コピーが保持するためにある意味で元の(または、右辺値の場合はコピー前の元の)と同等でなければならないという事後条件の場合、移動特殊メンバーは、それぞれのコピースペシャルメンバー。別の言い方をすれば、コピーセマンティクスは移動セマンティクスの改良版です。これは、アサーションが次の条件を満たしている必要があることを意味します。

T a;
T b = a;
T c = std::move(a);
assert( b == c );

つまり、コピー「リクエスト」(つまり、左辺値ソースを含む式)または移動リクエスト(右辺値ソースを含む式)を介してそこに到着したかどうかに関係なく、「実際に」何が起こったかに関係なく、同じ結果が得られる必要があります(特別会員のコピーまたは特別会員の移動が含まれていたかどうか)。

興味深いのは、などの特性がstd::is_copy_constructible以前はと呼ばれてstd::has_copy_constructorいたが、固有のプロパティではなく式に重点を置くために名前が変更されたという事実です。コンストラクタや割り当て演算子がないstd::is_copy_constructible<int>::value && std::is_move_assignable<int>::valueという事実に関係なく、のようなものが当てはまります。int

たとえば、移動コンストラクターの有無は、型をコピー構成可能にするために十分でも必要でもないため、式レベルで制約を表現することによって、実際にジェネリックプログラミングを行うことをお勧めします。

于 2012-12-22T03:22:04.237 に答える
1

Stepanovの論文によると、ムーブ代入とムーブコピーコンストラクターを、組み込み型の他のすべての演算子とともに追加します。

于 2012-12-22T00:52:44.693 に答える