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

Langage C++ Discussion :

Un tableau de char* en paramètre template


Sujet :

Langage C++

  1. #1
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut Un tableau de char* en paramètre template
    Bonjour à tous,

    J'aimerais factoriser plusieurs classes de mon projet qui présentent une structure similaire.
    Voici à quoi elles ressemblent (en pseudo-code, pour être plus clair) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    struct access_specifier
    {
        enum type
        {
            PUBLIC,
            PROTECTED,
            PRIVATE
        };
     
        value value_;
    };
    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
     
    struct built_in_type_specifier
    {
        enum type
        {
            CHAR,
            WCHAR_T,
            BOOL,
            SHORT,
            INT,
            LONG,
            SIGNED,
            UNSIGNED,
            FLOAT,
            DOUBLE,
            VOID
        };
     
        type type_;
    };
    Afin de les factoriser, j'aimerais créer une classe template dans ce style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    template<const char** StringList>
    class string_enumeration
    {
        public:
            string_enumeration(const std::string& value);
     
            const char*
            get_value() const;
     
        private:
            static const char** string_list_; //on aura string_list_ = StringList
            int value_index_; //index dans le tableau de char*
    };
    Pour avoir un équivalent de access_specifier, on fera ceci (enfin, on aimerais bien faire ceci, justement ) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    const char* access_specifier_string_list[] = {"public", "protected", "private", ""};
     
    typedef string_enumeration<access_specifier_string_list> access_specifier;
    Ainsi, on créera un access_specifier de cette façon :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    access_specifier an_access_specifier("public");
    Si "public" ne fait pas partie de la liste de char*, on balancera une exception ou un assert… mais là n'est pas le problème. La classe va mémoriser l'index de la chaîne reçue (ici 0, puisque "public" est le premier élément de la liste de char*).
    L'appel à get_value() n'a plus qu'à renvoyer un pointeur vers la chaîne pointée par l'index.

    Le code semble se construire correctement, mais aucun binaire n'est linké. Lorsque j'essaie de construire une deuxième fois, gcc se résout à me tenir ce charmant discours :
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
     
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/qualified_identifier.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    make[2]: quittant le répertoire « /mnt/data/Développement/Socoa »
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    make[1]: quittant le répertoire « /mnt/data/Développement/Socoa »
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/member_declarator_bit_field_member.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/qualified_operator_function_id.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/direct_declarator_function_part.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/namespace_definition.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/cv_qualifier.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/identifier.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/member_declaration_member_declarator_list.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/qualified_nested_id.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/member_declaration_unqualified_id.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/function_definition.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/string_enumeration.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/class_specifier.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/qualified_template_id.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/nested_name_specifier_template_id_part.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/simple_declaration.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/simple_template_type_specifier.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/template_declaration.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/template_id.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/nested_identifier_or_template_id.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/member_declarator_declarator.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/direct_declarator_array_part.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/member_specification_access_specifier.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/member_declaration_function_definition.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/using_declaration.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree/built_in_type_specifier.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    CMakeFiles/socoa.dir/src/socoa/cpp/program_syntax_tree_to_string_converter.cpp.o:(.data.rel.local+0x0): multiple definition of `socoa::cpp::program_syntax_tree::access_specifier_string_list'
    CMakeFiles/socoa.dir/src/socoa/cpp/declaration_syntax_analyzer.cpp.o:(.data.rel.local+0x0): first defined here
    collect2: ld returned 1 exit status
    make[2]: *** [lib/Debug/libsocoa.so] Erreur 1
    make[1]: *** [CMakeFiles/socoa.dir/all] Erreur 2
    make: *** [all] Erreur 2
    Process terminated with status 2 (0 minutes, 10 seconds)
    0 errors, 0 warnings

    Dois-je m'en tenir à du polymorphisme dynamique pour effectuer cette factorisation ?

  2. #2
    Membre averti Avatar de Nogane
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    241
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 241
    Points : 323
    Points
    323
    Par défaut
    Bonjours,
    Non ça ne peu pas marcher car dans:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef string_enumeration<access_specifier_string_list> access_specifier;
    Il faut que access_specifier_string_list soit une expression constante. Un pointeur ne peut pas en être une car il sera initialisé a l'exécution.
    (Je ne suis pas sur sur alors arrêtez moi qui je dit des bêtises)

    Sans y avoir trop reflechit, je dirait que tu va devoir initialiser ta class string_enumeration a l'execution. Elle ne sera donc plus template.
    Pas besoin du polymorphisme si tu crée une fonction(design pattern Factory) qui te crée et remplit ton string_enumeration en fonction du type que tu lui demande.

    EDIT: Peut-etre que dans ce cas un vector<string> suffirait?

  3. #3
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    Citation Envoyé par Nogane Voir le message
    Un pointeur ne peut pas être une [expression constante] car il sera initialisé a l'exécution.
    Je ne pense pas, une adresse étant une valeur constante comme une autre.

    Citation Envoyé par Nogane Voir le message
    EDIT: Peut-etre que dans ce cas un vector<string> suffirait?
    J'ai fait mon premier essai avec un vector de string (je n'utilise les types à la C qu'en cas de force majeur). Malheureusement, GCC m'a jeté avec un simple "vector<string> ne peut pas être un paramètre template", ce qui est normal puisqu'on ne peut pas initialiser un vector à la compilation.
    J'espère que ce ne sera pas le cas avec les std::initialization_list, parce que je compte pas mal sur C++0x pour simplifier ce genre de galère.

    Bon, je retrouve un peu la raison en déplaçant la définition dans un .cpp comme il se doit.
    Le .h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    const char** access_specifier_string_list;
     
    typedef string_enumeration<access_specifier_string_list> access_specifier;
    Le .cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    access_specifier_string_list = {"public", "protected", "private", ""};
    Évidemment, ça ne compile pas puisque access_specifier_string_list n'est pas constant. J'ai juste copié ce code pour la pédagogie.


    Maintenant, j'ai essayé de rajouter un niveau de pointeur :
    Le .h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    const char** access_specifier_string_list_var;
    const char*** const access_specifier_string_list = &access_specifier_string_list_var;
     
    typedef string_enumeration<access_specifier_string_list> access_specifier;
    Le .cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    access_specifier_string_list_var = {"public", "protected", "private", ""};
    Mais maintenant le monsieur me dit que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    /mnt/data/Développement/Socoa/src/socoa/cpp/program_syntax_tree/access_specifier.h:33: error: ‘socoa::cpp::program_syntax_tree::access_specifier_string_list’ cannot appear in a constant-expression
    /mnt/data/Développement/Socoa/src/socoa/cpp/program_syntax_tree/access_specifier.h:33: error: template argument 1 is invalid
    /mnt/data/Développement/Socoa/src/socoa/cpp/program_syntax_tree/access_specifier.h:33: error: invalid type in declaration before ‘;’ token

  4. #4
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 861
    Points
    11 861
    Par défaut
    Un paramètre template est soit un type (lui-même template ou non) soit une expression connue à la compilation. Ce n'est pas ton cas, donc il va falloir contourner le "problème".

  5. #5
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    Justement, conceptuellement parlant, l'ensemble {"public", "protected", "private"} est connu à la compilation… pourquoi n'est-ce pas le cas en pratique ?

    Par ailleurs, je suis en train de compiler la svn de gcc 4.4 pour voir si std::initialization_list passerait.
    http://gcc.gnu.org/projects/cxx0x.html

  6. #6
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 861
    Points
    11 861
    Par défaut
    Tu peux passer un char, mais pas une séquence de char. C'est une conséquence des règles de la norme

    EDIT : à moins de faire MonTemplate<'a', 'b', 'c'>

  7. #7
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    [têtu]Oui, mais je peux passer un pointeur, n'est-ce pas ?[/têtu]

  8. #8
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 861
    Points
    11 861
    Par défaut
    Non.
    Un pointeur est une adresse mémoire. C'a un sens à la compilation tu penses ?

  9. #9
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Pour faire ce genre de choses, plutôt que les templates, je te conseille de te tourner vers le pré-processeur, avec l'aide de boost::preprocessor, j'avais sans mal écrit une classe avec une syntaxe proche d'une enum, mais permettant de retourner une string correspondante.

  10. #10
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    Alp> Pourquoi pas ? On utilise une mémoire virtuelle après tout. Et les chaînes sont créées statiquement.

    Mouerf, bon… j'essaie de discuter, mais de toutes façons j'ai essayé avec un bête int* et je me fais jeter…
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    error: ‘i_ptr’ cannot appear in a constant-expression
    Mais je suis pas du tout convaincu par son argumentaire


    Plus sérieusement, je vais tout de même continuer de trouver un moyen de réaliser ça. Conceptuellement parlant, je sais que c'est bon. Parbleu.

  11. #11
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    JolyLoic> Super, je vais aller voir par là . Merci !

    Alp>

  12. #12
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 861
    Points
    11 861
    Par défaut
    Un quelconque pointeur n'existe pas à la compilation. Il existe syntaxiquement, mais la zone mémoire n'existe pas. Or les templates ne travaillent que sur ce qui est connu à la compilation.

    Tu vois ce que je veux dire ?

    La solution proposée par Loïc est effectivement un bon moyen de contourner le problème à mon avis.

  13. #13
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    Citation Envoyé par Alp Voir le message
    Un quelconque pointeur n'existe pas à la compilation. Il existe syntaxiquement, mais la zone mémoire n'existe pas. Or les templates ne travaillent que sur ce qui est connu à la compilation.
    Oui oui je sais bien, c'est pour ça que j'ai parlé de mémoire virtuelle dans mon précèdent message. J'imaginais donc un monde merveilleux où la valeur de l'adresse, de ce fait, serait connue à la compilation. Je sais bien que tu as raison

  14. #14
    Membre confirmé
    Avatar de gb_68
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2006
    Messages
    232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2006
    Messages : 232
    Points : 546
    Points
    546
    Par défaut
    Bonjour,
    il me semble aussi que c'est possible ; en tout cas ce code compile sous VC++ 2005
    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
    const char * access_specifier_string_list[] = {"public", "protected", "private", ""};
     
     
    template<const char** StringList>
    class string_enumeration
    {
        public:
            static const char** string_list_;
    };
     
    template<const char** StringList>
    const char** string_enumeration<StringList>::string_list_ = StringList;
     
    // ...
     
    cout << string_enumeration<access_specifier_string_list>::string_list_[0] << endl;
    cout << string_enumeration<access_specifier_string_list>::string_list_[1] << endl;
    cout << string_enumeration<access_specifier_string_list>::string_list_[2] << endl;
    Un petit lien http://www.comeaucomputing.com/techt...#stringliteral

  15. #15
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    Alp & Loïc> Par ailleurs, puisque vous deux êtes là, savez-vous s'il sera possible d'utiliser une std::initialization_list<std::vector<std::string>> en tant que paramètre template ? Ensuite j'initialiserais un vector static interne à la classe générée.
    On pourrait alors écrire ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    typedef string_enumeration<{"public", "protected", "private"}> access_specifier;
    Le panard, n'est-ce pas ?

  16. #16
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    Grr, je poste vraiment trop lentement.

    gb_68> Tiens, tiens…
    Mon problème c'est que tout ce code doit être dans un .h (vu qu'il s'agit d'une classe template).
    Le problème c'est que ce .h est inclus dans des translation units (c'est le terme utilisé dans le standard… on dirait unités de compilation, en français, apparemment) différentes. Du coup access_specifier_string_list[] est défini plusieurs fois, ce qui cause l'erreur que j'ai collé dans mon premier message.

  17. #17
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 861
    Points
    11 861
    Par défaut
    Pour ton problème et pour ta dernière question, je répondrais :
    Citation Envoyé par Brouillon de norme C++0x - Section 14.1
    A non-type template-parameter shall have one of the following (optionally cv-qualified) types:
    — integral or enumeration type,
    — pointer to object or pointer to function,
    — reference to object or reference to function,
    — pointer to member.
    Donc au temps pour moi, j'avais partiellement tort.

    EDIT : c'est surtout le 14.3.2 qui en parle en fait.
    1 A template-argument for a non-type, non-template template-parameter shall be one of:
    — an integral constant expression; or
    — the name of a non-type template-parameter; or
    — the address of an object or function with external linkage, including function templates and function template-ids
    but excluding non-static class members, expressed as & id-expression where the & is optional if the name refers to
    a function or array, or if the corresponding template-parameter is a reference; or
    — a constant expression that evaluates to a null pointer value (4.10); or
    Draft
    323 Templates 14.3 Template arguments
    — a constant expression that evaluates to a null member pointer value (4.11); or
    — a pointer to member expressed as described in 5.3.1.
    2 [ Note: A string literal (2.13.4) does not satisfy the requirements of any of these categories and thus is not an acceptable
    template-argument. [ Example:
    template<class T, char* p> class X {
    X();
    X(const char* q) { / ... / }
    };
    X<int, "Studebaker"> x1; // error: string literal as template-argument
    char p[] = "Vivisectionist";
    X<int,p> x2; // OK
    —end example ] —end note ]
    3 [ Note: Addresses of array elements and names or addresses of non-static class members are not acceptable templatearguments.
    [ Example:
    template<int* p> class X { };
    int a[10];
    struct S { int m; static int s; } s;
    X<&a[2]> x3; // error: address of array element
    X<&s.m> x4; // error: address of non-static member
    X<&s.s> x5; // error: &S::s must be used
    X<&S::s> x6; // OK: address of static member
    —end example ] —end note ]
    4 [ Note: Temporaries, unnamed lvalues, and named lvalues that do not have external linkage are not acceptable templatearguments
    when the corresponding template-parameter has reference type. [ Example:
    template<const int& CRI> struct B { / ... / };
    B<1> b2; // error: temporary would be required for template argument
    int c = 1;
    B<c> b1; // OK
    —end example ] —end note ]
    5 The following conversions are performed on each expression used as a non-type template-argument. If a non-type
    template-argument cannot be converted to the type of the corresponding template-parameter then the program is illformed.
    — for a non-type template-parameter of integral or enumeration type, integral promotions (4.5) and integral conversions
    (4.7) are applied.
    Draft
    14.3 Template arguments Templates 324
    — for a non-type template-parameter of type pointer to object, qualification conversions (4.4) and the array-topointer
    conversion (4.2) are applied; if the template-argument is of type std::nullptr_t, the null pointer conversion
    (4.10) is applied. [ Note: In particular, neither the null pointer conversion for a zero-valued integral
    constant expression (4.10) nor the derived-to-base conversion (4.10) are applied. Although 0 is a valid templateargument
    for a non-type template-parameter of integral type, it is not a valid template-argument for a non-type
    template-parameter of pointer type. However, both (int*)0 and nullptr are valid template-arguments for a
    non-type template-parameter of type “pointer to int.” —end note ]
    — For a non-type template-parameter of type reference to object, no conversions apply. The type referred to by the
    reference may be more cv-qualified than the (otherwise identical) type of the template-argument. The templateparameter
    is bound directly to the template-argument, which shall be an lvalue.
    — For a non-type template-parameter of type pointer to function, the function-to-pointer conversion (4.3) is applied;
    if the template-argument is of type std::nullptr_t, the null pointer conversion (4.10) is applied. If
    the template-argument represents a set of overloaded functions (or a pointer to such), the matching function is
    selected from the set (13.4).
    — For a non-type template-parameter of type reference to function, no conversions apply. If the template-argument
    represents a set of overloaded functions, the matching function is selected from the set (13.4).
    — For a non-type template-parameter of type pointer to member function, if the template-argument is of type
    std::mullptr_t, the null member pointer conversion (4.11) is applied; otherwise, no conversions apply. If the
    template-argument represents a set of overloaded member functions, the matching member function is selected
    from the set (13.4).
    — For a non-type template-parameter of type pointer to data member, qualification conversions (4.4) are applied; if
    the template-argument is of type std::nullptr_t, the null member pointer conversion (4.11) is applied.
    [ Example:
    template<const int* pci> struct X { / ... / };
    int ai[10];
    X<ai> xi; // array to pointer and qualification conversions
    struct Y { / ... / };
    template<const Y& b> struct Z { / ... / };
    Y y;
    Z<y> z; // no conversion, but note extra cv-qualification
    template<int (&pa)[5]> struct W { / ... / };
    int b[5];
    W<b> w; // no conversion
    void f(char);
    void f(int);
    template<void (*pf)(int)> struct A { / ... / };
    A<&f> a; // selects f(int)
    —end example ]

  18. #18
    Membre confirmé
    Avatar de gb_68
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2006
    Messages
    232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2006
    Messages : 232
    Points : 546
    Points
    546
    Par défaut
    Pour la séparation en .h/.cpp
    .h
    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
    extern const char * access_specifier_string_list[];
    // ou
    struct def_table
    {
    	static const char * string_list[];
    };
     
    template<const char** StringList>
    class string_enumeration
    {
     public:
            static const char** string_list_;
    };
     
    template<const char** StringList>
    const char** string_enumeration<StringList>::string_list_ = StringList;
    .cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #include "[...].h"
    const char * access_specifier_string_list[]= {"public", "protected", "private", ""};
    const char * def_table::string_list[]= {"hello", "world", "" };

  19. #19
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par Florian Goo Voir le message
    Alp & Loïc> Par ailleurs, puisque vous deux êtes là, savez-vous s'il sera possible d'utiliser une std::initialization_list<std::vector<std::string>> en tant que paramètre template ?
    Tu veux dire initializer_list<std::string>, je pense ?
    Citation Envoyé par Florian Goo Voir le message
    Ensuite j'initialiserais un vector static interne à la classe générée.
    On pourrait alors écrire ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    typedef string_enumeration<{"public", "protected", "private"}> access_specifier;
    Le panard, n'est-ce pas ?
    Je ne pense pas (mais n'ai pas le courrage de vérifier).
    Par contre, et si elle a un linkage externe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    initializer_list<string> enumNames = {"public", "protected", "private"};
    typedef string_enumeration<&enumNames> access_specifier;
    Devrait marcher.

    J'ai retrouvé le bout de code que j'avais commencé à écrire. Je ne sais plus dans quel état je l'avais laissé, et ne l'ai pas adapté aux montées de version de boost.

    Le code : RichEnum.h
    Un exemple de test : TestRichEnum.cpp

  20. #20
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    gb_68> Sapristi, mais ça MARCHE !

    J'avais tenté avec le export, mais gcc m'a gentiment dit que ce n'était pas implémenté. C'est parce que c'est pas standard, ou bien l'implémentation était trop difficile (je serais étonné, mais bon…).

    J'ai aussi tenté le coup de la def_table, mais bêtement je suis pas allé au bout, me disant que ça incluerait pointeur sur membre au lieu de l'universel const char** , la fatigue.

    Toujours est-il que je n'aurais pas trouvé [du tout]/[si vite] sans toi. Mercis tout plein !

    Je vais me renseigner sur le linkage externe, et ce qui fait que tout cela est possible.
    Je testerai avec les initializer_list dès la sortie de GCC 4.4.
    Enfin, je découvrirai boost.preprocessor plus tard

    Un grand merci à tout le monde

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 20
    Dernier message: 20/03/2013, 07h32
  2. problème dllImport avec tableau de char[] en paramètre E/S
    Par moulefrite dans le forum Windows Forms
    Réponses: 4
    Dernier message: 24/12/2008, 10h07
  3. Ansistring et tableau de char
    Par rabbi_jaccob dans le forum C++Builder
    Réponses: 2
    Dernier message: 24/12/2004, 11h51
  4. Adresse d'un tableau de char
    Par Trap D dans le forum C
    Réponses: 8
    Dernier message: 23/12/2003, 12h02
  5. Réponses: 4
    Dernier message: 10/10/2003, 18h04

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