Frage

Ich möchte eine Klasse MyStream damit definieren:

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

gibt Ausgang

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

Im Grunde möchte ich ein "[bla]" an der Front eingesetzt, dann eingesetzt, nachdem alle nicht abschließende std::endl?

Die Schwierigkeit hierbei ist nicht die Logik-Management, sondern Erkennen und den Umgang mit std::endl Überlastung. Gibt es eine elegante Art und Weise, dies zu tun?

Danke!

EDIT: Ich brauche keine Ratschläge zum Logik-Management. Ich muss wissen, wie zu erkennen / Überlastdruck von std::endl.

War es hilfreich?

Lösung

Was Sie tun müssen, ist Ihren eigenen Strompuffer schreiben:
Wenn der Strompuffer Sie Ausgang gespült wird als Präfix Zeichen und den Inhalt des Stroms.

Die folgenden funktioniert, weil std :: endl folgende Ursachen.

1) Add '\ n' in den Stream.
2) Anrufe flush () auf dem Strom
2a) Dies erfordert pubsync () auf dem Strompuffer.
2b) Dies ruft die virtuelle Methode sync ()
2c) Überschreiben Sie diese virtuelle Methode, um die Arbeit, die Sie tun möchten.

#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
>

Andere Tipps

Ihre überladenen Operatoren der MyStream Klasse haben einen vorherigen druckten-token-war-Endl-Flag zu setzen.

Dann wird, wenn das nächste Objekt gedruckt wird, kann der [blah] davor eingefügt werden.

std::endl ist eine Funktion Mitnahmen und der Rückkehr einen Verweis auf std::ostream. Um festzustellen, wurde es in Ihrem Stream verschoben, müssen Sie die operator<< zwischen Ihrem Typ überlasten und eine solche Funktion:

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

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

    return *this;
}

Vereinbarte mit Neil grundsätzlich.

Sie möchten das Verhalten des Puffers ändern, weil das der einzige Weg ist, iostreams zu verlängern. endl tut dies:

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

widen gibt ein einzelnes Zeichen, so können Sie Ihre Zeichenfolge dort nicht setzen. put ruft putc, die keine virtuelle Funktion ist und nur Haken gelegentlich overflow. Sie können an flush abfangen, die den Puffer des sync aufruft. Sie müssten alle Zeilenumbrüche abfangen und ändern, da sie overflowed werden oder manuell synced und wandeln sie in der Zeichenfolge.

Entwerfen eine Überschreibung Pufferklasse ist mühsam, weil basic_streambuf direkten Zugang zu seinem Pufferspeicher erwartet. Dies verhindert, dass Sie leicht zu einem bereits existierenden basic_streambuf I / O-Anfragen übergeben. Sie müssen auf einem Bein gehen und nehme an, Sie den Strompuffer Klasse kennen, und leiten daraus. (cin und cout nicht benutzen basic_filebuf garantiert, soweit ich das beurteilen kann.) Dann einfach virtual overflow und sync hinzufügen. (Siehe §27.5.2.4.5 / 3 und 27.5.2.4.2 / 7.) Durchführung der Substitution zusätzlichen Platz benötigen, so vorsichtig sein, dass zuzuteilen vor der Zeit.

- oder -

erklären Sie einfach einen neuen endl in Ihrem eigenen Namensraum, oder besser, einen Manipulator, der nicht endl überhaupt genannt wird!

Anstatt zu versuchen, das Verhalten von std::endl zu ändern, sollten Sie wahrscheinlich einen Filter streambuf schaffen den Job zu erledigen. James Kanze hat eine Beispiel rel="nofollow das zeigt, wie ein Zeitstempel am Anfang jeden einfügen Ausgangsleitung. Es sollte nur eine geringe Änderung verlangt, dass zu ändern, was auch immer Präfix Sie in jeder Zeile werden sollen.

Ich verwende Funktionszeiger. Es klingt erschreckend für Menschen, die nicht zu C verwendet werden, aber es ist viel effizienter in den meisten Fällen. Hier ein Beispiel:

#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;
}

Wenn Sie wirklich wollen Sie die Adresse für die endl überprüfen, um zu bestätigen, dass Sie nicht eine andere Leere / Leere Funktion bekommen, aber ich glaube nicht, es lohnt sich in den meisten Fällen. Ich hoffe, das hilft.

Sie können nicht std::endl ändern - wie der Name schon suggeriert es ein Teil des C ++ Standard Library ist und sein Verhalten festgelegt ist. Sie müssen das Verhalten des Stroms selbst ändern, wenn es ein Ende der Leitung empfängt. Persönlich würde ich nicht gedacht diese den Aufwand wert, aber wenn Sie in diesem Bereich wagen möchte ich dringend empfohlen, das Buch zu lesen Standard C ++ iostreams & Locales .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top