Frage

my_macro << 1 << "hello world" << blah->getValue() << std::endl;

sollte in erweitern:

std::ostringstream oss;
oss << 1 << "hello world" << blah->getValue() << std::endl;
ThreadSafeLogging(oss.str());
War es hilfreich?

Lösung

#define my_macro my_stream()
class my_stream: public std::ostringstream  {
public:
    my_stream() {}
    ~my_stream() {
        ThreadSafeLogging(this->str());
    }
};
int main() {
    my_macro << 1 << "hello world" << std::endl;
}

Ein temporäres vom Typ my_stream geschaffen, die eine Unterklasse von ostringstream ist. Alle Operationen in dieser Leiharbeit ähnlich wie bei einer ostringstream.

Wenn die Anweisung Ende (dh. Direkt nach dem Semikolon auf dem gesamten Druckvorgang in main ()), wird das temporäre Objekt geht der Anwendungsbereich und wird zerstört. Die my_stream destructor Anrufe ThreadSafeLogging mit den Daten "gesammelt" zuvor.

Geprüft (g ++).

Danke / Kredite an Dingo für den Hinweis auf, wie die ganze Sache zu vereinfachen, so brauche ich nicht die überladene operator<<. Schade upvotes nicht mit anderen geteilt werden können.

Andere Tipps

Könnten Sie nicht ableiten nur von ostream und geben Sie Ihre eigenen Thread sichere Implementierung? Dann könnten Sie gerade tun

myCOutObject << 1 << "hello world" << blah->getValue() << std::endl;

Und Sie erhalten genau die gleiche Funktionalität ohne Makros und C ++ richtig?

Nein. Das Problem ist, dass es ohne Funktion Syntax, ein Makro nur ersetzt beschränkt zu sein, wo es ist.

Aber wenn Sie bereit sind, Funktionssyntax zu verwenden, können Sie dann Sachen ersetzen sowohl vor als auch nach dem args.

my_macro(1 << "hello world" << blah->getValue() << std::endl);

Sie könnten durch die Definition MyMacro wie:

#define my_macro(args) std::ostreamstring oss; \
                       oss << args; \
                       ThreadSafeLogging(oss.str());

Hier finden Sie aktuelle google-glog , sie tun dies mit einem temporären Objekt instanziiert mit einem

LOG(INFO) << "log whatever" << 1;

, und sie haben auch andere interessante Makros wie LOG_IF et al.

In Anbetracht haben Sie diese Zeilen irgendwo im Code enthalten ist, ja, es ist möglich

#include <iostream>
#include <sstream> 

__LINE__ Makro wird von allen standart Compiler definiert. Also haben wir es verwenden können, einen Variablennamen erzeugen Weichen anders jedes Mal verwenden Sie das Makro:)

Hier ist eine neue Version, die nur als One-Anweisung Anweisung zu sehen ist: (Edited)

#define Var_(Name, Index) Name##Index
#define Var(Name, Index) Var_(Name, Index)
#define my_macro \
for (struct { int x; std::ostringstream oss; } Var(s, __LINE__) = { 0 }; \
     Var(s, __LINE__).x<2; ++Var(s, __LINE__).x)  \
    if (Var(s, __LINE__).x==1) ThreadSafeLogging(Var(s, __LINE__).oss.str()); \
    else Var(s, __LINE__).oss

// So you can use it like this 
int main() 
{ 
    if (4 != 2)
        my_macro << 4 << " hello "  << std::endl; 
    my_macro << 2 << " world !" << std::endl; 
} 

Developper wird wahrscheinlich nicht brauchen dieses Makro zu verwenden zweimal auf derselben Linie becasue der Einfachheit des Operators <<. Aber falls Sie diese benötigen, können Sie die Verwendung von __LINE__ von __COUNTER__ wechseln (was nicht Standard ist!). Dank Quuxplusone für diesen Tipp

Hier ist eine andere fiese Trick, den ich sah woanders. Es hat einen erheblichen Nachteil im Vergleich zu meiner anderen Antwort: Sie können nicht im gleichen Umfang nutzen zweimal, weil es eine Variable deklariert. Es kann aber immer noch interessant sein, für andere Fälle, in denen Sie somemacro foo läuft etwas nach foo.

haben wollen
#define my_macro \
    std::ostringstream oss; \
    for (int x=0; x<2; ++x) \
        if (x==1) ThreadSafeLogging(oss.str()); \
        else oss

int main() {
    my_macro << 1 << "hello world" << std::endl;
}

Der Logging-Setup ich habe, ist ganz ähnlich:

bool ShouldLog(const char* file, size_t line, Priority prio);

class LoggerOutput : public std::stringstream {
public:
  LoggerOutput(const char* file, size_t line, Priority prio) 
  : prio(prio) 
  {
    Prefix(file, line, prio);
  }
  void Prefix(const char* file, size_t line, Priority prio);
  ~LoggerOutput() {
    Flush();
  }
  void Flush();
private:
  Priority prio;
};

#define LOG(Prio) if (!Logging::ShouldLog(__FILE__, __LINE__, Prio)) {} else Logging::LoggerOutput(__FILE__, __LINE__, Prio)

Wenn die Protokollierung deaktiviert ist, wird die Ostream nie erstellt und wenig Overhead vorhanden. Sie können die Protokollierung auf Dateinamen und die Zeilennummer (n) oder Prioritätsstufen konfigurieren. Die ShouldLog Funktion kann zwischen Anrufungen ändern, so dass Sie oder Grenzausgabe drosseln könnte. Die Protokollausgabe verwendet zwei Funktionen selbst Präfix zu ändern, die einen fügt „file: Zeile: (PRIO)“ prefix zu der Linie, und Flush (), die beide spült sie in die Protokollausgabe als einen einzigen Befehl und fügt eine neue Zeile, um es . In meiner Implementierung tut es immer, aber Sie können das davon abhängig machen, wenn man nicht bereits vorhanden ist.

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