printf Parameter übergeben



  • Huhu! 🙂

    Hmm...ich sitze gerade daran mir eine Logfile Klasse zu schreiben.

    Bisher kann ich so einen Logeintrag vornehmen:

    int myInt = 42;
    mLog->log("Mein Integerwert: " + myStringTools::to_string(myInt));
    

    Die Methode der Logklasse sieht dabei so aus:

    void log_creator::log(string &ctext)
    {
    //schreibe ctext String in Log Datei
    ...
    }
    

    So weit.. so umständlich.

    Viel praktischer wäre es natürlich wenn ich im printf Stil meine Logs so schreiben könnte:

    int myInt = 42;
    mLog->log("Mein Integerwert: %d", myInt);
    

    Aber wie übergebe ich diesen Parametermischmasch an meine ::log() Funktion?



  • edit: oops


  • Administrator

    Von der Version, wie es printf macht, würde ich abraten, erst recht in C++. Es stehen dir allerdings verschiedene andere Möglichkeiten offen. Vor allem über operatoren und templates lässt sich sowas gut lösen.
    Du könntest dir mal boost::format anschauen oder wögmlich sogar gleich verwenden:
    http://www.boost.org/doc/libs/1_36_0/libs/format/index.html

    Grüssli



  • Hey, Dravere.

    Danke für den Tipp soweit.

    Hab mal bissl damit rumgebastelt...

    ... log() überladen:

    void log_creator::log(const boost::format& f)
    {
    	log(boost::str(f));
    }
    

    und nu kann ich schon mal so loggen:

    mLog->log(boost::format("test1: %d lala2: %d yago: %d") % 21 % 32 % 43);
    //Output: test1: 21 lala2: 32 yago: 43
    

    Nur das boost::format() is noch'n Schönheitsfehler.

    Hier hat wohl einer schon 'n Template für gebastelt... aber... ich hab weder Ahnung, was da passiert... noch kompiliert das.

    Grml.


  • Administrator

    Naja, wie gesagt, du könntest es ähnlich, wie boost::format selber lösen. Ich habe da zum Beispiel jetzt auch stark an die C++ Streams gedacht und mal ein kurzes Beispiel zusammengebaut, um dir einen Denkanstoss zu geben 😉

    #include <list>
    #include <string>
    #include <sstream>
    #include <iostream>
    
    //////////////////////////////////////////////////////////////////////////
    // Log
    
    class Log
    {
    	// Enums //
    public:
    	enum Action { SAVE };
    
    	// Attributes //
    private:
    	std::list<std::string> m_logMessages;
    
    	std::string m_nextMessage;
    
    	// Constructors & Destructor //
    public:
    	Log() { };
    	~Log() { };
    
    	// Methods //
    public:
    	void append_next_message(std::string const& text)
    	{
    		m_nextMessage += text;
    	}
    
    	void save_next_message()
    	{
    		m_logMessages.push_back(m_nextMessage);
    		m_nextMessage.clear();
    	}
    };
    
    template<typename ValueT>
    Log& operator <<(Log& log, ValueT const& value)
    {
    	std::stringstream ss;
    	ss << value;
    
    	log.append_next_message(ss.str());
    
    	return log;
    }
    
    Log& operator <<(Log& log, Log::Action action)
    {
    	if(action == Log::SAVE)
    	{ log.save_next_message(); }
    
    	return log;
    }
    
    int main()
    {
    	Log log;
    
    	log << "Hello, this is warning number " << 50 << '!' << Log::SAVE;
    	log << "Hello, this is warning number " << 51 << '!' << Log::SAVE;
    
    	std::cin.get();
    
    	return 0;
    }
    

    Kann man sicher noch verbessern, wie gesagt, ist nur kurz innert ein paar Minuten zusammengeschrieben worden.
    Vielleicht könntest du sogar die normalen Streams verwenden und einen eigene Klasse, welche von einem Streambuf erbt, implementieren.
    Dazu dann eigene Manipulatoren. Wir haben zu dem Thema einen schönen Artikel im Magazin:
    http://magazin.c-plusplus.net/artikel/Benutzerdefinierte Manipulatoren

    Grüssli



  • Holla! Das ist natürlich eine sehr viel feinere Lösung. 😃

    Dank Dir für die Mühe!


Anmelden zum Antworten