Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

problème de parcours de map

24 réponses
Avatar
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

10 réponses

1 2 3
Avatar
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.

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
}
}
Avatar
Fabien LE LEZ
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.
Avatar
James Kanze
On Sep 10, 1:04 am, Fabien LE LEZ wrote:
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
Avatar
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

(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
Avatar
Mickaël Wolff
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
Avatar
Michael Doubez
On 10 sep, 11:25, "MGN" wrote:
[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
Avatar
Michael Doubez
On 10 sep, 00:50, "MGN" wrote:
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
Avatar
Michael Doubez
On 10 sep, 14:12, Michael Doubez wrote:
[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
Avatar
MGN
> 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
Avatar
James Kanze
On Sep 10, 11:25 am, "MGN" wrote:
> À 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
1 2 3