2009-07-25 6 views
4

Si je veux trier un vecteur d'un type UDT par l'un des deux types de variables qu'il contient, est-il possible que le type de bibliothèque standard le fasse ou dois-je écrire mon propre tri? fonction.Types de bibliothèques standard et types définis par l'utilisateur

Par exemple, si vous aviez

struct MyType{ 
int a; 
int b; 
}; 

vector<MyType> moo; 

// do stuff that pushes data back into moo 

sort(moo.begin(), moo.end()) // but sort it by lowest to highest for a, not b 

est donc possible en utilisant ce genre de stdlib? Merci.

Répondre

8

Il est possible d'utiliser la fonction standard si votre type implémente "bool operator < (...) const" et un constructeur de copie (généré par le compilateur ou personnalisé).

struct MyType { 
    int a; 
    int b; 
    bool operator < (const MyType& other) const { 
     ... // a meaningful implementation for your type 
    } 
    // Copy constructor (unless it's a POD type). 
    MyType(const MyType &other) 
     : a(other.a), b(other.b) { } 
    // Some other form of construction apart from copy constructor. 
    MyType() 
     : a(0), b(0) { } 
}; 

Vous pouvez passer une fonction de commande (ou un foncteur) comme troisième argument à sort() au lieu de mettre en œuvre l'opérateur "<".

bool type_is_less(const MyType& t1, const MyType& t2) { ... } 
... 
std::sort(c.begin(), c.end(), type_is_less); 

Ceci est utile dans les situations suivantes:

  1. vous ne voulez pas mettre en œuvre l'opérateur "<" pour une raison quelconque,
  2. vous devez trier un conteneur ou des types de pointeur intégrés pour lequel vous ne pouvez pas surcharger les opérateurs.
  3. vous souhaitez trier la séquence en utilisant différentes commandes. ex: parfois vous voulez une structure avec les membres du prénom/nom triés par prénom, d'autres fois par nom de famille. deux fonctions différentes (ou foncteurs) rendent ces options triviales.
+1

Une autre option est de spécialiser 'std :: less' pour votre type. De cette façon, vous n'avez pas besoin de passer le foncteur à chaque fois (par exemple parce qu'il y a vraiment une définition raisonnable), et pourtant votre type n'a pas 'operator <'. –

+0

type_is_less peut également être un "objet fonction" (un objet surchargeant l'opérateur()) – newacct

+1

Cela a un défaut sérieux en ce que 'operator <' n'est pas 'const'. Cela signifie que cela ne fonctionnera pas pour le code qui considère le côté gauche de la constante de comparaison. (BTW, je l'ai vu si souvent mal, cela suffit à eux seuls pour rendre ces opérateurs globaux, beaucoup moins de gens se trompent ainsi.) Bien sûr, il y a d'autres raisons aussi.) – sbi

3

Il y a trois façons de le faire:

Vous pouvez surcharger operator< pour votre classe:

bool operator<(const MyType& lhs, const MyType& rhs) {return lhs.a<rhs.a;} 

Ceci a pour inconvénient que, si jamais vous voulez les trier selon b, vous Je n'ai pas de chance. Vous pouvez également vous spécialiser std::less pour votre type. Cela fait std::sort de travail (et d'autres choses, comme l'utilisation du type comme une clé dans une carte) sans détourner operator< pour cette signification. Cependant, il détourne toujours une syntaxe de comparaison générale pour a, alors que vous pourriez, à d'autres endroits dans votre code, comparer votre type selon b.

Ou vous pouvez écrire votre propre comparateur comme ceci:

struct compare_by_a { 
    bool operator()(const MyType& lhs, const MyType& rhs) const 
    {return lhs.a<rhs.a;} 
}; 

(Note:.. Le const après que l'opérateur ne soit pas strictement nécessaire, je considère encore un bon style, cependant) Ce laisse le général- but, moyen de comparaison indéfini; donc, si un code veut les utiliser sans que vous le sachiez, la compilation émet une erreur et vous en informe. Vous pouvez utiliser ce comparateur ou d'autres comparateurs de manière sélective et explicite lorsque vous avez besoin d'une comparaison.

Questions connexes