4

次のようなタイプのセットがあります。

struct MyFlag
{
     SomeId source_id; // INVALID_ID by default
     SomeData data; // regular type

     friend bool operator==( const MyFlag& a, const MyFlag& b ) { return a.source_id == b.source_id; }
     friend bool operator<( const MyFlag& a, const MyFlag& b ) { return a.source_id < b.source_id; }
     friend bool operator!=( const MyFlag& a, const MyFlag& b ) { return !(a == b); }

     friend bool operator==( const SomeId& a, const MyFlag& b ) { return a == b.source_id; }
     friend bool operator<( const SomeId& a, const MyFlag& b ) { return a < b.source_id; }
};



MyFlag flag_a { id, data_A };
MyFlag flag_b { id, data_B };

assert( flag_a == flag_b );
assert( flag_a.data != flag_b.data );
assert( flag_a == id );
assert( flag_b == id ); 

MyFlag flag = flag_b;
assert( flag == flag_a );
assert( flag == id );
assert( flag.data != flag_a.data );

const MyFlag flag_x ={ id_x, data_A };
flag = flag_X;
assert( flag != flag_a );
assert( flag.data == flag_a.data );

つまり、オブジェクトの状態の特定の部分のみが比較対象となります。この例では、MyFlag オブジェクトは ID を使用して他のオブジェクトと比較されますが、含まれる残りのデータは比較されません。

Sean Parent が「値の型」について与えた定義と一致すると思いますが、これは奇妙でなじみのない (しかし私の場合は役立つ) パターンだとも思います。

だから私の質問は:この...概念の概念名はありますか?


そのようなタイプはどのように役立ちますか?私はこの種の型を「ブラック ボード」イベント システムで使用します。これは基本的に、少なくとも規則的な型を持つ任意の値の一種のセットです。ただし、このブラック ボードは、プッシュされた (挿入された) 値が既に見つかっていても (比較によって) 体系的に上書きします。このようにして、比較演算子を識別子として使用して、ブラック ボードの値の完全な状態を上書きします。

それがよく知られたパターンやアイデアなのか、それとも長期的に問題があるのか​​ はわかりません。これまでのところ、非常に役に立ちました。また、「頭が良すぎる」ようにも感じますが、それを確認するには、このパターンの経験が不足しています。比較演算子の使い方を悪用しているのかもしれませんが、これらの型のセマンティクスは私の使い方では正しいと感じています。

必要に応じて、詳細な使用例を提供できます。

4

5 に答える 5

1

あなたが説明しているように見えるのは、本質的ではない部分です。std::vector の capacity() と非常によく似ています。Regular の概念は、コピー、代入、および等価性のセマンティクスの観点から定義されています。これらのセマンティクスが守られている限り、型は Regular です。型が何を表すかを決定することによって、型の本質的な部分が何であるかを決定する必要があります。オブジェクトが表すものに寄与する重要な部分は、コピーして等値比較に含める必要があります。

于 2015-06-08T05:19:52.337 に答える
1

型には、全体の順序付けを定義する正しい比較演算子があるため、TotallyOrdered( N3351定義を使用して) です。

それは、全体の順序付けがすべてのオブジェクトの状態を比較するかどうかを区別しませんが、それを区別するための概念はないようです。定義することも (==状態の比較された部分に基づいてオブジェクトが等しいと言う場合、比較されない部分もあるかどうかをどのように判断できますか?) も、アルゴリズムが気にする理由もないためです。

于 2014-01-08T08:53:45.557 に答える
0

関係演算子を適用するレベルとそのセマンティクスを区別する必要があると思います。オペレーターは正しいセマンティクスを持っているようですが、紛らわしいレベル (オブジェクト全体ではなく ID メンバー) で適用されます。

まず、オブジェクト全体の状態を定義operator==operator<て比較します。これは、最も驚くべき方法ではなく、最も慣用的な方法です。ID のみを比較するには、ID データ メンバーへの射影を行う名前付き演算子を作成します。必要に応じて、混合バージョン (1つのパラメーターと 1 つのパラメーターを使用) を定義することもできますが、これは通常、暗黙的な変換のオーバーヘッドを回避するためにのみ必要です。この場合は不要のようです。 id_equal_toMyFlagSomeID

第 2 に、これらの演算子が正しいセマンティクス( の再帰、対称、および推移operator==、および の非反射、非対称、推移、および合計) を持つことを確認するには、および の対応する演算子でoperator<それらを定義するだけです。また、 and on にも正しいセマンティクスがあることを確認する必要があります。組み込みの場合、これは保証されますが、ユーザー定義の ID タイプの場合は、同じトリックを再度適用できます。std::tiestd::tupleoperator==operator<SomeIdstd::tie

#include <cassert>
#include <tuple>

enum { invalid = -1 };
using SomeId = int;   // or any regular type with op== and op<
using SomeData = int; // or any regular type with op== and op<

struct MyFlag
{
    SomeId source_id; // INVALID_ID by default
    SomeData data;    // regular type

    friend bool operator==(MyFlag const& a, MyFlag const& b) 
    { return std::tie(a.source_id, a.data) == std::tie(b.source_id, b.data); }

    friend bool operator!=(MyFlag const& a, MyFlag const& b) 
    { return !(a == b); }

    friend bool operator<(MyFlag const& a, MyFlag const& b) 
    { return std::tie(a.source_id, a.data) < std::tie(b.source_id, b.data); }

    // similarly define >=, >, and <= in terms of !(a < b), (b < a) and !(b < a)

    friend bool id_equal_to(MyFlag const& a, MyFlag const& b)
    { return a.source_id == b.source_id; }    
};

int main()
{    
    auto const id = 0;
    auto const data_A = 1;
    auto const data_B = 2;

    MyFlag flag_a { id, data_A };
    MyFlag flag_b { id, data_B };

    assert( flag_a != flag_b );
    assert( id_equal_to(flag_a, flag_b) );
    assert( flag_a.data != flag_b.data );

    MyFlag flag = flag_b;
    assert( flag != flag_a );
    assert( id_equal_to(flag, flag_a) );
    assert( flag.data != flag_a.data );

    auto const id_x = invalid;
    const MyFlag flag_x = { id_x, data_A };
    flag = flag_x;
    assert( flag != flag_a );
    assert( id_equal_to(flag, flag_x) );
    assert( !id_equal_to(flag, flag_a) );
    assert( flag.data == flag_a.data );    
}

ライブの例

于 2014-01-08T12:42:43.117 に答える