2009-02-04 7 views
10

Mam działającą klasę rejestratora, która wyprowadza jakiś tekst do pliku richtextbox (Win32, C++). Problem w tym, że zawsze kończy się przy użyciu to tak:Jak używać mojej klasy logowania jak std C++ stream?

stringstream ss; 
ss << someInt << someString; 
debugLogger.log(ss.str()); 

zamiast byłoby znacznie wygodniej jest używać go jak strumień, jak w:

debugLogger << someInt << someString; 

Czy istnieje lepszy sposób niż przekazywanie wszystkiego do wewnętrznej instancji Stringstream? Jeśli to zrobisz, kiedy będę musiał spłukać?

Odpowiedz

28

Musisz wdrożyć operator << odpowiednio dla swojej klasy. Ogólny wzór wygląda następująco:

template <typename T> 
logger& operator <<(logger& log, T const& value) { 
    log.your_stringstream << value; 
    return log; 
} 

Zauważ, że to dotyczy (nie const) odniesienia, ponieważ operacja modyfikuje swój rejestrator. Zauważ też, że trzeba powrócić parametr log w celu łączenia do pracy:

log << 1 << 2 << endl; 
// is the same as: 
((log << 1) << 2) << endl; 

Jeśli najgłębsza operacja nie wrócił aktualny log instancji, wszystkie inne operacje byłyby albo nie w czasie kompilacji (zła metoda podpis) lub zostałby połknięty w czasie wykonywania.

+0

Jak poradziłbym sobie z "problemem spłukiwania", tzn. W pewnym momencie muszę wysłać wszystko do mojego richtextboxa. Czy powinienem przetestować wartość przychodzącą dla "linii końcowej"? – newgre

+0

To jest osobne pytanie, ale odpowiedź jest prosta: zamiast używać "\ n", użyj końcówki! Spowoduje to automatyczne opróżnienie strumienia. Jednakże, aby podłączyć TextBox do strumienia, zasadniczo musisz zaimplementować własny bufor strumienia (spójrz na metodę rdbuf). –

+1

Lub dodaj własny typ manipulatora, który naśladuje koniec/końce, z przeciążeniem operatora << w celu jego wykrycia. – Kylotan

1

W klasie Logger przesłonięcie operatora < <.

Kliknij opcję Here, aby dowiedzieć się, jak zaimplementować operatora < <.

Można również unikać instrukcji rejestrowania w kodzie za pomocą programowania zorientowanego na aspekt.

+2

dostaję 404 na ten link. –

14

Przeciążenie operatora wstawiania < < nie jest drogą do zrobienia. Będziesz musiał dodać przeciążenia dla wszystkich endl lub innych zdefiniowanych przez użytkownika funkcji.

Jedną z dróg jest zdefiniowanie własnego strebufu i powiązanie go ze strumieniem. Następnie wystarczy użyć strumienia.

Oto kilka prostych przykładów:

+0

_ "Będziesz musiał dodać przeciążenia dla wszystkich endl lub innych funkcji zdefiniowanych przez użytkownika." _ To jest jedno przeciążenie. –

+0

@LightnessRacesinOrbit To więcej niż jedno przeciążenie, ponieważ musimy zająć się 'endl',' flush', 'hex',' setw' i tak dalej. W końcu trzeba zdefiniować kilka przeciążeń. Możemy zmniejszyć liczbę przeciążeń dzięki szablonom, ale to nie jest najlepsze podejście. –

+0

Nie, jedno przeciążenie jest wymagane dla nich wszystkich. Standardowa biblioteka jest zaprojektowana w ten sposób. –

0

As Luc Hermitte noted , jest artykuł "Logging In C++", który opisuje bardzo schludne podejście do rozwiązania tego problemu. W skrócie, zważywszy masz funkcji takich jak następuje:

void LogFunction(const std::string& str) { 
    // write to socket, file, console, e.t.c 
    std::cout << str << std::endl; 
} 

można napisać otoki na używanie go w std :: cout podobny sposób:

#include <sstream> 
#include <functional> 

#define LOG(loggingFuntion) \ 
    Log(loggingFuntion).GetStream() 

class Log { 
    using LogFunctionType = std::function<void(const std::string&)>; 

public: 
    explicit Log(LogFunctionType logFunction) : m_logFunction(std::move(logFunction)) { } 
    std::ostringstream& GetStream() { return m_stringStream; } 
    ~Log() { m_logFunction(m_stringStream.str()); } 

private: 
    std::ostringstream m_stringStream; 
    LogFunctionType m_logFunction; 
}; 

int main() { 
    LOG(LogFunction) << "some string " << 5 << " smth"; 
} 

(online demo)

Ponadto, istnieje bardzo ładne solution dostarczone przez Stewart.

0

eleganckie rozwiązanie, które również rozwiązuje problemy płukania jest następujący:

#include <string> 
#include <memory> 
#include <sstream> 
#include <iostream> 

class Logger 
{ 
    using Stream = std::ostringstream; 
    using Buffer_p = std::unique_ptr<Stream, std::function<void(Stream*)>>; 

public: 
    void log(const std::string& cmd) { 
     std::cout << "INFO: " << cmd << std::endl; 
    } 

    Buffer_p log() { 
     return Buffer_p(new Stream, [&](Stream* st) { 
      log(st->str()); 
     }); 
    } 
}; 

#define LOG(instance) *(instance.log()) 

int main() 
{ 
    Logger logger; 
    LOG(logger) << "e.g. Log a number: " << 3; 
    return 0; 
}