2010-08-20 5 views
2

J'ai un vecteur de classes de conteneurs commandés où je dois connaître l'indice du conteneur qui a un élément donnéprédicat stl avec différents types

, je voudrais faire ce qui suit, mais évidemment n » t travail. Je pourrais créer un conteneur factice pour héberger la date à trouver, mais je me demandais s'il y avait une meilleure façon.

struct FooAccDateComp 
{ 
    bool operator()(const Container& d1, const MyDate& f1) const 
    { return d1->myDate < f1; } 
}; 

class Container 
{ 
    MyDate myDate; 
    ... 
}; 

vector<Container> mystuff; 
MyDate temp(2008, 3, 15); 

//add stuff to variable mystuff 

int index = int(upper_bound(events.begin(), events.end(),temp, FooAccDateComp())-events.begin()); 

EDIT: La classe conteneur peut contenir d'autres dates.

+1

Modifiez upper_bound à find_if, et cela devrait fonctionner correctement. Cela dit, pourquoi n'utilisez-vous pas une carte ici? –

+0

@Billy: un vecteur trié peut être plus rapide qu'une carte, si vous ne le changez pas très souvent. –

+2

@Billy: les complexités sont très différentes, 'upper_bound' est O (log N) alors que' find_if' est O (N). –

Répondre

4

upper_bound doit être en mesure d'évaluer des expressions comme Comp(date,container), mais vous avez seulement fourni Comp(container,date). Vous devrez fournir à la fois:

struct FooAccDateComp 
{ 
    bool operator()(const Container& c, const MyDate& d) const 
     { return c.myDate < d; } 

    bool operator()(const MyDate& d, const Container& c) const 
     { return d < c.myDate; } 
}; 

Rappelez-vous que le vecteur doit être triée selon cette comparaison pour upper_bound et les amis de travailler.

+1

Gasp, vous avez été plus rapide: p Je voulais juste ajouter que 'upper_bound' ne renvoie pas forcément' Container' avec la date donnée, il renvoie le premier élément avec une date égale à OU PLUS GRAND. Vous aurez besoin de tester, par la suite, si vous avez atteint la fin et (si ce n'est pas le cas) si la date est effectivement ce que vous vouliez (il n'y a peut-être pas de conteneur dans le vecteur). –

+0

J'ai essayé cela et il se plaint toujours de ne pas être en mesure de "convertir le paramètre 2 de Const Container & à const Date &". J'utilise VS2008. Cela fonctionne-t-il de votre côté? Je suis d'accord il semble que cela devrait fonctionner – Steve

+0

@Steve: J'ai fait un test rapide avec GCC avant de répondre, et tout allait bien. Je n'ai pas de copie de VS disponible, j'en ai peur. –

1

Vous n'avez pas nécessairement besoin d'un prédicat spécial, il vous suffit d'activer la comparaison entre Container et MyDate.

#include <vector> 

struct MyDate { 
    MyDate(int, int, int); 
}; 

struct Container { 
    MyDate myDate; 
}; 

// enable comparison between Container and MyDate 
bool operator<(Container const&, MyDate const&); 
bool operator==(Container const&, MyDate const&); 

std::vector<Container> v; 
//add stuff to variable mystuff 
MyDate temp(2008, 3, 15); 
std::vector<Container>::iterator i = std::lower_bound(v.begin(), v.end(), temp); 
ptrdiff_t index = i != v.end() && *i == temp ? i - v.begin() : -1; 
+1

Un prédicat dédié est beaucoup mieux, vraiment. Considérons le cas où vous avez plusieurs dates dans le 'Container', avec lequel compareriez-vous? –

+0

Ajoutez de la complexité uniquement si vous en avez besoin. Dans cet exemple, cela semble inutile. –

+0

il y a effectivement d'autres dates dans le conteneur. Je vais mettre à jour la question – Steve

0

Vous pouvez utiliser find_if si vous ne me dérange pas dégrader les performances (vous avez dit que vous avez un vecteur de tri Container, donc la recherche binaire serait plus rapide) Ou vous pouvez ajouter

struct Container { 
    MyDate myDate; 
    operator MyDate() {return myDate}; 
} 
bool operator <(MyDate const&, MyDate const&) 
{ 
    return // your logic here 
};  

maintenant, vous pouvez utiliser les fonctions de recherche binaires

std::vector<Container>::iterator i = std::upper_bound(v.begin(), v.end(), MyDateObject);

Certes, il ne fonctionnera que si votre vecteur est triée par Container.myDate

+1

Je suppose que vous voulez dire 'opérateur MyDate()'. Il est généralement préférable d'éviter les opérateurs de conversion si vous le pouvez; ils peuvent masquer les erreurs qui seraient autrement interceptées par le compilateur. En outre, cela donne une copie inutile sur chaque comparaison. –

+0

Ouais, ma mauvaise. Cela aurait certainement dû être 'operator MyDate()'. Fixé. Merci de pointer ça – a1ex07

0

Votre exemple est brisée de plusieurs façons triviales: la classe Container doit être défini avant FooAccDateComp afin qu'il soit utilisé là-bas, vous devriez faire myDate un membre public Container, accès à ce membre dans la méthode de comparaison à l'aide plutôt que ->myDate, et enfin décider d'appeler votre vecteur mystuff ou events, mais ne pas mélanger les deux. Je suppose que les corrections appropriées ont été faites.

Vous devez avoir défini votre fonction de comparaison pour prendre en paramètre un paramètre Date en tant que premier argument et un paramètre Container en second; le contraire de ce que vous avez fait. Ou vous pouvez utiliser std::lower_bound au lieu de std::upper_bound si cela vous convient (puisque vous ne dites pas ce que vous allez faire avec index il est difficile de dire) que le choix fait dans la question est adapté à cela. Contrairement à ce que dit la réponse actuellement acceptée, vous n'avez pas besoin des deux si vous n'utilisez que std::upper_bound ou seulement std::lower_bound (bien que vous ayez besoin des deux si vous utilisez std::equal_range, ou si vous utilisez à la fois std::upper_bound et std::lower_bound).

Vous pouvez les trouver à première vue un peu étranges spécifications dans la norme, mais il y a un moyen de comprendre sans regarder pourquoi ils doivent être comme ça.Lorsque vous utilisez lower_bound, vous souhaitez trouver le point qui sépare les Container entrées qui sont (strictement) inférieures à votre Date donné de celles qui ne sont pas, et cela nécessite d'appeler la fonction de comparaison avec cet argument Date en deuxième position. Si toutefois vous demandez un upper_bound (comme vous êtes), vous voulez trouver le point qui sépare les entrées qui ne sont pas strictement plus plus que votre donné Date de ceux qui sont, et cela nécessite l'appel de la fonction de comparaison avec cet argument Date en première position (et inversant le résultat booléen, il revient). Et pour equal_range vous avez bien sûr besoin des deux possibilités.

Questions connexes