Ich bin auf der Suche nach einem portablen Weg, um eine faule Auswertung in C ++ für die Protokollierungsklasse zu implementieren. Nehmen wir an, ich habe eine einfache Protokollfunktion wie
%Vor%dann in syslog () Funktion können wir tun:
%Vor%also rufen wir eigentlich nie die Formatierungsfunktion (sprintf) auf. Auf der anderen Seite, wenn wir Logging-Stream wie
verwenden %Vor%all die Formatierung wird immer ausgeführt, was sehr viel Zeit in Anspruch nehmen kann. Gibt es eine Möglichkeit, alle Goodies von Ostream (wie benutzerdefinierte & lt; & lt; Operator für Klassen, Typ Sicherheit, elegante Syntax ...) tatsächlich so zu verwenden, dass die Formatierung ausgeführt wird, nachdem die Protokollierungsstufe überprüft wurde?
Dies sieht so aus, als könnte mit Vorlagen für Ausdrücke gehandhabt werden. Beachten Sie jedoch, dass Expression-Templates entschieden nicht-trivial zu implementieren sind.
Die allgemeine Vorstellung davon, wie sie funktionieren, besteht darin, dass die Operatoren einfach ein temporäres Objekt erstellen und dieses temporäre Objekt an Ihr Logging-Objekt übergeben. Das Protokollierungsobjekt würde auf die Protokollierungsebene schauen und entscheiden, ob die im temporären Objekt enthaltenen Aktionen ausgeführt werden sollen, oder es einfach verwerfen.
Was ich in unseren Apps getan habe, ist die Rückgabe von boost::iostreams::null_stream
für den Fall, dass die Protokollierungsebene diese Anweisung filtert. Das funktioniert einigermaßen gut, wird aber immer noch alle & lt; & lt; Betreiber.
Wenn die Protokollierungsstufe zur Kompilierungszeit festgelegt wird, können Sie zu einem Objekt mit einer Null & lt; & lt; Betreiber.
Ansonsten sind es Expressionsvorlagen, wie Jerry sagte.
Der einfachste und einfachste Weg ist, den Scheck einfach außerhalb der Formatierung zu verschieben:
%Vor%Wenn Sie den allgemeinen Fall wirklich verkürzen wollten, könnten Sie ein Makro verwenden:
%Vor%Aber die Einsparungen sind marginal.
Ein möglicher MyLogger:
%Vor%Das Problem besteht darin, iostream-artiges Überladen von Operatoren mit einer printf-ähnlichen Logging-Funktion zu kombinieren - speziell Manipulatoren zu übersetzen und Flags / Felder von iostreams in eine Formatzeichenkette zu formatieren. Sie könnten in einen Stringstream schreiben und diesen dann in Ihre syslog-Funktion einteilen oder etwas Zarteres ausprobieren. Der obige MyLogger funktioniert am einfachsten, wenn er auch einen ostream-Verweis enthält, auf den er weiterleiten kann, aber Sie benötigen noch ein paar weitere op & lt; & lt; Überlasten für iomanips (z. B. endl), wenn Sie das tun.
Für meine habe ich eine debug_ostream-Klasse erstellt, die & lt; & lt; Betreiber. Diese Operatoren prüfen die Debug-Ebene, bevor sie den echten Operator aufrufen.
Sie müssen Nicht-Template-Überschreibungen für const char*
und std::ostream& (*x)(std::ostream&)
definieren, da diese sonst nicht funktionieren. Ich bin mir nicht sicher warum.
Mit Inlining und ausreichend hohen Optimierungsleveln wird der Compiler die gesamte Ausgabezeile in eine einzige Überprüfung der Debug-Ebene anstatt einer pro Ausgabeelement verwandeln.
Ich sollte hinzufügen, dass dies das ursprüngliche Problem nicht löst. Wenn beispielsweise ein Teil der Debug-Zeile eine teure Funktion aufrufen soll, um einen Wert für die Ausgabe zu erhalten, wird diese Funktion trotzdem aufgerufen. Meine Lösung überspringt nur den Formatierungsaufwand.
Tags und Links c++ iostream logging lazy-evaluation