Domanda

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

dovrebbe espandersi in:

std::ostringstream oss;
oss << 1 << "hello world" << blah->getValue() << std::endl;
ThreadSafeLogging(oss.str());
È stato utile?

Soluzione

#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;
}

Una temporanea di tipo my_stream è stato creato, che è una sottoclasse di ostringstream. Tutte le operazioni a che il lavoro temporaneo come farebbero su un ostringstream.

Quando l'istruzione estremità (es. Subito dopo il punto e virgola in tutta l'operazione di stampa in main ()), l'oggetto temporaneo va fuori del campo di applicazione e viene distrutto. Le chiamate my_stream destructor ThreadSafeLogging con i dati "raccolti" in precedenza.

Tested (g ++).

Grazie / crediti a dingo per aver ricordato come semplificare il tutto, quindi non ho bisogno del operator<< sovraccarico. Peccato upvotes non possono essere condivise.

Altri suggerimenti

Non potevi solo derivare da ostream e fornire il proprio thread-safe implementazione? Poi si può solo fare

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

E ottenere la stessa identica funzionalità senza macro e l'utilizzo di C ++ correttamente?

No. Il problema è che senza utilizzando la sintassi funzione, una macro è limitato al solo sostituito dove sia.

Ma se erano disposti ad utilizzare la sintassi funzione, è quindi possibile sostituire roba sia prima che dopo le args.

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

Si potrebbe definendo MyMacro come:

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

Date un'occhiata al google-glog , lo fanno utilizzando un oggetto temporaneo istanziare con un

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

e hanno anche altre macro interessanti, come LOG_IF et al.

In considerazione di avere queste linee inclusi da qualche parte nel codice, sì è possibile

#include <iostream>
#include <sstream> 

macro __LINE__ è definito da tutti i compilatori standart. Così possiamo utilizzare per generare un nome di variabile, che è diversa ogni volta che si utilizza la macro:)

Ecco una nuova versione che è visto come solo un uno-dichiarazione: (Montaggio)

#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 probabilmente non è necessario utilizzare questa macro due volte sulla stessa linea lo stavano ristrutturando di semplicità dell'operatore <<. Ma nel caso in cui avete bisogno di questo, è possibile cambiare l'uso di __LINE__ da __COUNTER__ (che non è di serie!). Grazie a Quuxplusone per questo suggerimento

Ecco un altro brutto scherzo che ho visto da qualche altra parte. Ha un notevole svantaggio rispetto al mio altra risposta: non è possibile utilizzare due volte nello stesso ambito, perché dichiara una variabile. Tuttavia, può essere ancora interessante per altro i casi in cui si desidera avere run somemacro foo qualcosa di dopo foo.

#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;
}

Il setup di registrazione che ho è abbastanza simile:

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)

Se la registrazione è disattivata, l'ostream viene mai creato ed esiste poco overhead. È possibile configurare la registrazione sul nome del file e numero di linea (s) o livelli di priorità. La funzione ShouldLog può cambiare tra le invocazioni, così si potrebbe strozzare o uscita limite. L'uscita log utilizza due funzioni di modificarsi, prefisso che aggiunge un "file: riga: (PRIO)" il prefisso alla linea, e filo () che entrambi espelle verso l'uscita log come unico comando e aggiunge una nuova riga ad essa . Nella mia applicazione lo fa sempre, ma si può fare che condizionale se uno non è già presente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top