web-dev-qa-db-ja.com

有効なキーになるためには、std :: mapキークラスが満たすべき要件は何ですか?

特定のクラスのオブジェクトを別のクラスのオブジェクトにマップしたい。ただし、キーとして使用するクラスは、私が作成したものではなく、いくつかの値を持つ単純なstructです。 std :: mapはその内容を順序付けしますが、どのようにそれを行うのか、そして任意のクラスをキーとして使用できるのか、または定義する必要がある一連の要件(演算子とその他)があるのか​​疑問に思っていました。

もしそうなら、演算子マップを使用するクラスを実装するラッパーを作成できます。私は最初に何を実装する必要があるかを知る必要があるだけで、クラスI オンラインで見つかった の参照は指定しません。

68
Kian

キーに必要なのは、コピーおよび割り当て可能であることだけです。マップ内の順序は、テンプレートの3番目の引数(および、使用する場合はコンストラクターの引数)によって定義されます。これはデフォルトから_std::less<KeyType>_で、デフォルトは_<_演算子ですが、デフォルトを使用する必要はありません。比較演算子を(できれば関数型オブジェクトとして)書くだけです:

_struct CmpMyType
{
    bool operator()( MyType const& lhs, MyType const& rhs ) const
    {
        //  ...
    }
};
_

厳密な順序を定義する必要があることに注意してください。つまり、CmpMyType()( a, b )がtrueを返す場合、CmpMyType()( b, a )はfalseを返す必要があります。クラス)。

62
James Kanze

次のように、operator <を定義する必要があります。

struct A
{
  int a;
  std::string b;
};

// Simple but wrong as it does not provide the strict weak ordering.    
// As A(5,"a") and A(5,"b") would be considered equal using this function.
bool operator<(const A& l, const A& r )
{
  return ( l.a < r.a ) && ( l.b < r.b );
}

// Better brute force.
bool operator<(const A& l, const A& r )
{ 
    if ( l.a < r.a )  return true;
    if ( l.a > r.a )  return false;

    // Otherwise a are equal
    if ( l.b < r.b )  return true;
    if ( l.b > r.b )  return false;

    // Otherwise both are equal
    return false;
}

// This can often be seen written as
bool operator<(const A& l, const A& r )
{
   // This is fine for a small number of members.
   // But I prefer the brute force approach when you start to get lots of members.
   return ( l.a < r.a ) ||
          (( l.a == r.a) && ( l.b < r.b ));
}
22
BЈовић

答えは、実際には、「比較」テンプレート引数の説明の下で、リンクする参照にあります。

唯一の要件は、Compare(デフォルトはless<Key>、デフォルトではoperator<はキーを比較するために)「厳密な弱い順序」でなければなりません。

3
Nemo

setと同じ:クラスは、「より小さい」の精神で厳密な順序付けが必要です。適切な_operator<_をオーバーロードするか、カスタムの述語を提供します。 !(a<b) && !(b>a)が等しいと見なされる2つのオブジェクトaおよびb

マップコンテナは、実際にすべての要素をその順序で指定された順序で保持します。これにより、キー値によるO(log n)ルックアップおよび挿入時間を実現できます。

2
Kerrek SB