I'm adding functions to my (simple) log class to make it usable like a stream. Currently, after some modifications, I got this (in my cpp):
// blah blah blah...
// note: here String is a defined as: typedef std::string String;
void Log::logMessage( const String& message )
{
logText(); // to be sure we flush the current text if any (when "composing" a message)
addText( message );
logText(); // really log the message and make the current text empty
}
// blah blah blah...
Log& operator<<( Log& log, const std::stringstream& message )
{
log.logMessage( message.str() );
return log;
}
Log& operator<<( Log& log, const String& message )
{
log.addText( message );
return log;
}
Now in my "client" app I'm using this code to check the result (m_log is a valid pointer as you have already guessed):
gcore::Log& log = *m_log;
log << getName() << " : application created.";
log << "This is a test for " << getName();
Now the problem I got is that logText() (and logMessage) is never called because this test code will only call the << operator with String. What I need is a way to call logText() when the given steam of string is finished :
log << getName() << " : application created.";
would be equivalent to
log.addText( getName() );
log.addText( " : application create." );
log.logText();
I'm not sure how to do this or even if it's possible. My first guess is that it would be possible to use std::endl at the end of the stream like this :
log << getName() << " : application created." << std::endl;
Or something equivalent, but if it's possible to do it without adding objects to the stream, that would be nice.
Any idea?
You can create a temp object and use his destructor to catch the end of the statement:
following code should give you the basic idea
class Log
{
public:
class Sublog
{
public:
Sublog(const std::string& message)
{
std::cout << message;
}
void addText(const std::string& message)
{
std::cout << message;
}
~Sublog()
{
std::cout << std::endl;
}
Sublog& operator<<(const std::string& message )
{
this->addText(message);
return *this;
}
};
};
Log::Sublog operator<<( Log& log, const std::string& message )
{
return Log::Sublog(message);
}
which would be used like this
int main()
{
Log log;
log << "Foo" << "bar";
log << "baz" << "plop";
}
after each semicolon, the destructor of Sublog is called
Klaim: the (working and effective) implementation of this solution in my case :
in the Log header :
/** To allow streaming semantic on logs (used in << operator) .
*/
class LogStreamer
{
public:
LogStreamer( Log& log, const String& text )
: m_log( log )
{
m_log.addText( text );
}
~LogStreamer()
{
m_log.logText();
}
LogStreamer& operator<<( const String& text )
{
m_log.addText( text );
return *this;
}
private:
Log& m_log;
};
GCORE_API LogStreamer operator<<( Log& log, const String& message );
and in the cpp file:
LogStreamer operator<<( Log& log, const String& message )
{
return LogStreamer( log, message );
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.