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 :

utilisation correcte des template variadiques C++11


Sujet :

C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 99
    Points : 303
    Points
    303
    Par défaut utilisation correcte des template variadiques C++11
    Bonjour à tous!

    Je commence à expérimenter un peu avec C++11 sous GCC 4.4.0, étant particulièrement intéressé par les templates variadiques.

    Ma première expérience est assez perturbante. J'essaie de créer une fonction qui imprime les types de ses arguments templates via un typeid(...).

    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
     
    #include <iostream>
    #include <typeinfo>
     
    /* Version sans arguments de fonction */
    void printType(){
        std::cout << std::endl ;
    }
     
    template <typename Arg, typename ... Args>
    void printType() {
        std::cout << typeid(Arg).name();
        printType<Args...>();
    }
     
    /* Version avec arguments de fonction */
    void printType2(){
        std::cout << std::endl ;
    }
     
    template <typename Arg, typename ... Args>
    void printType2(Arg v, Args ... args) {
        std::cout << typeid(Arg).name();
        printType2(args...);
    }
     
     
    int main(){
        int a, c, e;
        float b, d;
        printType2(a,b,c,d,e); // ok : sortie du style "ififi"
        printType2(b,c,d,e,a); // ok : sortie du style "fifii"
        printType();              // ok : sortie ligne vide
        printType<int, float>(); // erreur de compilation "no matching function for call printType()"
        return 0;
    }
    Tout ceci est compilé avec la commande:
    c++ -std=gnu++0x variadicTest.cpp

    Pouvez vous m'expliquer pourquoi la version du printType sans arguments de fonction (mais arguments templates explicites) ne fonctionne pas? Qu'ai-je râté?

    Merci pour tout renseignement!
    Daniel

  2. #2
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Bonjour,
    Ça ressemble à un bug de GCC.
    L'appel printType<int, float>(); est équivalent en C++03 à :
    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
     
    #include <iostream>
    #include <typeinfo>
     
    void printType()
    {
       std::cout << std::endl ;
    }
     
    template <typename T1>
    void printType()
    {
       std::cout << typeid(T1).name() << std::endl;
       printType();
    }
     
    template <typename T1, typename T2>
    void printType()
    {
       std::cout << typeid(T1).name() << std::endl;
       printType<T2>();
    }
     
    int main()
    {
       printType();
       printType<int, float>();
    }
    qui compile et donne le résultat attendu avec vs2008.

    Peut-être pourrais tu essayer avec la dernière version de GCC (4.5) pour voir si l'erreur de compilation persiste ?

  3. #3
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Je ne pense pas que ce soit un bug gcc. printType<>() et printType() ne sont pas 2 mêmes fonctions.
    Disons que ça s'applique moyennement avec des fonctions car tu cherches à faire une spécialisation partielle d'une fonction générique, ce qui n'est pas possible.
    Le cas printType2 fonctionne car la fonction terminale n'est pas générique et n'en n'a pas besoin puisque le match se fait sur les arguments.

    Pour printType pas d'argument pour déduire les paramètres génériques, mais ils sont explicitement passés à la main. Tu peux t'en tirer avec une gymnastique en utilisant la fin de la récursion sur 1 argument et non sur 0 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /* Version sans arguments de fonction */
    template<typename Arg>
    void printType(){
        std::cout << typeid(Arg).name();
    }
     
    template <typename Arg1, typename Arg2, typename ... Args>
    void printType() {
        std::cout << typeid(Arg1).name();
        printType<Arg2, Args...>();
    }
    Mais pour moi, j'ai l'impression qu'il faudrait passer par une structure et faire une spécialisation partielle sur cette structure pour gérer la fin de la récursion (avec 0 elts).
    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
    #include <iostream>
    #include <typeinfo>
     
    template<typename ...Args>
    struct printType_impl;
     
    template<>
    struct printType_impl<>
    {
        static void do_it()
        {
            std::cout<<"End !\n";
        }
    };
    template<typename A1, typename... Args>
    struct printType_impl<A1,Args...>
    {
        static void do_it()
        {
            std::cout << typeid(A1).name();
            printType_impl<Args...>::do_it();
        }
    };
     
    template <typename ... Args>
    void printType() {
        printType_impl<Args...>::do_it();
    }
     
    int main(){
        printType<int, float>();
        printType<>();
        printType<int, float,int,float>();
        return 0;
    }

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 99
    Points : 303
    Points
    303
    Par défaut
    Bonjour,

    Merci pour ces explications! Il doit effectivement y avoir une différence entre printType<>() et printType() même si je n'ai pas totalement saisi la nuance, mais du moment que ce comportement est spécifié et "garanti" sur les différents compilos, ça me va . D'ailleurs, il y a-t-il d'autres compilos qui gèrent les templates variadiques ou est-ce trop tôt encore?

    Merci et bonne journée à tous!
    Daniel

    PS: Pour éliminer un doute concernant GCC (des bugs, ça arrive!) j'ai mis à jour vers la 4.5 ce qui n'a pas résolu le problème.

  5. #5
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par mangobango Voir le message
    Merci pour ces explications! Il doit effectivement y avoir une différence entre printType<>() et printType() même si je n'ai pas totalement saisi la nuance,
    La différence est plus évidente avec un argument, mais le principe est le même :
    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
    #include <iostream>
     
    template<typename t_>
    void fonction(t_)
    {
    	std::cout<<"template\n";
    }
    void fonction(int)
    {
    	std::cout<<"non template\n";
    }
     
    int main()
    {
    	int i(0);
    	fonction(i);
    	fonction<int>(i);
    	short s(1);
    	fonction(s);
     
    	return 0;
    }
    fonction(int) et l'instanciation de fonction<int>(int) sont 2 fonctions différentes avec 2 adresses différentes.
    Par défaut, l'appel fonction(i) est résolu en prenant fonction(int) car c'est le 'meilleur' match. L'instanciation de la fonction générique fonction n'a pas lieu. Pour l'obtenir, il faut l'appeler explicitement : fonction<int>(i) .
    Avec fonction(s), le meilleur match c'est l'instanciation de la fonction générique avec short : fonction<short>. L'appel de fonction(int) nécessiterait une conversion short-> int qui a été définie comme moins prioritaire que l'instanciation du générique
    Tout ça pour dire (mais je ne suis pas sur d'arriver à m'expliquer clairement) que ce n'est pas un bug gcc mais bien le comportement défini par la norme.


    Citation Envoyé par mangobango Voir le message
    D'ailleurs, il y a-t-il d'autres compilos qui gèrent les templates variadiques ou est-ce trop tôt encore?
    Je ne sais pas.

  6. #6
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Et si on y ajoute des trucs comme ceci on n'est pas sorti de l'auberge
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template<typename tr_>
    void fonction(tr_ &)
    {
    	std::cout<<"ref template\n";
    }
    template<typename tcr_>
    void fonction(tcr_ const &)
    {
    	std::cout<<"cref template\n";
    }

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 99
    Points : 303
    Points
    303
    Par défaut
    Ah! J'ai compris! Comme moi je demandais explicitement l'utilisation de la fonction printType<>() et qu'elle n'existe pas (à moins de faire une spécialisation partielle de fonction template, ce qui n'est pas possible), gcc ne trouvait pas! Super, ça à du sens!

    Merci!
    Daniel

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 99
    Points : 303
    Points
    303
    Par défaut
    Rebonjour à tous!

    Bon, je bump ce sujet car j'ai une question liée à l'exemple de sérialisation des arguments templates. Les solutions ci-dessus marchent du tonnerre pour les arguments qui sont des types. Seulement, j'ai pas réussi à faire en sorte que ça fonctionne pour des non-types. Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    printTemplateArgs<int, double, 3, char, 4>();
    En gros ça revient à pouvoir déclarer un genre de:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    //conceptuellement seulement! c'est pas du C++ valide.
    template < Any ... Args >
    printTemplateArgs();
     
    template < typename ... Args >
    printTemplateArgs();
     
    template < unsigned int ... Args >
    printTemplateArgs();
    J'ai un peu cherché dans le standard mais j'ai rien vu de ce type et je ne suis pas sûr que le concept d'un template "Any" soit apprécié! J'ai pris des réflexes de pythonien depuis quelque temps, où (presque) tout est possible!

    Merci pour vos lumières!
    Daniel

  9. #9
    Membre chevronné
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Points : 1 921
    Points
    1 921
    Par défaut
    mets tes entiers dans des std::integral_c ou des boost::mpl::integral_c

  10. #10
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    J'ai pas gcc sous la main (args, mais pourquoi VC10 ne les implémente pas ) mais en potassant la norme, je pense qu'il y a un problème dans ta façon d'utiliser le non-type parameter :
    dit que tu auras plusieurs int et non un int puis des choses. En gros, avec ça, tu peux faire type<1,2,3> mais pas type<1,int, 2, double>.
    Ce que tu commences à vouloir faire devient assez tordu Sans avoir trop réfléchi, je pense que tu dois changer ton fusil d'épaule. Avec une fonction générique, la combinatoire risque d'exploser. Peut être est-ce plus facile à traiter avec des classes génériques, des spécialisations partielles et des meta-liste (j'hésite à dire type-list dans la mesure où certains arguments ne seraient pas des types). Ca demande de se pencher sur le problème un peu plus longtemps que les 5' que j'ai ce soir.

  11. #11
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par Joel F Voir le message
    mets tes entiers dans des std::integral_c ou des boost::mpl::integral_c
    c'est pas fô. Ca revient à transformer les constantes en type, c'est ça ?

  12. #12
    Membre chevronné
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Points : 1 921
    Points
    1 921
    Par défaut
    oui. Ca evite le probleme des parametrages tempalte hétérogénes (valeurs+types) qui en autre t'interdisent de passer de tels types sous formes de meta-lambda-fonction.

  13. #13
    Membre averti
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 99
    Points : 303
    Points
    303
    Par défaut
    Ok merci les gens! J'ai trouvé integral_constant dans type_traits. Je pense que c'est ce qu'il me faut. Au pire j'ai Boost sous la main, mais j'essaie de me focaliser sur C++11.

    J'utilise MingW pour tester GCC 4.4 ou 4.5 sous Windows. Trolltech, enfin, Nokia, fournit une archive de la 4.4 (celle qui sert à compiler Qt OpenSource).
    ftp://ftp.trolltech.com/misc/MinGW-gcc440_1.zip. Ca fonctionne plutôt bien. Suffit de le décompresser l'archive, de mettre dans le PATH et de rajouter "mingw32-" avant gcc, c++ etc... Mingw a aussi GCC 4.5 de dispo.

    Et pour ce que je veux faire, je me demande aussi assez souvent si c'est une bonne idée , mais bon pour l'instant je fais bien mumuse.

    Daniel

Discussions similaires

  1. Réponses: 7
    Dernier message: 16/08/2010, 17h08
  2. Utilisation correcte des vectors et iterators
    Par Ange_blond dans le forum SL & STL
    Réponses: 7
    Dernier message: 29/01/2009, 13h46
  3. Utilisation avancée des templates
    Par olivier2019 dans le forum Eclipse Java
    Réponses: 4
    Dernier message: 03/04/2008, 14h26
  4. [XSL] utilisation des templates
    Par KibitO dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 16/12/2005, 15h54
  5. Utilisation des templates
    Par mikky dans le forum C++
    Réponses: 1
    Dernier message: 14/09/2005, 12h59

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