How does QDebug() << stuff; add a newline automatically?
I'm trying to implement my own qDebug()
style debug-output stream, this is basically what I have so far:
struct debug
{
#if defined(DEBUG)
template<typename T>
std::ostream& operator<<(T const& a) const
{
std::cout << a;
return std::cout;
}
#else
template<typename T>
debug const& operator<<(T const&) const
{
return *this;
}
/*开发者_JAVA技巧 must handle manipulators (endl) separately:
* manipulators are functions that take a stream& as argument and return a
* stream&
*/
debug const& operator<<(std::ostream& (*manip)(std::ostream&)) const
{
// do nothing with the manipulator
return *this;
}
#endif
};
Typical usage:
debug() << "stuff" << "more stuff" << std::endl;
But I'd like not to have to add std::endl;
My question is basically, how can I tell when the return type of operator<<
isn't going to be used by another operator<<
(and so append endl
)?
The only way I can think of to achieve anything like this would be to create a list of things to print with associated with each temporary object created by qDebug()
, then to print everything, along with trailing newline (and I could do clever things like inserting spaces) in ~debug()
, but obviously this is not ideal since I don't have a guarantee that the temporary object is going to be destroyed until the end of the scope (or do I?).
Something like this will do:
struct debug {
debug() {
}
~debug() {
std::cerr << m_SS.str() << std::endl;
}
public:
// accepts just about anything
template<class T>
debug &operator<<(const T &x) {
m_SS << x;
return *this;
}
private:
std::ostringstream m_SS;
};
Which should let you do things like this:
debug() << "hello world";
I've used a pattern like this combined with a lock to provide a stream like logging system which can guarantee that log entries are written atomically.
NOTE: untested code, but should work :-)
Qt uses a method similar to @Evan. See a version of qdebug.h for the implementation details, but they stream everything to an underlying text stream, and then flush the stream and an end-line on destruction of the temporary QDebug object returned by qDebug().
When you write that this is the typical usage:
debug() << "stuff" << "more stuff" << std::endl;
are you definitely planning to construct a debug object each time you use it? If so, you should be able to get the behavior you want by having the debug destructor add the newline:
~debug()
{
*this << std::endl;
... the rest of your destructor ...
}
That does mean you cannot do something like this:
// this won't output "line1" and "line2" on separate lines
debug d;
d << "line1";
d << "line2";
The stream insertion (<<
) and extraction (>>
) are supposed to be non-members.
My question is basically, how can I tell when the return type of operator<< isn't going to be used by another operator<< (and so append endl)?
You cannot. Create a member function to specially append this or append an endl
once those chained calls are done with. Document your class well so that the clients know how to use it. That's your best bet.
精彩评论