[Solved] Problem defining a std::endl manipulator for a custom class
-
Hi gurus,
I've implemented a logging class that is responsible for producing output to std output, adding colors and name of the caller class, and has some output levels defined. I'm on Fedora 14 32bits, using GCC 4.5.1 with glibc 2.13.
Here's the header file :
#include <string> #include <iomanip> #include <sstream> #include <map> #include "CColor.h" // Color codes enum DebugLevelType { ALL, /**< Shows everything */ MEM, /**< Ultra detailed debugging */ DEBUG, /**< Debugging message */ LFUNC, /**< Function output in loops */ LINFO, /**< Info message in loops */ FUNC, /**< Function message */ INFO, /**< General info */ BLANK, /**< Equivalent of std::cout */ PROGRESS, /**< - */ RELEASE, /**< Information that would go in a logfile */ WARN, /**<Warning, beeps */ ERR, /**< Critical failure message, beeps also */ OFF /**< No output */ }; class MessageStream { public: MessageStream( const DebugLevelType& level, const string& source = "" ); MessageStream( const MessageStream& flot ); virtual ~MessageStream(); std::ostringstream& stream(); const DebugLevelType& currentLevel() const; const DebugLevelType& instanceLevel() const; static void setUseColour( const bool& useColour ); static const bool& useColour(); const bool& isActive() const; MessageStream& doOutput(); MessageStream& flush(); MessageStream& operator<<( const DebugLevelType& level ); std::string Source; std::ostringstream Stream; DebugLevelType CurrentLevel; DebugLevelType InstanceLevel; static bool UseColour; bool IsActive; private: static const std::map< DebugLevelType, CColor > Decorations; static const std::map< DebugLevelType, std::string > Textes; void activate(); void deactivate(); }; MessageStream& endmsg( MessageStream& flot ); template< typename T > MessageStream& operator<<( MessageStream& flot, const T& arg ) { flot.stream() << arg; return flot; }
As the class doesn't inherit from any output stream class, I had to define the operator<< template, which works fine. The endmsg function is supposed to act like std::endl. The code is :
MessageStream& endmsg( MessageStream& flot ) { return flot.doOutput(); } MessageStream& MessageStream::doOutput() { try { if ( isActive() ) { if ( useColour() ) cout << Decorations.find( CurrentLevel ) -> second . colorCode(); if ( NiveauCourant != BLANK ) cout << setw( 20 ) << left << Source << setw( 10 ) << left << Textes.find( CurrentLevel ) -> second; cout << Stream.str(); if ( useColour() ) cout << "\033[0m"; // resets the color to default cout << endl; } Stream.str( "" ); } catch( exception& e ) { cerr << "Exeption : " << e.what() << endl; } return *this; }
Now, when I use a stupid example to perform some tests, I do this :
MessageStream Debug( DEBUG, "StupidTest" ); Debug << "Some debug statement" << endmsg;
I expect the output to be like "StupidTest DEBUG Some debug statement", but the output I get is "StupidTest DEBUG Some debug statement1", without any newline. I understand that my template tries to use "endmsg" as a regular variable, and puts a '1'. How can I get this to work...?
I tried to make MessageStream inherit from std::ostringstream, but
- it doesn't work either
- the std::left and std::setw( ) don't work properly.
Is there a way to prevent the MessageStream instance to use the template when endmsg is added to the stream output? If not, how should I write the endmsg function?
Thanks in advance,
johan -
I guess I can, I didn't think about it. I basically looked at "this code":http://lhcb-release-area.web.cern.ch/LHCb-release-area/DOC/analysis/releases/latest/doxygen/dd/d15/_msg_stream_8h_source.html and tried to remove the stuff I don't need.
I'll test your suggestion, thanks!
-
Hi Johan,
I have noted in your code that you reference MessageStream. However, the doOutput method is writing the endl simply to cout respectively to cerr in case of an error.
That looks strange to me.Can you elaborate a little on that part?
I would have expected that you write the endl to MessageStream.
-
[quote author="koahnig" date="1304930013"]Hi Johan,
I have noted in your code that you reference MessageStream. However, the doOutput method is writing the endl simply to cout respectively to cerr in case of an error.
That looks strange to me.Can you elaborate a little on that part?
I would have expected that you write the endl to MessageStream.[/quote]
Hi,
I'm not sure to understand your question. The MessageStream class itself is no output stream, it is designed in such a (bad?) way that you need to call doOutput in order to display it in your terminal. As long as you don't call doOutput you are just filling up the Stream object of your MessageStream instance, but no output is produced. As long as there is no error the message is then printed to std::cout (against which I guess you have no objection), but I usually do error report on std::cerr that's all.
As mentionned in a previous post, this class was inspired by a class used in the LHCb experiment, class which was coded by people much smarter than me, and I didn't question their choice of implementation (which may be a wrong idea).
@ Andre : thanks again, you made my day!!