web-dev-qa-db-fra.com

À quelles exigences les classes de clés std :: map doivent-elles satisfaire pour être des clés valides?

Je veux mapper des objets d'une classe donnée à des objets d'une autre. La classe que je veux utiliser comme clé, cependant, n'a pas été écrite par moi et est un simple struct avec quelques valeurs. std :: map ordonne son contenu, et je me demandais comment il le faisait, et si une classe arbitraire pouvait être utilisée comme clé ou s'il y avait un ensemble d'exigences (opérateurs et autres) qui devaient être définies.

Si c'est le cas, je pourrais créer un wrapper pour la classe implémentant la carte des opérateurs. J'ai juste besoin de savoir ce que je dois implémenter en premier, et aucune des références pour la classe I trouvée en ligne ne les spécifie.

68
Kian

Tout ce qu'il faut à la clé, c'est qu'elle soit copiable et assignable. L'ordre dans la carte est défini par le troisième argument du modèle (et l'argument du constructeur, s'il est utilisé). Ceci par défaut à std::less<KeyType>, Qui correspond par défaut à l'opérateur <, Mais il n'est pas nécessaire d'utiliser les valeurs par défaut. Écrivez simplement un opérateur de comparaison (de préférence en tant qu'objet fonctionnel):

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

Notez qu'il doit définir un ordre strict, c'est-à-dire si CmpMyType()( a, b ) retourne vrai, alors CmpMyType()( b, a ) doit retourner faux, et si les deux retournent faux, les éléments sont considérés comme égaux (membres de la même équivalence classe).

62
James Kanze

Vous devez définir l'opérateur <, par exemple comme ceci:

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Јовић

La réponse se trouve en fait dans la référence que vous liez, sous la description de l'argument du modèle "Comparer".

La seule exigence est que Compare (qui est par défaut less<Key>, qui utilise par défaut operator< pour comparer les clés) doit être un "ordre faible strict".

3
Nemo

Identique à set: La classe doit avoir un ordre strict dans l'esprit "inférieur à". Soit surcharger un operator< Approprié, soit fournir un prédicat personnalisé. Deux objets a et b pour lesquels !(a<b) && !(b>a) seront considérés comme égaux.

Le conteneur de carte gardera en fait tous les éléments dans l'ordre fourni par cet ordre, c'est ainsi que vous pouvez obtenir le temps de recherche et d'insertion O (log n) par valeur de clé.

2
Kerrek SB