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 :

enum dont les champs sont des noms de type


Sujet :

C++

  1. #1
    Membre régulier
    Homme Profil pro
    Développeur du dimanche
    Inscrit en
    Février 2013
    Messages
    154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur du dimanche

    Informations forums :
    Inscription : Février 2013
    Messages : 154
    Points : 107
    Points
    107
    Par défaut enum dont les champs sont des noms de type
    Bonjour,

    Aujourd'hui, en C++, j'aimerais faire quelque chose d'un peu foufou.

    J'ai une template struct Test :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template <typename...Ts>
    struct Test
    {
     
    };
    Je voudrais que pour chaque instance de Test, un enum soit créé à l'intérieur de la structure, avec comme champs le nom des types rentrés en template. Hum hum. Un exemple sera plus parlant.

    Du coup, une instance comme ceci...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Test<chat,chien,cheval> test;
    ...créerait un enum comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    enum
        {
            chat,
            chien,
            cheval
        }
    L'objectif, c'est ensuite de faire une fonction template dans ma structure, qui me renverrait à quelle position se trouve le type :

    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
    template <typename...Ts>
    struct Test
    {
    enum
        {
            chat,
            chien,
            cheval
        }
     
        template <typename T>
        unsigned test()
        {
            // on récupère le nom de T, et avec ça on pioche dans l'enum
        }
    };
     
    std::cout<<test.test<chien>(); // affiche 1, parce que chat(0) chien(1) cheval(2)
    J'arrive déjà à faire ça avec une unordered_map<std::type_index,unsigned> mais ça ne me convient pas trop, c'est très lent.

  2. #2
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    745
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 745
    Points : 3 660
    Points
    3 660
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    template<Enum E>
    static unsigned test()
    { return E; }


    J'ai quand même l'impression que l'exemple ne correspond pas à l'énoncé.

    Si le but est de créer une enum + une fonction de correspondance type -> valeur ou nom -> valeur, la méta-prog ne te sera pas utile: c'est impossible.
    Par contre, il est possible de faire des macros qui créeront l'ensemble. Boost.preprocessor devrait beaucoup aider. Si c'est juste une énumération continue (sans spécifier de valeurs) alors cela devrait se faire en moins d'une centaine de ligne.

    Il y a quelques années, j'avais fait un truc du genre. À l'époque, je n'avais pas d'idée pour gérer convenablement les valeurs aléatoires, à la place, il y a des options pour les configurer: valeur de départ, incrémentation par saut, décalage binaire. L'ensemble est trop compliqué et même pas pédantic à cause d'une variadic vide -_-. Un jour, je referais.
    Si cela t'inspire. Le fichier de tests (j'ai dû commenter pour trouver une erreur de compilation et oublié de décommenter).

  3. #3
    Membre régulier
    Homme Profil pro
    Développeur du dimanche
    Inscrit en
    Février 2013
    Messages
    154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur du dimanche

    Informations forums :
    Inscription : Février 2013
    Messages : 154
    Points : 107
    Points
    107
    Par défaut
    J'ai quand même l'impression que l'exemple ne correspond pas à l'énoncé.
    Non

    Merci pour ta réponse, je vais regarder du côté de boost preprocessor, alors.

    J'en profite pour reformuler mon objectif : en fait, je peux encore simplifier.

    J'ai une array de strings :

    std::string array[3] = {"chat","chien","cheval"};

    J'aimerais créer un enum à partir de array, pour pouvoir ensuite utiliser chat pour 0, chien pour 1, cheval pour 2.

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 128
    Points : 33 041
    Points
    33 041
    Billets dans le blog
    4
    Par défaut
    Salut,

    avec une macro tu devrais pouvoir t'en sortir, mais pas avec des strings pour le créer.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define MYENUM(Name, ...) struct Name { enum { __VA_ARGS__ }; static std::string GetConcat() { return #__VA_ARGS__; } }
    Ensuite pour tester si ta string a une valeur dans l'enum, qqch comme ça devrait marcher
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template< class EnumName > bool Exists(const std::string& value)
    {
      std::string enumList = EnumName::GetConcat();
      std::vector<std::string> values = Split(enumList, ',');
      for (int i = 0; i < values.size() ++i)
        if (values[i] == value)
          return true;
      return false;
    }
    Ca ferait une utilisation proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    MYENUM(Animals, chat, chien, cheval);
    assert(Exists(Animals, "chat"));
    assert(!Exists(Animals, "perruche"));

  5. #5
    Membre régulier
    Homme Profil pro
    Développeur du dimanche
    Inscrit en
    Février 2013
    Messages
    154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur du dimanche

    Informations forums :
    Inscription : Février 2013
    Messages : 154
    Points : 107
    Points
    107
    Par défaut
    Bon j'ai pas mal trituré ton code dans tous les sens, tu me fais découvrir un aspect des macros que je ne connaissais pas, c'est génial

    Par contre, il me vient une question. Est-il possible de passer les arguments d'un variadic template dans les arguments d'un variadic macro ? Quelque chose du style :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #define bar(...) std::cout<<#__VA_ARGS__;
     
    template <typename...Ts>
    void foo()
    {
        bar(Ts);
    }
     
    int main()
    {
        foo<int,char,bool>();
    }
    J'aimerais que foo() m'affiche "int,char,bool", pour l'instant elle m'affiche "Ts"

  6. #6
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par MrPchoun Voir le message
    Est-il possible de passer les arguments d'un variadic template dans les arguments d'un variadic macro ?
    les macros sont traités bien avant les templates
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #define bar(...) std::cout<<#__VA_ARGS__;
     
    template <typename...Ts>
    void foo()
    {
        bar(Ts);
    }
     
    int main()
    {
        foo<int,char,bool>();
    }
    Après expansion des macros, devient
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #define bar(...) std::cout<<#__VA_ARGS__;
     
    template <typename...Ts>
    void foo()
    {
        std::cout<<"Ts";
    }
     
    int main()
    {
        foo<int,char,bool>();
    }
    Les macros et templates sont durs à mélanger
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    #define bar(...) std::cout<<#__VA_ARGS__;
    int main() {
        bar(int,char,bool);
    }

  7. #7
    Membre régulier
    Homme Profil pro
    Développeur du dimanche
    Inscrit en
    Février 2013
    Messages
    154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur du dimanche

    Informations forums :
    Inscription : Février 2013
    Messages : 154
    Points : 107
    Points
    107
    Par défaut
    Les macros et templates sont durs à mélanger.
    Il est pourtant possible de faire l'inverse de ce que je cherche à faire, de passer les arguments d'un macro dans un template :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template <typename...Ts>
    void bar() {}
     
    #define foo(...) bar<__VA_ARGS__>();
     
    int main()
    {
        foo(int,char,bool);
    }
    Mais ça m'avance pas beaucoup tout ça

  8. #8
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    745
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 745
    Points : 3 660
    Points
    3 660
    Par défaut
    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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #include <boost/preprocessor/variadic/to_list.hpp>
    #include <boost/preprocessor/stringize.hpp>
    #include <boost/preprocessor/list/for_each.hpp>
    #include <boost/preprocessor/punctuation/comma.hpp>
     
    #include <initializer_list>
    #include <iostream>
     
    #define FOO_STRINGIZE(r, data, elem) , BOOST_PP_STRINGIZE(elem)
     
    #define foo(...) \
      bar<__VA_ARGS__>(0 \
        BOOST_PP_LIST_FOR_EACH(FOO_STRINGIZE, _, BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__)) \
      )
     
    #define UNPACK(...) (void(::std::initializer_list<char>{(void((__VA_ARGS__)), char())...}))
     
    template<class> using to_cstr_t = char const *;
     
    template<class... Ts>
    void bar(int, to_cstr_t<Ts>... cstrs)
    {
      unsigned i = 0;
      UNPACK(std::cout << ++i << ' ' << cstrs << "\n");
    }
     
     
    int main()
    {
      foo(char, int, bool);
    }

Discussions similaires

  1. Remplir table avec formulaire dont les champs sont liés
    Par christian.bedere dans le forum IHM
    Réponses: 7
    Dernier message: 03/11/2008, 18h00
  2. Réponses: 3
    Dernier message: 20/08/2007, 17h30
  3. Résultat exact division dont les membres sont des requêtes
    Par totoranky dans le forum Langage SQL
    Réponses: 2
    Dernier message: 07/08/2007, 14h51
  4. Tri alphabétique d'un TreeMap dont les clés sont des String
    Par Djakisback dans le forum Collection et Stream
    Réponses: 6
    Dernier message: 31/03/2006, 14h33
  5. fusionner 2 tables dont les champs sont identiques mais.....
    Par NoobX dans le forum SQL Procédural
    Réponses: 1
    Dernier message: 27/10/2005, 16h12

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