Stringstream Sub Klasse mit eigenen Manipulatoren



  • Hi,

    Habe mir eine kleine Logger Klasse geschrieben mit der Ich über ein cout ähnliches verhalten also z.B.:

    Logger.h

    LOGGER << error << e.what() << print;
    

    Einen Log eintrag erzeugen möchte.

    Das ganze sieht dann ungefär so aus.

    #ifndef _LOGH_
    #define _LOGH_
    #include <sstream>
    #include <syslog.h>
    #include <iostream>
    
    class LOG : public std::stringstream{
    	public:
    	enum class PRIORITIES : int;
    
    	LOG();
    	~LOG();
    	void setLevel( PRIORITIES level );
    	void setDestination( std::string identifier );
    	void printMessage();
    
    	private:
    	PRIORITIES level;
    
    };
    
    extern LOG LOGGER;
    
    LOG &emergency(LOG &out);
    LOG &alert(LOG &out);
    LOG &critical(LOG &out);
    LOG &error(LOG &out);
    LOG &warning(LOG &out);
    LOG &notice(LOG &out);
    LOG &info(LOG &out);
    LOG &debug(LOG &out);
    LOG &print(LOG &out);
    
    #endif
    

    Logger.cpp

    #ifndef _LOGCPP_
    #define _LOGCPP_
    #include "LOG.h"
    
    LOG LOGGER;
    
    enum class LOG::PRIORITIES{ EMERGENCY = LOG_EMERG, ALERT = LOG_ALERT, CRITICAL = LOG_CRIT, ERROR = LOG_ERR, WARNING = LOG_WARNING, NOTICE = LOG_NOTICE, INFO = LOG_INFO, DEBUG = LOG_DEBUG };
    
    LOG::LOG(){
    	closelog();
    	openlog( "d_console", LOG_PID, LOG_DAEMON );
    }
    
    LOG::~LOG(){
    	closelog();
    }
    
    void LOG::setLevel( PRIORITIES level ){
    	this->level = level;
    }
    
    void LOG::setDestination( std::string identifier ){
    	closelog();
    	openlog( identifier.c_str(), LOG_PID, LOG_DAEMON );
    }
    
    void LOG::printMessage(){
    	std::cout << "should print: " << this->str() << std::endl;
    	syslog( (int)level, "%s", this->str().c_str() );
    	this->clear();
    }
    
    LOG &emergency(LOG &out){
    	out.setLevel(LOG::PRIORITIES::EMERGENCY);
    	return out;
    }
    
    LOG &alert(LOG &out){
    	out.setLevel(LOG::PRIORITIES::ALERT);
    	return out;
    }
    
    LOG &critical(LOG &out){
    	out.setLevel(LOG::PRIORITIES::CRITICAL);
    	return out;
    }
    
    LOG &error(LOG &out){
    	out.setLevel(LOG::PRIORITIES::ERROR);
    	return out;
    }
    
    LOG &warning(LOG &out){
    	out.setLevel(LOG::PRIORITIES::WARNING);
    	return out;
    }
    
    LOG &notice(LOG &out){
    	out.setLevel(LOG::PRIORITIES::NOTICE);
    	return out;
    }
    
    LOG &info(LOG &out){
    	out.setLevel(LOG::PRIORITIES::INFO);
    	return out;
    }
    
    LOG &debug(LOG &out){
    	out.setLevel(LOG::PRIORITIES::DEBUG);
    	return out;
    }
    
    LOG &print(LOG &out){
    	out.printMessage();
    	return out;
    }
    
    #endif
    

    Das Problem das Ich derzeitig habe ist das beim Aufruf nach dem Beispiel nicht viel Passiert. Der Compiller gibt mir Warnungen mit:

    warning: the address of ‘LOG& error(LOG&)’ will always evaluate as ‘true’
    

    Und Ich glaube das das zusammen hängt aber Ich sehe den Fehler nicht.

    Könnte mir da jemand bitte weiterhelfen?



  • Nachdem Ich die Augen wieder nen stück weit geöffnet hab hab Ich den Fehler auch schon gefunden. Trotzdem danke. Ich weiß das wenn ich zu ner freundlicheren Zeit gepostet hätte hier wohl mittlerweile auch schon eine Antwort hätte.

    Wen es interessiert, es hat

    LOG& operator<<(LOG& (*m)(LOG&));
    

    mit

    LOG& LOG::operator<<(LOG& (*m)(LOG&)){  
    	return (*m)(*this);
    }
    

    im code gefehlt



  • Dachte ich,

    Hahaha.. ich geb auf für heute.



  • TheOneWhoShallBeNamed schrieb:

    Logger.h

    #ifndef _LOGH_
    #define _LOGH_
    #include <sstream>
    #include <syslog.h>
    #include <iostream>
    
    class LOG : public std::stringstream{
    	public:
            // ...
    

    es ist wohl ein Fehler, den jeder C++-Programmierer einmal gemacht haben haben muss.
    Grundsätzlich ist es nicht zu empfehlen, seine LOG-Klasse von std::stringstream (oder std::fstream oder egal-stream) abzuleiten. Weil dann genau passiert, was hier auch passiert, nämlich der Zwang alle möglichen inserters (operator<<) zu überladen.

    Abgesehen von der (überflüssigen) Arbeit zieht das auch noch Arbeit bei jeder Klasse nach sich, die in das LOG ausgegeben werden soll.

    Die einfachere Variante ist, die LOG-Klasse von einem std::streambuf abzuleiten und anschließend einen std::ostream seiner Wahl (std::cout, std::clog oder ein eigenes Objekt) auf eben diesen Streambuf umzuleiten (mit rdbuf). Siehe auch IoSwitch.



  • Was ist denn das Problem?
    Wenn er eine neue Klasse einführt, überlädt er einfach operator << für ostream und kann sie auch im Logger verwenden.
    Oder verstehe ich da etwas falsch?

    Edit: Includeguard in einem Sourcefile macht irgendwie wenig Sinn.



  • Nathan schrieb:

    Was ist denn das Problem?
    Wenn er eine neue Klasse einführt, überlädt er einfach operator << für ostream und kann sie auch im Logger verwenden.
    Oder verstehe ich da etwas falsch?

    ja - Du hast Recht. Zumindest solange der Anwender die Reihenfolge bei der Ausgabe einhält und den eigenen Manipulator immer am Anfang der Ausgabe schreibt.


Log in to reply