I have a C++ class where I place many std::cout statements to print informative text messages about a mass of signals that this class is handling. My intentition is to redirect these text messages to a function named log. In this function, I have flag named mVerbose which defines if the log text should be printed. The content of this function is as follows:
void XXXProxy::log(std::stringstream& ss)
{
if(mVerbose)
{
std::cout << ss;
ss << "";
}
}
Then, the caller code snippet to this function is as follows: std::stringstream logStr;
logStr << "SE"
<< getAddr().toString()
<< ": WAITING on epoll..."
<< std::endl;
log(logStr);
I would like to overload the << operator in my XXXProxy in a way that I can get rid of creating a std::stringstream object and calling the log function. I want to be able to log the text messages as below and let the << operator aggregate everything into:
<< "SE"
<< getAddr().toString()
<< ": WAITING on epoll..."
<< std::endl;
So I wouldlike to have an member << function that looks like:
void XXXProxy::operator << (std::stringstream& ss)
{
if(mVerbose)
{
std::cout << ss;
ss << "";
}
}
QUESTION
I am relatively a novice C++ developer and get lots of compilation errors when attemting to write the above stated like << operator. Could you please make some suggestions or direct me to some links for me to correctly implement this << operator. Thanks.
If you don't want to use std::cout
directly and you want to have your own Log class, you could implement a simple wrapper providing the same interface of std::ostream
: operator<<:
class Log {
private:
std::ostream& _out_stream;
//Constructor: User provides custom output stream, or uses default (std::cout).
public: Log(std::ostream& stream = std::cout): _out_stream(stream) {}
//Implicit conversion to std::ostream
operator std::ostream() {
return _out_stream;
}
//Templated operator>> that uses the std::ostream: Everything that has defined
//an operator<< for the std::ostream (Everithing "printable" with std::cout
//and its colleages) can use this function.
template<typename T>
Log& operator<< (const T& data)
{
_out_stream << data;
return *this;
}
}
So if you implement std::ostream& operator>>(std::ostream& os , const YourClass& object)
for your classes, you can use this Log class.
The advantage of this approach is that you use the same mechanism to make std::cout << your_class_object
work, and to make the class work with the Log.
struct Foo
{
int x = 0; //You marked your question as C++11, so in class initializers
//are allowed.
//std::ostream::operator<< overload for Foo:
friend std::ostream& operator<<(std::ostream& os , const Foo& foo)
{
return os << foo.x;
}
};
int main()
{
Log my_log;
Foo my_foo;
my_foo.x = 31415;
my_log << my_foo << std::endl; //This prints "31415" using std::cout.
}
extern const
of class Log, and make the class implement a singleton. This allows you to access the Log everywhere in your program.Log output (17:57): log message
. To do that, you could use std::endl
as a sentinel and store a flag that says when the next output is the beginning of a line (the beginning of a log message). Checkout the next answer for a complete and working implementation.