2010-02-10 15 views
6

Chcę utworzyć klasę rejestratora taki, że z funkcji takich jak to:jak mogę napisać klasy rejestratora z cout styl interfejsu (logger << "Błąd:" << endl << val;)

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

To powinno wydrukować niestandardową sformatowaną wiadomość. Na przykład. „09.12.2009 11:22:33 Błąd 5 widział”

Moja prosta klasa aktualnie wygląda tak:

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

Spowoduje OSS poprawnie mieć bufor „Błąd: 5 widział”. Ale nie wiem, jaką inną funkcję muszę napisać/zmodyfikować, żeby coś zostało wydrukowane na ekranie. Czy ktoś wie, jak uzyskać to do pracy lub czy istnieje inny sposób zaprojektowania tej klasy, aby moja funkcjonalność działała?

+0

Pytanie: Lokalizacja. znacznik czasu Czy chcesz wyłączyć znacznik czasu: 1) Każde wyrażenie 2) Tylko na początku każdego wiersza Czy chcesz, aby linia sama się zakończyła (jak na twoją funkcję Test()). Zasadniczo potrzebujesz trochę więcej szczegółowe informacje na temat warunków, w których dodawany jest znacznik czasu.Jeśli logujesz się do pliku konsoli zarówno? Dlaczego potrzebujesz specjalnej klasy i dlaczego można; t używać standardowego strumienia? –

+0

Martin, to tylko przykładowa klasa Obnażyłem klasę oryginalnego rejestratora tylko z problemem dotyczącym użycia stylu cout logger. –

Odpowiedz

1

O ile widzę twój logger nie różni się od ostringstream. Po prostu bierze to, co jest dane, i wysyła je do strumienia napisów. Jeśli chcesz go użyć w ten sposób, możesz napisać destruktor dla Logger, który wysyła ciąg do cout.

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

Ale to nie ma sensu, jeśli Logger * zostanie utworzony i użyty w całym programie.

0

ten (od this post) robi to, co chcesz, ale to zmusza cię do końca każdą linię 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: Dobrze według Twojego komentarza to nie wydaje się bądź kim chcesz. Następnie zalecam robić tak, jak mówią MSalters.

+0

Po wyrzuceniu zawartości podczas wyprowadzania 'std :: endl', prawdopodobnie powinieneś wyczyścić zawartość' oss', aby dane wyjściowe nie były powtarzane w następnej linii. –

+0

Nie, to też przyszło mi do głowy. Ale nie chcę zmuszać użytkownika do używania zawsze końcówki. W jaki sposób cout wie, kiedy ma prawo do druku? Nie wymaga endl od użytkownika. –

+0

@David - dzięki, naprawiono @Dheeraj - cout drukuje rzeczy po ich nadejściu (problemy z buforowaniem). – Manuel

4

Za każdym std::ostream jest streambuf. Kabinę tę można odzyskać i ustawić za pomocą std::stream::rdbuf(). W szczególności można go zawijać - można udostępnić obiekt streambuf, który przetwarza przetwarzany tekst. (postprocessing oznacza, że ​​nie można odróżnić std::cout << 123; od std::cout << "123";)

W danym przypadku, postprocessing jest dość prosta. Na początku każdej linii chcesz wstawić kilka bajtów. Oznacza to jedynie, że powinieneś śledzić, czy już wypisałeś prefiks dla bieżącego wiersza. Jeśli nie, zrób to i ustaw flagę. A gdy zobaczysz znak nowej linii, zresetuj go. Twoje opakowanie strebuf ma tylko jedną wartość stanu: bool.

1

Pytanie dotyczy wyboru czasu i sposobu zsynchronizowania informacji - po linii? Bez względu na to, czy jest zbuforowana, czy nie, nie ma innego wyjścia, jak tylko kontrolować EOL i informacje na linii - opróżnianie lub bezpośrednie wyprowadzanie.

Nawet jeśli destruktor ma być używany jako EOL/Flush,

{ log << [anything]; } jako inline-local wsporniki stos składni powołania destructor LOG na wyjściu wsporniki lub jako std :: endl, albo muszą być stosowane.

ile wdrożenie metaobiektów z jakiegoś operatora dopisywania takich jak „< <” lub „+”, jesteś kończąc całą drogę obowiązku korzystania wyraźny sposób, aby zakończyć linię i czy równo