Lazy-Evaluierung mit Ostream C ++ - Operatoren

8

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?

    
SavinG 17.02.2011, 23:07
quelle

4 Antworten

4

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.

    
Jerry Coffin 17.02.2011 23:13
quelle
4

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.

    
Macke 17.02.2011 23:21
quelle
3

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.

    
Fred Nurk 18.02.2011 00:04
quelle
2

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.

    
Zan Lynx 17.02.2011 23:31
quelle