IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Créer une map avec un type comme clé


Sujet :

C++

  1. #1
    Membre expérimenté
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 824
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 824
    Points : 1 544
    Points
    1 544
    Par défaut Créer une map avec un type comme clé
    Bonjour,


    J'aimerai savoir s'il était possible de faire un dictionnaire prenant en clé un type.
    En effet, j'ai un module qui doit référencer certaines classes et leur attribuer un nom.

    Par exemple :
    CClient = "clients"
    CVoitures = "voitures"

    Dans mon module j'aimerai retrouver la valeur par ce genre d'instruction :
    std::string sCode = maMap[CClient];

    Est-ce que c'est possible ?


    Merci beaucoup,

    A bientôt
    "Heureusement qu'il y avait mon nez, sinon je l'aurais pris en pleine gueule" Walter Spanghero

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Points : 1 053
    Points
    1 053
    Par défaut
    Et bien je dirais que tu as soit la solution facile avec une map<string,string> :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::string sCode = maMap["CClient"];
    Ou alors il y a des solutions plus évoluées mais aussi bien plus complexes à base de méta programmation.

    Il est peut-être aussi possible d'utiliser une astuce à base de valeur de retour de type_info(), mais je perso je ne recommanderais pas une telle bidouille.

  3. #3
    Membre expérimenté
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 824
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 824
    Points : 1 544
    Points
    1 544
    Par défaut
    Oui là justement ça reste une chaîne de caractère la clé.

    Il y a quoi comme solution ? Est-ce que il faut regarder du côté des typelist ?
    "Heureusement qu'il y avait mon nez, sinon je l'aurais pris en pleine gueule" Walter Spanghero

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Points : 1 053
    Points
    1 053
    Par défaut
    Oui, c'est à ça que je pensais.
    L'ennui c'est que, d'une part, il est probable que tu doives te refaire ta propre typelist spécialisée à partir de rien. Ensuite, le stockage des chaines de caractères en tant que paramètre template ce n'est pas simple. Je crois que Boost contient quelque chose pour simplifier ça (si ça dit quelque chose à un lecteur...).

    Edit: je viens de penser à quelque chose de plus simple, à base de classes de traits:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template<class A>
    struct classname {
       static const char* name="unknown";
    };
     
    template<>
    struct classname<machin> {
       static const char* name="machin";
    }
     
    ...
    Quelques macros par dessus ça et ça devrait être fonctionnel (quoique, je suis pas certain que des const char* en static ça passe correctement écrit comme ça)

    Edit2: Effectivement non, par contre de cette façon c'est bon:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    template<class A>
    struct classname {
    	static string name() {
    		return "unknown";
    	}
    };
     
    template<>
    struct classname<machin> {
       static string name() {
    	   return "machin";
    	}
    };

  5. #5
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    Et pourquoi pas des const std::string à la place de ces const char* ?
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  6. #6
    Membre expérimenté
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 824
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 824
    Points : 1 544
    Points
    1 544
    Par défaut
    Ok, merci beaucoup,

    Je vais faire quelques recherches et tester 2-3 trucs.

    Merci
    "Heureusement qu'il y avait mon nez, sinon je l'aurais pris en pleine gueule" Walter Spanghero

  7. #7
    Membre éprouvé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Points : 1 053
    Points
    1 053
    Par défaut
    Encore moins, j'avais un doute sur const char* mais avec une classe je suis certain que ça ne passera jamais sans définir quelque chose dans le cpp.

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Tout type capable d'apporter une réponse à une comparaison de type "plus petit que" peut être utilisé comme clé.

    Le tout, est qu'il faudra sans doute prévoir un foncteur permettant de mettre cette comparaison en oeuvre.

    Le cas échéans, tu pourrais même tout à fait envisager un comportement polymorphique grâce à une arborescence correcte.

    Ainsi, une classe proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class MaCle
    {
        public:
            MaCle(/*paramètres éventuels */);
            /*virtual */ ~MaCle();
            struct less
            {
                bool operator()(const MaCle& c1, const MaCle& c2)
                {
                    /* toute la logique permettant de déterminer c1<c2 */
                }
            };
            /* il peut y avoir d'autres méthodes */
        private:
            /* les membres de la classe */
    },
    pourra sans aucun problème être utilisé comme clé dans une std::map.

    Elle sera utilisée sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::map<MaCle, objetGere, MaCle::less > lamap;
    et tu pourrais tout à fait effectuer une recherche sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if( lamap.find(MaCle(/* paramètres nécessaires */)!=lamap.end())
    {
        /*l'objet existe dans la map */
    }
    ou, si tu préfère l'écriture "conventionnelle":
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    MaCle tofind/* (paramètres nécessaires) */;
    if(lamap.find(tofind) != lamap.end())
    {
        /* bla, bla bla */
    }
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #9
    Membre éprouvé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Points : 1 053
    Points
    1 053
    Par défaut
    Koala, il ne parlait pas d'associer des instances d'un type à des chaines de caractères, mais directement des types à des chaines de caractères, ce qui n'est pas à proprement parler une donnée et n'est pas utilisable avec std::map.

  10. #10
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Au temps pour moi... j'avais effectivement mal compris le sens de la question.

    Ceci dit, il reste malgré tout parfaitement possible de s'en sortir, pour autant de partir sur un héritage appelé de réalisation:

    L'idée est simple: plutôt que de rajouter des membres à une classe de base dans une classe dérivée, on veille à ce que tous les membres utiles se trouvent dans la classe de base - de manière à éviter les problèmes de perte d'informations si une classe dérivée se fait passer pour une classe de base - et à spécialiser tout simplement le constructeur.

    En effet, le polymorphisme au niveau de la clé doit être résolu à l'utilisation, et non à la compilation (ce qui disqualifie l'utilisation des template, du moins pour la classe de base).

    Ce n'est pas "très orthodoxe", mais tu pourrais envisager une arborescence proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    class MaCle
    {
        public:
            MaCle(size_t mtype): mtype(mtype){}
            ~MaCle(){}
            /* le prédicat permettant de comparer deux éléments de type MaCle 
             * est à rajouter ;) */
        private:
            size_t mtype;
    };
    class CClient : public MaCle
    {
        public:
            CClient():MaCle(1){}
    };
    class CVoiture : public MaCle
    {
        public:
            CVoiture():MaCle(2){}
    };
    /* et tous les autres types qu'il faudrait utiliser comme clé */
    La déclaration du tableau associatif s'effectuerait sous une forme proche de
    std::map<MaCle, std::string> lamap;
    Les méthodes d'ajout et de recherche de la chaine de caractères correspondante seraient classique:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void MonContener::insert(const MaCle& c, const std::string& str)
    {
        lamap.insert(std::make_pair(c,str));
    }
    const std::string& MonContener::find(const MaCle & c)
    {
        std::map<MaCle,std::string>::iterator it=lamap.find(c);
        if(it==lamap.end())
        {
            /* prévoir le cas où l'élément n'est pas trouvé... */
        }
        return (*it).second;
    }
    et les appels pourraient s'effectuer sous une forme proche de
    MonConteneur ct;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    /*...*/
    ct.insert(CVoiture(),"voiture");
    ct.insert(CClient(),"client");
    /*...*/
    std::string str=ct.find(CClient());
    std::string str2=ct.find(CVoiture());
    et le tout fournirait le comportement recherché

    Mais, l'un dans l'autre, je me dis qu'il serait surement plus intéressant encore d'utiliser de préférence une énumération (par exemple) comme clé...

    Il est, en effet, facile de fournir une méthode qui renvoie une telle valeur à toutes les classes qui en ont besoin (sans qu'elles soient forcément liées par un héritage commun), et, par voie de conséquence, de récupérer la chaine de caractères qui correspond
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #11
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Ce que tu veux c'est une simple correspondance type -> chaîne.
    Or une correspondance type -> quelque chose, ça s'obtient tout simplement avec des classes templates spécialisées.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    template<typename T>
    struct name
    {
    };
     
    template<>
    struct name<Type1>
    {
        // exposition de la chaîne d'une manière ou d'une autre
    };
     
    etc.
    Boost ftw

  12. #12
    Membre expérimenté
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 824
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 824
    Points : 1 544
    Points
    1 544
    Par défaut
    Merci beaucoup à vous,

    Je vais prendre la solution de Loufoque.

    Merci
    "Heureusement qu'il y avait mon nez, sinon je l'aurais pris en pleine gueule" Walter Spanghero

  13. #13
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut
    Citation Envoyé par loufoque Voir le message
    Ce que tu veux c'est une simple correspondance type -> chaîne.
    Or une correspondance type -> quelque chose, ça s'obtient tout simplement avec des classes templates spécialisées.
    Que l'on appelle classes de traits. (voir FAQ C++ du site et Modern C++ Design pour approfondir)

    Pour info, ne te lances pas la-dedans si tu veux faire du 'dynamique' car il faut que le type de la classe soit explicitement écrit dans le code pour que cela fonctionne (par explicitement, je compte aussi les instanciations de template ou T est remplacé). Mais peut-être veux-tu juste faire du statique ?

    Peux-tu nous dire comment sera utilisé ton dictionnaire dans le code ?

  14. #14
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    NiamorH >> n'oublie pas aussi l'article de Alp sur les traits et politiques.
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  15. #15
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut
    Alp sait déjà que j'ai une dent contre lui

Discussions similaires

  1. [Google Maps] Créer une map Google avec plusieurs marqueurs
    Par Prodiguy dans le forum APIs Google
    Réponses: 1
    Dernier message: 03/05/2013, 18h21
  2. Réponses: 2
    Dernier message: 18/11/2011, 16h57
  3. Réponses: 3
    Dernier message: 29/09/2009, 12h06
  4. créer une table avec des colonnes de types différents
    Par d_hazem dans le forum Composants
    Réponses: 1
    Dernier message: 15/01/2009, 15h23
  5. Réponses: 1
    Dernier message: 18/04/2007, 23h02

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo