problème de parcours de map

Le
MGN
Bonsoir,
J'ai des map du type
std::map<objet*,objet*,foncteur>
où le foncteur varie (le type des objets aussi, mais ça ne change rien à la
définition de la map).
Je cherche à parcourir (uniquement parcourir, pas modifier) une map de ce
type sans connaître le foncteur qui a été utilisé pour le tri, ie quelque
chose du type :

std::map<objet*,objet*,foncteur> x;
std::map<objet*,objet*>::iterator it;
for(it=x.begin();it!=x.end();++it) {}

Evidement, cette syntaxe ne marche pas. Quelqu'un sait comment faire ?
Merci à vous
Marc
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 3
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Fabien LE LEZ
Le #20107511
On Thu, 10 Sep 2009 00:50:32 +0200, "MGN"
J'ai des map du type
std::map<objet*,objet*,foncteur>
où le foncteur varie



"std::map <T, T, machin>" et "std::map <T, T, truc>" sont deux types
différents, tout comme "std::string" et "int" sont deux types
différents.

Si tu veux une fonction qui accepte en paramètre plusieurs types
différents, il te faut un template :

template <class Map> void f (Map const& m)
{
for (Map::const_iterator i= m.begin(); i != m.end(); ++i)
{
// faire quelque chose
}
}

Si tu veux t'assurer que seul un std::map<objet*,objet*,?> sera
accepté par la fonction :

template <class Foncteur> void f
(std::map<objet*,objet*,Foncteur> const& m)
{
for (Map::const_iterator i= m.begin(); i != m.end(); ++i)
{
// faire quelque chose
}
}
Fabien LE LEZ
Le #20107501
J'ai écrit :

template <class Foncteur> void f
(std::map<objet*,objet*,Foncteur> const& m)



Pour des raisons de cohérence, il vaut peut-être mieux remplacer
"Foncteur" par "Compare" ici. Mais bon, ça ne change rien au
fonctionnement du code.
James Kanze
Le #20109051
On Sep 10, 1:04 am, Fabien LE LEZ
On Thu, 10 Sep 2009 00:50:32 +0200, "MGN"


>J'ai des map du type
>std::map<objet*,objet*,foncteur>
>où le foncteur varie



"std::map <T, T, machin>" et "std::map <T, T, truc>" sont deux
types différents, tout comme "std::string" et "int" sont deux
types différents.



Ce qu'on pourrait considérer un défaut de conception dans la
STL. Bien que...

Si tu veux une fonction qui accepte en paramètre plusieurs
types différents, il te faut un template :



template <class Map> void f (Map const& m)
{
for (Map::const_iterator i= m.begin(); i != m.end(); ++i)
{
// faire quelque chose
}
}



Si tu veux t'assurer que seul un std::map<objet*,objet*,?>
sera accepté par la fonction :



template <class Foncteur> void f
(std::map<objet*,objet*,Foncteur> const& m)
{
for (Map::const_iterator i= m.begin(); i != m.end(); ++i)
{
// faire quelque chose
}
}



