2010-02-10 12 views
6

ich erstellen möchten einen Logger-Klasse, so dass mit einer Funktionalität wie folgt aus:wie kann ich einen Logger-Klasse mit COut Stil-Schnittstelle schreiben (Logger << „Fehler:“ << val << endl;)

Logger log; 
log << "Error: " << value << "seen" << endl; 

Dies sollte mir eine benutzerdefinierte formatierte Nachricht drucken. Z.B. „12-09-2009 11.22.33 Fehler 5 gesehen“

Meine einfache Klasse sieht derzeit wie folgt aus:

class Logger { 
    private: 
     ostringstream oss; 
    public: 
     template <typename T> 
     Logger& operator<<(T a); 
} 

template <typename T> 
Logger& Logger::operator<<(T a) { 
    oss << a; 
    return *this; 
} 

void functionTest(void) { 
    Logger log; 
    log << "Error: " << 5 << " seen"; 
} 

Diese oss richtig verursachen, um den Puffer „Fehler: 5 gesehen“ haben. Aber ich weiß nicht, welche andere Funktion ich schreiben/ändern muss, damit etwas auf dem Bildschirm gedruckt wird. Weiß jemand, wie man das zum Laufen bringt oder gibt es eine andere Möglichkeit, diese Klasse so zu gestalten, dass meine Funktionalität funktioniert?

+0

. Frage: Die Zeitstempel: Soll die Zeit abgelaufen sein: 1) Jeder Ausdruck 2) Nur am Anfang jeder Zeile Wollen Sie, dass die Zeile selbst terminiert (gemäß Ihrer Funktion Test()) Grundsätzlich müssen Sie ein bisschen mehr sein Spezifisch über die Bedingungen, unter denen der Zeitstempel hinzugefügt wird.Außerdem protokollieren Sie in einer Datei die Konsole beide? Warum brauchen Sie eine spezielle Klasse und warum können Sie nicht den Standard-Stream? –

+0

Martin, dies ist nur eine Beispielklasse Ich habe die ursprüngliche Logger-Klasse mit nur dem Problem bezüglich der Cout-Style-Verwendung reduziert von Logger. –

Antwort

1

Soweit ich Ihren Logger sehen kann, ist nicht anders als ostringstream. Es nimmt nur was gegeben ist und gibt es an den String-Stream aus. Wenn Sie es so verwenden möchten, können Sie einen Destruktor für Logger schreiben, der die Zeichenfolge an cout ausgibt.

Aber natürlich macht dies keinen Sinn, wenn ein Logger * im gesamten Programm erstellt und verwendet wird.

0

Diese (von this post) tut, was Sie wollen, aber es zwingt Sie jede Zeile mit std :: endl zu beenden:

class Logger { 
    private: 
     ostringstream oss; 
    public: 
     template <typename T> 
     Logger& operator<<(T a); 

    Logger& operator<<(std::ostream&(*f)(std::ostream&)) 
    { 
     if(f == std::endl) 
     { 
      std::cout << "12-09-2009 11:22:33" << oss.str() << std::endl; 
      oss.str(""); 
     } 
     return *this; 
    } 
}; 

template <typename T> 
Logger& Logger::operator<<(T a) { 
    oss << a; 
    return *this; 
} 

void functionTest(void) { 
    Logger log; 
    log << "Error: " << 5 << " seen" << std::endl; 
} 

int main() 
{ 
    functionTest(); 
} 

EDIT: Nun nach Ihren Kommentar scheint es nicht zu Sei was du willst. Dann empfehle ich Ihnen, wie MSalters sagen.

+0

Nach dem Ausgeben des Inhalts, wenn "std :: endl" ausgegeben wird, sollten Sie wahrscheinlich den Inhalt von "oss" löschen, damit die Ausgabe nicht in der nächsten Zeile wiederholt wird. –

+0

Nein, das kam mir auch in den Sinn. Aber ich möchte den Benutzer nicht zwingen, immer endl zu verwenden. Wie weiß Cout, wann es das Recht zum Drucken gibt? Es benötigt kein Endl vom Benutzer. –

+0

@David - danke, behoben @Dheeraj - Cout druckt Dinge, wie sie ankommen (Probleme beiseite puffern). – Manuel

4

Hinter jedem std::ostream ist ein streambuf. Es kann abgerufen und über std::stream::rdbuf() eingestellt werden. Insbesondere kann es umbrochen werden - Sie können ein Streambuf-Objekt bereitstellen, das den gestreamten Text nachbearbeitet. (Nachbearbeitungs bedeutet, dass Sie nicht std::cout << 123; von std::cout << "123"; unterscheiden können)

In Ihrem speziellen Fall

, ist die Nachbearbeitung ziemlich einfach. Zu Beginn jeder Zeile möchten Sie einige Bytes einfügen. Dies bedeutet lediglich, dass Sie verfolgen sollten, ob Sie das Präfix für die aktuelle Zeile bereits ausgegeben haben. Wenn nicht, tun Sie das und setzen Sie die Flagge. Und wenn Sie einen Zeilenumbruch sehen, setzen Sie ihn zurück. Ihr Streambuf-Wrapper hat nur einen einzigen bool Status.

1

Die Frage ist zu wählen, wann und wie Informationen synchronisiert werden sollen - nach Linie? Es ist also egal, ob es gepuffert ist oder nicht, es gibt keine andere Wahl, als EOL und die Informationen auf der Leitung zu steuern - es zu spülen oder direkte Ausgaben.

Auch wenn die destructor als EOL/Flush, verwendet werden soll

{ log << [anything]; } als Inline-lokalen Stack Klammern Syntax Protokoll des destructor die Klammern oder als std :: endl Verlassen aufrufen, entweder verwendet werden.

Sofern Implementierung Metaobjekts mit einigem append Operator wie ‚< <‘ oder „+‘, man die ganzen Weg verpflichtet ist, endet eine explizite Art und Weise zu verwenden, um die Linie zu beenden und oder bündig