2010-02-10 6 views
6

Voglio creare una classe logger in modo tale che con una funzionalità simile a questo:come faccio a scrivere una classe logger con cout l'interfaccia di stile (logger << "Errore:" << val << endl;)

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

Questo dovrebbe stamparmi un messaggio formattato personalizzato. Per esempio. "12-09-2009 11:22:33 Errore 5 visto"

mio semplice classe attualmente appare così:

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

Questo farà sì che OSS di avere correttamente il buffer di "Errore: 5 visto". Ma non so quale altra funzione ho bisogno di scrivere/modificare in modo che qualcosa venga stampato sullo schermo. Qualcuno sa come farlo funzionare o c'è un altro modo per progettare questa classe per far funzionare la mia funzionalità?

+0

. Domanda: L' time stamp. Vuoi stampare il timestamp: 1) Ogni espressione 2) Solo all'inizio di ogni riga. Vuoi che la linea si interrompa automaticamente (come per il tuo functionTest()). Fondamentalmente devi essere un po 'di più specificatamente sulle condizioni in cui viene aggiunta la marca temporale. Stai anche registrando su un file la console? Perché hai bisogno di una classe speciale e perché non puoi usare lo stream standard? –

+0

Martin, questa è solo una classe di esempio Ho rimosso la classe originale del logger con solo il problema riguardante l'uso dello stile cout di logger. –

risposta

1

Per quanto posso vedere il tuo registratore non è diverso da ostringstream. Prende solo ciò che viene dato e lo invia al flusso di stringhe. Se si desidera utilizzarlo in questo modo, è possibile scrivere un distruttore per Logger che restituisce la stringa a cout.

Logger::~Logger() 
{ 
    std::cout<<getcurrentDateTimeAsString()<<" "<<oss.str()<<std::endl; 
} 

Ma ovviamente, questo non ha senso se un Logger * viene creato e utilizzato in tutto il programma.

0

Questo (da this post) fa quello che vuoi, ma ti costringe a terminare ogni riga con std :: endl:

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: Ebbene secondo il tuo commento che non sembra Sii quel che vuoi essere. Allora ti raccomando di fare come dicono i MSalters.

+0

Dopo aver scaricato il contenuto quando viene prodotto 'std :: endl', probabilmente si dovrebbe cancellare il contenuto di' oss' in modo che l'output non venga ripetuto nella riga successiva. –

+0

No, mi è venuto in mente anche questo. Ma non voglio forzare l'utente ad usare sempre endl. In che modo cout sa quando è il diritto di stampare? Non ha bisogno di un endl da parte dell'utente. –

+0

@David - grazie, corretto @Dheeraj - cout stampa le cose non appena arrivano (problemi di buffering a parte). – Manuel

4

Dietro ogni std::ostream è un streambuf. La cabina può essere recuperata e impostata tramite std::stream::rdbuf(). In particolare, può essere spostato - è possibile fornire un oggetto streambuf che post-elabora il testo in streaming. (post-elaborazione significa che non è possibile distinguere std::cout << 123; da std::cout << "123";)

Nel tuo caso particolare, il post-processing è abbastanza semplice. All'inizio di ogni riga si desidera inserire alcuni byte. Questo significa semplicemente che dovresti tenere traccia di se hai già emesso il prefisso per la riga corrente. Altrimenti, fallo e imposta la bandiera. E ogni volta che vedi una nuova riga, resetta. Il tuo wrapper streambuf ha un solo valore di bool.

1

La domanda è scegliere quando e come le informazioni devono essere sincronizzate - per linea? Quindi, indipendentemente dal fatto che sia bufferizzato o no, non c'è altra scelta che controllare EOL e le informazioni sulla linea - flushing o output diretti.

Anche se il distruttore deve essere utilizzato come EOL/lavaggio,

{ log << [anything]; } come parentesi pila sintassi inline-locale per invocare distruttore di registro in uscita le staffe, o come std :: endl, né deve essere utilizzato.

A meno attuazione meta-oggetto con qualche operatore append come '< <' o "+', si terminano tutto il senso obbligato a utilizzare un modo esplicito per terminare la linea e oa filo