Ce qui manque de souplesse. Si ça suffit à MGN, bien ; c'est
certainement la solution la plus simple. Mais ça signifie qu'à
un endroit donné dans le code, c'est toujours le même type de
map qui sert (et que le compilateur sache ce type) . Sinon,
c'est tout à fait possible de faire des maps avec des
comparateurs différents, mais avec le même type. À la place d'un
objet fonctionnel pour le comparateur, il suffit d'utiliser une
fonction :
typedef std::map< Object*, Object*, bool cmp( Object*, Object* ) >
Map ;
Du coup, on spécifie le comparateur lors de la construction, et
tous les map ont le même type. (On pourrait aussi utiliser un
objet fonctionnel unique qui se sert du modèle lettre/enveloppe
pour le polymorphisme, mais c'est plus compliqué.)

--
James Kanze
MGN
Le #20109231
> À la place d'un
objet fonctionnel pour le comparateur, il suffit d'utiliser une
fonction :
typedef std::map< Object*, Object*, bool cmp( Object*, Object* ) >
Map ;
Du coup, on spécifie le comparateur lors de la construction, et
tous les map ont le même type.



excuse-moi, je ne vois pas de différence avec un foncteur...la fonction
"définit" le type de map

(On pourrait aussi utiliser un
objet fonctionnel unique qui se sert du modèle lettre/enveloppe
pour le polymorphisme, mais c'est plus compliqué.)



oui, j'avais pensé à cette solution, mais j'ai peur de diminuer les
performances...

=> j'ai une solution qui va faire hurler :-())
je fais un reinterpret_cast de std::map<objet*,objet*,foncteur> en
std::map<objet*,objet*> et je parcours la map castée avec un
std::map<objet*,objet*> ::iterator.
Tant que je n'utilise l'iterateur qu'à des fins de visualisation, ie sans
modifier la map, il n'y a aucun risque....
Qu'en pensez-vous ?
(j'ajoute qu'il n'y a que 3 lignes de code concernées et que la performance
est importante)
Merci
Marc
Mickaël Wolff
Le #20109871
MGN a écrit :

excuse-moi, je ne vois pas de différence avec un foncteur...la fonction
"définit" le type de map


La différence c'est que le foncteur est un objet, alors que James te
proposes de ne fournir qu'un pointeur sur une fonction. Du coup, même si
tu changes la fonction, le type de map sera le même.

=> j'ai une solution qui va faire hurler :-())
je fais un reinterpret_cast de std::map<objet*,objet*,foncteur> en
std::map<objet*,objet*> et je parcours la map castée avec un
std::map<objet*,objet*> ::iterator.


J'ai coupé des orties fraîches récemment, tu en veux ? :D

Tant que je n'utilise l'iterateur qu'à des fins de visualisation, ie
sans modifier la map, il n'y a aucun risque....
Qu'en pensez-vous ?
(j'ajoute qu'il n'y a que 3 lignes de code concernées et que la
performance est importante)



Pourquoi ne fais-tu pas un typedef comme James le proposes ?

typedef std::map<objet*,objet*,foncteur> Map ;
Map x;
for(Map::iterator it = x.begin() ; it != x.end() ; ++it) {}

--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org
Michael Doubez
Le #20110701
On 10 sep, 11:25, "MGN" [snip]
=> j'ai une solution qui va faire hurler :-())
je fais un reinterpret_cast de std::map<objet*,objet*,foncteur> en
std::map<objet*,objet*> et je parcours la map castée avec un
std::map<objet*,objet*> ::iterator.
Tant que je n'utilise l'iterateur qu'à des fins de visualisation, ie sa ns
modifier la map, il n'y a aucun risque....



Il y a le risque que le cast ne marche pas car map<> stoque l'objet de
comparaison donc le layout memoire rique de ne pas être le même (et
d'ailleur il ne l'est sûrement pas).

Par exemple dans gcc 3.4.3, l'objet de comparaison "_Compare comp;"
est stocké avant la racine de la map "_Rep_type _M_t;". Il y a peu de
chance que le stockage soit au même offset.

Qu'en pensez-vous ?
(j'ajoute qu'il n'y a que 3 lignes de code concernées et que la perform ance
est importante)



La solution de James Kanze: les types sont les mêmes, seule
l'initialisation de la fonction de comparaison change.

--
Michael
Michael Doubez
Le #20110691
On 10 sep, 00:50, "MGN"
Bonsoir,
J'ai des map du type
std::map<objet*,objet*,foncteur>
où le foncteur varie (le type des objets aussi, mais ça ne change rie n à la
définition de la map).
Je cherche à parcourir (uniquement parcourir, pas modifier) une map de ce
type sans connaître le foncteur qui a été utilisé pour le tri, ie quelque
chose du type :

std::map<objet*,objet*,foncteur> x;
std::map<objet*,objet*>::iterator it;
for(it=x.begin();it!=x.end();++it) {}

Evidement, cette syntaxe ne marche pas. Quelqu'un sait comment faire ?



La question qui se pose est : comment se fait-il que tu ne connaisses
pas le type du foncteur. Si tu as le type T de x alors T::iterator est
l'itérateur.

Si tu peux mettre ton traitement dans un fonctor qui prend en
paramètre un:
std::pair<objet*,objet*> (T::value_type de son petit nom) alors tu
peux faire:

struct Fonction
{
void operator()(const std::pair<objet*,objet*>& entry)const
{
// operation
}
}

Puis:
std::for_each(x.begin(),x.end(),Fonction());

Si tu as besoin de stocker des résultats, passes des pointeurs à
Fonction().

--
Michael
Michael Doubez
Le #20110791
On 10 sep, 14:12, Michael Doubez [snip]
Si tu peux mettre ton traitement dans un fonctor qui prend en
paramètre un:
std::pair<objet*,objet*> (map<>::value_type de son petit nom)



Oups, en fait:
std::pair<const objet*,objet*>

Puisque la clé est const.

alors tu peux faire:

struct Fonction
{
   void operator()(const std::pair<const objet*,objet*>& entry)const
   {
      // operation
   }

}

Puis:
std::for_each(x.begin(),x.end(),Fonction());

Si tu as besoin de stocker des résultats, passes des pointeurs à
Fonction().




--
Michael
MGN
Le #20111661
> La solution de James Kanze: les types sont les mêmes, seule
l'initialisation de la fonction de comparaison change.


ok, merci
bon, je suis un peu neuneu (j'utilise toujours des foncteurs en fait)
=> Je voudrais savoir si c'est bien comme ça qu'il faut procéder :

bool ordre_croissant(int* a,int* b) { return *a<*b; }
bool ordre_decroissant(int* a,int* b) { return *b<*a; }

std::map<int*,std::string*,bool(*)(int*,int*)> x;
x.comp=ordre_decroissant;

x[new int(0)]=new std::string("zéro");
x[new int(1)]=new std::string("un");
x[new int(2)]=new std::string("deux");

Ma question : y-a-t-il un moyen de lier la fonction de comparaison à x lors
de la déclaration de x ?
Merci à vous
James Kanze
Le #20114311
On Sep 10, 11:25 am, "MGN"
> À la place d'un
> objet fonctionnel pour le comparateur, il suffit d'utiliser
> une fonction :
> typedef std::map< Object*, Object*, bool cmp( Object*, Object* ) >
> Map ;
> Du coup, on spécifie le comparateur lors de la construction,
> et tous les map ont le même type.



excuse-moi, je ne vois pas de différence avec un foncteur...la
fonction "définit" le type de map



The type of a pointer to function will be « bool (*)( Object*,
Object* ) », égal ce que fait la fonction. Le type d'un objet
fonctionnel, c'est le type de l'objet, qui est (typiquement)
différent pour chaque fonction.

> (On pourrait aussi utiliser un objet fonctionnel unique qui
> se sert du modèle lettre/enveloppe pour le polymorphisme,
> mais c'est plus compliqué.)



oui, j'avais pensé à cette solution, mais j'ai peur de
diminuer les performances...



S'il te faut une indirection, il te faut une indirection. Il n'y
a pas 36 mille solutions.

=> j'ai une solution qui va faire hurler :-())
je fais un reinterpret_cast de std::map<objet*,objet*,foncteur> en
std::map<objet*,objet*> et je parcours la map castée avec un
std::map<objet*,objet*> ::iterator.



Tu as un comportement indéfini. Qui, je crois, provoquera des
core dump sur certaines implémentations.

Tant que je n'utilise l'iterateur qu'à des fins de
visualisation, ie sans modifier la map, il n'y a aucun
risque....



Sauf que l'itérateur peut partir du principe que les éléments
sont dans l'ordre.

Qu'en pensez-vous ?



Que ce n'est pas une bonne idée.

--
James Kanze
Publicité
Poster une réponse
Anonyme