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 :

Comment créer son propre "cout" avec un "endl" ?


Sujet :

C++

  1. #1
    Membre habitué Avatar de sopsag
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 224
    Points : 190
    Points
    190
    Par défaut Comment créer son propre "cout" avec un "endl" ?
    Bonjour à tous,

    j'ai une classe qui surcharge l'opérateur << pour permettre la sortie formatée vers un ostream.

    Je veux que l'utilisateur de ma classe puisse déclarer son propre ostream-like avec une sortie formatée à lui.
    Tout marche comme je veux sauf pour le retour à la ligne avec endl.
    Voici un petit bout de code (ultra simplifié) qui illustre mon cas:
    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
    struct Point // ma classe
        {
        int x,y ;
     
        // avec sa surcharge de l'opérateur de sortie formatée
        template <typename output>
        friend output & operator<< ( output & o , const Point & t ) ;
        } ;
     
    // implémentation de l'opérateur de sortie formatée
    template <typename output> output & operator<< ( output & o , const Point & t )
        {
        o << "(" << t.x << "," << t.y << ")" ;
        // o << output::endl ; // ne compile pas avec o == std::cout car endl n'est pas membre de std::ostream
        return o ;
        }
     
    // le ostream-like de l'utilisateur
    struct my_ostream
        {
        my_ostream & operator<< ( int x )                       { printf("int    : %d\n",x ) ; return *this ;}
        my_ostream & operator<< ( const char * s )              { printf("string : \"%s\"\n",s ) ; return *this ;}
        my_ostream & operator<< ( my_ostream&(*f)(my_ostream&)) { return f( *this ) ;}
        // le "endl" de my_ostream a la même signature que celui de std :
        static my_ostream & endl ( my_ostream & o )             { printf("end of line\n") ; return o ;}
        } ;
     
    void test_output2 ()
        {
        Point p = { 12,13 } ;
        my_ostream my_cout ;
        my_cout << p ;
        std::cout << p ; // si je commente cet appel, le "o << output::endl" du dessus compile bien.
        }
    Quelqu'un saurait-il comment faire (proprement) ce genre de truc ?
    [WinXP sp3 / Visual 2005 / Eclipse Ganymede / Python 2.6]
    Hadrien

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    188
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 188
    Points : 248
    Points
    248
    Par défaut
    Bonjour,

    Peut être
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static const char endl = '\n';
    Après tout c'est juste pour signaler une fin de ligne

  3. #3
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    780
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mai 2006
    Messages : 780
    Points : 1 176
    Points
    1 176
    Par défaut
    en fait le endl fait un flush aussi

  4. #4
    Membre habitué Avatar de sopsag
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 224
    Points : 190
    Points
    190
    Par défaut
    En fait, ce que je voudrais, c'est pouvoir faire ces 2 appels et que ça marche !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    my_cout << p ;   // utilise un ostream perso
    std::cout << p ; // utilise le ostream des stl
    Or, dans mon exemple, l'appel "<< endl" dans ma surcharge de l'opérateur << ne compile pas pour la 2eme ligne.
    [WinXP sp3 / Visual 2005 / Eclipse Ganymede / Python 2.6]
    Hadrien

  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
    output est un type et en gros tu es en train de demander à ton compilateur de compiler un appel std::ostream::std::endl, ce qui n'a pas de sens, std::endl n'étant absolument pas membre de std::ostream
    "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
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    La maniere habituelle de faire son "ostream like" est de definir un streambuf -- apres quoi tu n'as plus de probleme.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  7. #7
    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
    Après d'âpres recherches, j'ai réussi à remettre la souris sur le site auquel je pensais pour en apprendre plus sur les streams

    Il est là http://www.angelikalanger.com/Articles/Topics.html#CPP
    "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)

  8. #8
    Membre actif
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    188
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 188
    Points : 248
    Points
    248
    Par défaut
    en fait si tu veux que ton ostream perso comprenne std::endl il faut que tu surcharge l'opérateur << pour la signature de la fonction std::endl qui est

    template <class charT, class traits>
    basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os);

    apriori

    voir ce lien

  9. #9
    Membre habitué Avatar de sopsag
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 224
    Points : 190
    Points
    190
    Par défaut
    Citation Envoyé par Davidbrcz Voir le message
    std::endl n'étant absolument pas membre de std::ostream
    Bé oui, je sais bien, d'où ma question...
    Mais merci pour ce lien précieux ! de longues heures de lecture en perspectives... toutefois j'ai peur de ne pas y trouver ma réponse.

    Pour mon machin, la solution de atttchoum est celle vers laquelle je me dirigeais... ça donne un truc comme ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    struct my_ostream
        {
        // j'ajoute cette méthode qui va traduire les manipulateurs
        template <class c, class t>
        my_ostream & operator<< ( std::basic_ostream<c,t>&(*f)(std::basic_ostream<c,t>&)) 
            { 
            switch ( f )
                {
                case std::endl : my_ostream::endl( *this ) ;
                case std::ends : ; // etc
                }
            return *this ;
            }
    Ça ne compile pas et je n'ai encore compris pourquoi...
    Mais de toutes façons, je trouve ça assez moche.

    Quant à la solution de Jean-Marc Bourguet à base de streambuf, je ne la comprends pas...
    [WinXP sp3 / Visual 2005 / Eclipse Ganymede / Python 2.6]
    Hadrien

  10. #10
    Invité
    Invité(e)
    Par défaut
    Il suffit de placer ta fonction endl dans le namespace std puis de faire une surcharge approprié de << dans ta classe(un peu comme tu as fait)

    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
     
    class my_ostream;
     
    namespace std
    {
        my_ostream& endl(my_ostream& out);
        my_ostream& ends(my_ostream& out);
        my_ostream& flush(my_ostream& out);
    }
     
     
    class my_ostream
    {
        my_ostream& operator<<(my_ostream& (*manip)(my_ostream&))
        {
             return manip(*this);
        }
    }
     
    my_ostream& std::endl(my_ostream& out)
    {
        return my_ostream::endl(out);
    }

  11. #11
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Oula attend, tu veux que l'appel à endl te trouve tout seul s'il s'agit de std::endl ou de ton endl ?

    Cela me parait tordu oO. Comme tu ne fais pas d'héritage, std::endl ne sera JAMAIS valide pour ta class my_ostream...

    Quant au switch/case sur du pointeur de fonction ou de l'extenstion de std... >< !

    =>Tu enlèves les std de Joe et ça devrait donner ce que tu veux (je crois) sans écorcher les yeux de quiconque ou presque.
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  12. #12
    Invité
    Invité(e)
    Par défaut
    Pourquoi vouloir enlever les std?
    Ca torture un peu le compilateur mais vu qu'il n'y a pas d'ambiguité(un ostream standard n'aura jamais d'operateur << acceptant un 'my_ostream& (*)(my_ostream&) et inversement) tout est réglé.
    J'ai quand même fait un petit test( avec mingw gcc 4.4) et tout compile et fonctionne.

  13. #13
    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
    Pourquoi vouloir enlever les std?
    Car ouvrir le namespace standard pour y mettre du code perso est casse geulle. Dès que quelqu'un va relire ton code, il ne va pas s'y retrouver
    "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)

  14. #14
    Membre à l'essai
    Étudiant
    Inscrit en
    Juin 2010
    Messages
    15
    Détails du profil
    Informations personnelles :
    Âge : 34

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2010
    Messages : 15
    Points : 11
    Points
    11
    Par défaut
    Salut tous,

    D'avance, excuser les accents merci et ma francais.

    Bon ce sujet la date un peu, mais il se trouve que je me retrouve confronte a ce probleme egalement.

    Alors je sais pas si depuis ca a change ou quoi depuis le temps, mais en fait, endl ne peut pas etre compris par ostream.
    Alors dans mon cas je voulais que ce quoi s'afficher sur la console soit aussi ecris dans un fichier. Alors jai fait ma propre classe.
    Mais ca bugais. Parce que en fait dans ma classe ja'vais ma fonctions pour ecrire qui etait xsputn. Du coup lors de l'appelle avec endl j' ecrivais un caractere (endl) dans un buffer et par consequent ma classe appelait automatiquement overflow.
    Il m'a suffit de la redefinir pour dire qu'a la place j'ecrivais pas un string mais un caractere avec put.

  15. #15
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    La bonne façon n'a pas changé. Il faut définir son streambuf et tout coule ensuite de source. Les articles d'Angelika Langer sur le sujet sont un très bon point de départ.

    Pour ton besoin d'écrire un "tee", un streambuf-filter qui va bien doit probablement déjà exister dans boost.iostream. Et ... bingo: http://stackoverflow.com/questions/9...xample-program
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

Discussions similaires

  1. Comment créer son propre #quelquechose
    Par Joooooon dans le forum Visual Studio
    Réponses: 3
    Dernier message: 04/08/2010, 11h23
  2. Comment créer son propre Widget Gtkmm?
    Par Greensource dans le forum GTK+ avec C & C++
    Réponses: 2
    Dernier message: 08/04/2009, 11h41
  3. Comment créer son propre logo ?
    Par jojo_ol76 dans le forum Imagerie
    Réponses: 7
    Dernier message: 15/01/2008, 15h03
  4. Comment créer son propre iterator ?
    Par kidpaddle2 dans le forum C++
    Réponses: 9
    Dernier message: 02/04/2007, 22h02
  5. Comment créer son propre logiciel de gestion ?
    Par Sayanne dans le forum Autres Logiciels
    Réponses: 8
    Dernier message: 11/04/2006, 18h03

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