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 :

Plusieurs parametres template


Sujet :

Langage C++

  1. #1
    Membre habitué
    Homme Profil pro
    Inscrit en
    Février 2006
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 153
    Points : 168
    Points
    168
    Par défaut Plusieurs parametres template
    Bonjour

    Je souhaite reproduire (en gros) le fonctionnement de python join, c'est a dire de joindre par un separateur les éléments d'un conteneur.

    ex :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    std::vector<int> vec;
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);
    join(std::cout, vec.begin(), vec.end(), " - ");
    // Affiche : 1 - 2 - 3
    Pour faire quelquechose de générique, j'ai donc fait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template <class Stream, class Iterator, class Sep>
    Stream& join(Stream& s, Iterator it, Iterator last, const Sep& sep)
    {
    	for (--last; it != last; ++it) {
    		s << *it << sep;
    	}
    	s << *it;
    	return s;
    }
    Un fois cela fait, je me suis dit qu'il serai intéressant de surcharger cette fonction de plusieurs manieres :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // Pour un conteneur complet plutot qu'un range d'iterator
    template <class Stream, class Container, class Sep>
    Stream& join(Stream& s, const Container& c, const Sep& sep)
    {
    	return join(s, c.begin(), c.end(), sep);
    }
    Jusque là, tout va bien. Mais je souhaitais aller un peu plus loin, surtout dû au fait que j'utilise wxWidgets, et que la classe wxString accepte les operateurs de flux. J'aurais donc bien voulu faire un truc du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    wxString s;
    s << "coucou " << join(vec.begin(), vec.end(), " - ") << " hop";
    Je ne souhaite plus fournir le flux à la méthode. Ca n'est pas dérangeant en soit, mais le problème vient plutôt de la déclaration et de l'instanciation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template<class Stream, class Iterator, class Sep>
    Stream join(Iterator it, Iterator last, const Sep& sep)
    {
    	Stream s;
    	return join(s, it, last, sep);
    }
     
    // Comment l'appeller ?
    join<wxString>(vec.begin(), vec.end(), " - ");
    Le compilateur est évidement un peu perdu : j'ai 2 fonctions join prenant 3 paramètres. On aurai pu penser que le fait que les 2 premiers arguments nécessitant d'être identique aurai permis au compilateur de prendre la bonne fonction, mais cela n'a pas l'air d'être le cas.
    Me méprends-je ?
    Y a t il un solution ?
    --
    Jérémie
    Jérémie

  2. #2
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    En ce qui concerne l'insertion d'un séparateur, il y a une autre solution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::copy(vect.begin(), vect.end(), std::ostream_iterator<int>(std::cout, " - ") );
    Après, pourquoi mettre un stream en template plutôt qu'utiliser un std::ostream ou un std::istream ?

  3. #3
    Membre habitué
    Homme Profil pro
    Inscrit en
    Février 2006
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 153
    Points : 168
    Points
    168
    Par défaut
    Bonjour
    Citation Envoyé par poukill Voir le message
    En ce qui concerne l'insertion d'un séparateur, il y a une autre solution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::copy(vect.begin(), vect.end(), std::ostream_iterator<int>(std::cout, " - ") );
    Heuu, ouiménon. Cela ne fait pas ce que je veux :
    Je veux "1 - 2 - 3", et non pas "1 - 2 - 3 - " (remarque le dernier -).

    Citation Envoyé par poukill Voir le message
    Après, pourquoi mettre un stream en template plutôt qu'utiliser un std::ostream ou un std::istream ?
    Ca, c'est a cause de wxWidgets, où wxString n'hérite pas de stream...
    --
    Jérémie
    Jérémie

  4. #4
    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,

    Il n'y a aucune bibliothèque C++ "normalement constituée" qui oserait faire hériter ses chaines de caractères de sa classe de flux...

    Une chaine de caractères permet de représenter une information particulière, dans un format "humainement lisible", alors que les flux ont pour but de... permettre la transmission ou la conversion de l'information... et pas seulement de chaines de caractères

    Il n'y a donc strictement aucune raison pour que la chaine de caractères ne dérive du flux
    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

  5. #5
    Membre habitué
    Homme Profil pro
    Inscrit en
    Février 2006
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 153
    Points : 168
    Points
    168
    Par défaut
    Je suis tout à fait d'accord avec votre point de vue. Mais que dois je comprendre de la réponse :
    - Il ne faut pas faire ce que j'ai prévu (cémal) ?
    - Je peux poursuivre dans cette direction ?

    Ca m'embête de passer par un ostringstream, puis par le convertir en wxString. Ceci implique moultes conversions de chaine de caractère (avec les charset qui vont bien).
    --
    Jérémie
    Jérémie

  6. #6
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Je crois que lorqu'on "build" WxWidget, il y a une option dans le config.h pour que WxWidget utilise les flux de la STL.

  7. #7
    Membre habitué
    Homme Profil pro
    Inscrit en
    Février 2006
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 153
    Points : 168
    Points
    168
    Par défaut
    Citation Envoyé par poukill Voir le message
    Je crois que lorqu'on "build" WxWidget, il y a une option dans le config.h pour que WxWidget utilise les flux de la STL.
    Tout a fait, mais cela ne fait pas que wxString soit un stream.
    On dérive...

    Pour revenir à la question initiale, le compilateur peut il faire la différence entre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template <class Stream, class Container, class Sep>
    Stream& join(Stream& s, const Container& c, const Sep& sep)
    {
    	return join(s, c.begin(), c.end(), sep);
    }
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template<class Stream, class Iterator, class Sep>
    Stream join(Iterator it, Iterator last, const Sep& sep)
    {
    	Stream s;
    	return join(s, it, last, sep);
    }
    Et comment appeler la dernière fonction (car le template Stream n'est qu'un type de retour, que le compilateur ne peut deviner).
    Merci
    --
    Jérémie
    Jérémie

  8. #8
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Citation Envoyé par jfouche Voir le message
    Tout a fait, mais cela ne fait pas que wxString soit un stream.
    On dérive...
    Comme disait Koala, j'espère bien !!
    Ce serait une grave erreur de conception de faire ainsi.

    Pour la question initiale, il me semble que le compilo devrait s'en sortir non ? Dans un cas, il y a deux itérateurs à fournir du même type template. Le compilo ne peut pas se tromper.

  9. #9
    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 jfouche Voir le message
    Bonjour

    Je souhaite reproduire (en gros) le fonctionnement de python join, c'est a dire de joindre par un separateur les éléments d'un conteneur.

    ex :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    std::vector<int> vec;
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);
    join(std::cout, vec.begin(), vec.end(), " - ");
    // Affiche : 1 - 2 - 3
    Pour faire quelquechose de générique, j'ai donc fait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template <class Stream, class Iterator, class Sep>
    Stream& join(Stream& s, Iterator it, Iterator last, const Sep& sep)
    {
    	for (--last; it != last; ++it) {
    		s << *it << sep;
    	}
    	s << *it;
    	return s;
    }
    Quelques remarques : cette méthode plante si la liste est vide ?
    Citation Envoyé par jfouche Voir le message
    Un fois cela fait, je me suis dit qu'il serai intéressant de surcharger cette fonction de plusieurs manieres :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // Pour un conteneur complet plutot qu'un range d'iterator
    template <class Stream, class Container, class Sep>
    Stream& join(Stream& s, const Container& c, const Sep& sep)
    {
    	return join(s, c.begin(), c.end(), sep);
    }
    Jusque là, tout va bien. Mais je souhaitais aller un peu plus loin, surtout dû au fait que j'utilise wxWidgets, et que la classe wxString accepte les operateurs de flux. J'aurais donc bien voulu faire un truc du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    wxString s;
    s << "coucou " << join(vec.begin(), vec.end(), " - ") << " hop";
    Je ne souhaite plus fournir le flux à la méthode. Ca n'est pas dérangeant en soit, mais le problème vient plutôt de la déclaration et de l'instanciation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template<class Stream, class Iterator, class Sep>
    Stream join(Iterator it, Iterator last, const Sep& sep)
    {
    	Stream s;
    	return join(s, it, last, sep);
    }
     
    // Comment l'appeller ?
    join<wxString>(vec.begin(), vec.end(), " - ");
    Le compilateur est évidement un peu perdu : j'ai 2 fonctions join prenant 3 paramètres. On aurai pu penser que le fait que les 2 premiers arguments nécessitant d'être identique aurai permis au compilateur de prendre la bonne fonction, mais cela n'a pas l'air d'être le cas.
    Me méprends-je ?
    Y a t il un solution ?
    --
    Jérémie
    L'idée serait d'avoir une seule surcharge avec 3 paramètres template allant chercher l'implémentation dans une structure template. Ensuite, tu utilises la spécialisation partielle sur ta classe template avec wxString explicitement. Quelque chose comme ça (à la volée donc à affiner/corriger) :
    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
     
    template<class T1, class T2, class Sep>
    struct join_helper
    {
       typedef T1& return_type;
       typedef T1& arg1;
       typedef const T2& arg2;
       typedef const Sep& arg3;
       static return_type doIt(T1& s, const T2& c, const Sep& sep)
       {
          return join(s, c.begin(), c.end(), sep);
       }
    };
     
    template<class T2, class Sep>
    struct join_helper<wxString, T2, Sep>
    {
       typedef wxString return_type;
       typedef T2 arg1;
       typedef const T2 arg2;
       typedef const Sep& arg3;
       static return_type doIt(T2 it, T2 last, const Sep& sep)
       {
          wxString s;
          return join(s, it, last, sep);
       }
    };
     
    template <class T1, class T2, class T3>
    typename join_it<T1,T2,T3>::return_type join(
       typename join_it<T1,T2,T3>::arg1 s,
       typename join_it<T1,T2,T3>::arg1 c,
       typename join_it<T1,T2,T3>::arg1 sep
    )
    {
    	return join_helper<T1,T2,T3>::doIt(s, c.begin(), c.end(), sep);
    }

  10. #10
    Membre habitué
    Homme Profil pro
    Inscrit en
    Février 2006
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 153
    Points : 168
    Points
    168
    Par défaut
    Wouah, ca arrache
    Merci pour la réponse, je pense, que je vais regarder cela de plus prêt.
    Simplifier me semble un complexe, non ?
    Je vois que j'ai encore pas mal de boulot sur les templates...
    --
    Jérémie
    Jérémie

  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
    Boost ftw

  12. #12
    Membre habitué
    Homme Profil pro
    Inscrit en
    Février 2006
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 153
    Points : 168
    Points
    168
    Par défaut
    Bah voila, boost une fois encore boost possède (peut être) la solution...
    Tiens, la 1.39.0 vient juste de sortir, merci
    --
    Jérémie
    Jérémie

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. probleme template a plusieurs parametres
    Par typedef dans le forum Langage
    Réponses: 4
    Dernier message: 01/05/2010, 08h13
  2. Réponses: 2
    Dernier message: 20/06/2005, 14h57
  3. [VB] Passer plusieurs parametres à une procedure stockée
    Par wolflinger dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 19/04/2005, 14h13
  4. Réponses: 5
    Dernier message: 12/05/2004, 16h37
  5. procedures/fonctions stockees : renvoi de plusieurs parametr
    Par Spoutnik dans le forum PostgreSQL
    Réponses: 3
    Dernier message: 11/05/2004, 11h53

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