Shoehorning anything (with `operator<<()`) into `qDebug()` the quick and dirty templated way
By Ybalrid
- 3 minutes read - 514 wordsSo, the other day I was working on some Ogre + Qt5 code.
I haven’t really worked with Qt that much since Qt4 was the hot new thing, so I was a bit rusty, but I definitively like the new things I’ve seen in version 5. But I’m not here to discuss Qt 5 today. ^^
There’s a few weird things Qt does that I can’t really warp my head around. One is the incompatibility between QString and std::string (There’s probably a nasty problem called “unicode” behind this), but one other one is that QDebug is not an std::ostream derived object.
If you don’t know, in the Qt world, a QApplication is expected write it’s debugging output by writing into a QDebug object, with an output stream operator (“«“) operator. A QDebug object is easilly accessible by calling “qDebug()” this makes this code fairly common :
qDebug() << "Some stuff to log";
This is pretty standard things to do in C++, for instance, the standard library itself makes heavy use of the stream operator for io (hence, the main header is called iostream), and on a personal note : they are, the cleanest way to represent in code how to push stuff in and out of a program, IMO.
Qt choose not to use the standard output stream object as the base for their streams, but to rebuild it from scratch, that’s fine, except when you are trying to interact with something non-Qt.
Every object in Ogre that contains relevant data (the vectors, matrices, colors and other stuff) that can be logged, has an operator«() defined to write to standard streams, but obviously, it will not work with Qt.
If you are lazy like me, and consider that it’s code “for development” and that you intend to remove it/switch it out in production, here’s a snippet you can paste in an header somewhere to redirect theses streams to QDebug’s output :
template <class T> static QDebug operator<<(QDebug dbg, const T& obj)
{
std::stringstream ss;
ss << obj; //Obj has to have an operator<< overload itself to go to the stringtstream.
dbg << ss.str().c_str(); //Get the string, then get the c_string, should be ASCII
return dbg; //Return the debug stream to chain to QDebug objects, by value. Ask Qt's developers, not me
}
This is absolutely not ideal, for example, that stringstream object will be instantiated at each call of this templated function. If your can attempt to, for example, stream out an Ogre::Vector3 inside a QDebug, the compiler will stamp out an operator« that will write the text into a stream, extract the string, and call the operator« of QDebug that take C-style char* strings.
Also, I have no idea why they choose to pass the QDebug object by value in this function, I did not took the time to dig much under the hood, but it seems to be the way Qt deal with this.
It works well enough to me to check the content of some Ogre::Vector3 objects into the debug panel of Qt Creator, or the terminal output on Linux. ^^”