Question

Je veux définir une MyStream de classe afin que:

MyStream myStream;
myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl;

donne la sortie

[blah]123
[blah]56
[blah]78

En fait, je veux un "[bla]" inséré à l'avant, puis inséré après chaque non terminaison std::endl?

La difficulté ici est pas la gestion logique, mais la détection et la surcharge du traitement des std::endl. Y at-il une façon élégante de le faire?

Merci!

EDIT: Je ne ai pas besoin des conseils sur la gestion logique. Je dois savoir comment détecter / impression de surcharge de std::endl.

Était-ce utile?

La solution

Ce que vous devez faire est d'écrire votre propre tampon de flux:
Lorsque le tampon de flux est rincée vous sortie préfixer caractères et le contenu du flux.

Les travaux suivants, car std :: endl fait ce qui suit.

1) Ajouter '\ n' au flux.
2) Les appels flush () sur le flux
2a) Cela appelle pubsync () sur le tampon de flux.
2b) Ceci appelle la synchronisation de méthode virtuelle ()
2c) Remplacer cette méthode virtuelle pour faire le travail que vous voulez.

#include <iostream>
#include <sstream>

class MyStream: public std::ostream
{
    // Write a stream buffer that prefixes each line with Plop
    class MyStreamBuf: public std::stringbuf
    {
        std::ostream&   output;
        public:
            MyStreamBuf(std::ostream& str)
                :output(str)
            {}
            ~MyStreamBuf() {
                if (pbase() != pptr()) {
                    putOutput();
                }
            }

        // When we sync the stream with the output. 
        // 1) Output Plop then the buffer
        // 2) Reset the buffer
        // 3) flush the actual output stream we are using.
        virtual int sync() {
            putOutput();
            return 0;
        }
        void putOutput() {
            // Called by destructor.
            // destructor can not call virtual methods.
            output << "[blah]" << str();
            str("");
            output.flush();
        }
    };

    // My Stream just uses a version of my special buffer
    MyStreamBuf buffer;
    public:
        MyStream(std::ostream& str)
            :std::ostream(&buffer)
            ,buffer(str)
        {
        }
};


int main()
{
    MyStream myStream(std::cout);
    myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl;
}

> ./a.out
[blah]123 
[blah]56 
[blah]78
>

Autres conseils

Vos opérateurs surchargées de la classe MyStream doivent établir un était-endl précédent imprimé jeton drapeau.

Ensuite, si l'objet suivant est imprimé, le [blah] peut être inséré devant lui.

std::endl est une prise de fonction et de retourner une référence à std::ostream. Pour détecter il a été déplacé dans votre flux, vous devez surcharger le operator<< entre votre type et une telle fonction:

MyStream& operator<<( std::ostream&(*f)(std::ostream&) )
{
    std::cout << f;

    if( f == std::endl )
    {
        _lastTokenWasEndl = true;
    }

    return *this;
}

D'accord avec Neil principe.

Vous voulez changer le comportement du tampon, parce que c'est le seul moyen d'étendre iostreams. endl fait ceci:

flush(__os.put(__os.widen('\n')));

widen retourne un seul caractère, donc vous ne pouvez pas mettre votre chaîne là-dedans. put appelle putc qui n'est pas une fonction virtuelle et que des crochets de temps en temps overflow. Vous pouvez intercepter à flush, qui appelle la sync du tampon. Vous auriez besoin d'intercepter et de modifier tous les caractères de saut de ligne comme ils sont overflowed ou manuellement synced et les convertir à votre chaîne.

La conception d'une classe tampon prioritaire est gênant car basic_streambuf attend un accès direct à la mémoire tampon. Cela vous empêche de passer facilement les requêtes d'E / S à un basic_streambuf pré-existante. Vous devez aller sur une branche et supposons que vous connaissez la classe tampon de flux, et en tirer. (cin et cout ne sont pas garantis à utiliser basic_filebuf, autant que je peux dire.) Ensuite, il suffit d'ajouter virtual overflow et sync. (Voir §27.5.2.4.5 / 3 et 27.5.2.4.2 / 7.) Exécution de la substitution peuvent nécessiter un espace supplémentaire veillez donc à allouer cette avance.

- OU -

Il suffit de déclarer une nouvelle endl dans votre propre espace de noms, ou mieux, un manipulateur qui n'est pas appelé endl du tout!

Au lieu de tenter de modifier le comportement de std::endl, vous devriez probablement créer un streambuf de filtrage pour faire le travail. James Kanze a montrant comment insérer un horodatage au début de chaque ligne de sortie. Il devrait exiger que des modifications mineures de changer cela à tout ce préfixe que vous voulez sur chaque ligne.

J'utilise des pointeurs de fonction. Il semble terrifiant à des gens qui ne sont pas utilisés à C, mais il est beaucoup plus efficace dans la plupart des cas. Voici un exemple:

#include <iostream>

class Foo
{
public:
    Foo& operator<<(const char* str) { std::cout << str; return *this; }
    // If your compiler allows it, you can omit the "fun" from *fun below.  It'll make it an anonymous parameter, though...
    Foo& operator<<(std::ostream& (*fun)(std::ostream&)) { std::cout << std::endl; }
} foo;

int main(int argc,char **argv)
{
    foo << "This is a test!" << std::endl;
    return 0;
}

Si vous voulez vraiment vous pouvez vérifier l'adresse de endl confirmer que vous ne recevez pas une autre fonction vide / vide, mais je ne pense pas que cela vaut la peine dans la plupart des cas. J'espère que cela aide.

Vous ne pouvez pas changer std::endl - comme son nom l'indique est une partie de la bibliothèque standard C ++ et son comportement est fixe. Vous devez changer le comportement du flux lui-même, lorsqu'il reçoit une fin de ligne. Personnellement, je ne l'aurais pas pensé que cela vaut la peine, mais si vous voulez vous aventurer dans ce domaine, je recommande fortement la lecture du livre standard C ++ et iostreams Paramètres régionaux.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top