Überlast Umgang mit std :: endl?
-
19-09-2019 - |
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
.
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 overflow
ed werden oder manuell sync
ed 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 .