I have written a class for generating debug messages as console output like so.
class mDebug
{
std::ostringstream logStream;
public:
mDebug();
mDebug(const mDebug& other);
~mDebug();
template <typename T>
mDebug& operator<<(const T& value) {logStream << value;}
};
It contains a templated catchall << operator that allows me to write neat debug output of primitive types like so.
mDebug() << 1.2 << "hello";
True debugging power unfolds when I implement global debug operators for the more complex objects I have in my framework, for example for a Vector:
mDebug operator<<(mDebug dbg, const Vector<T> &o)
{
dbg << "sz:" << o.size() << " | ";
dbg << "[";
if (o.size() > 1)
for (uint i = 0; i < o.size()-1; i++)
dbg << o[i] << ",";
if (o.size() > 0)
dbg << o[o.size()-1];
dbg << "]";
return dbg;
}
and then I can
Vector<double> vec;
vec << 1.2 << 1.3 << 1.4;
mDebug() << vec;
Cool. The one thing left that doesn’t let me sleep at night is that the global mDebug Vector operator takes and returns a copy of the debug stream rather than a reference. I would much prefer to have it like so
mDebug& operator<<(mDebug& dbg, const Vector<T> &o)
but then a compilation error happens that says:
error: no match for ‘operator<<’ (operand types are ‘std::ostringstream’ {aka ‘std::__cxx11::basic_ostringstream’} and ‘const Vector’)
30 | logStream << value;
| ~~~~~~~~~~^~~~~~~~
Apparently, the member operator mDebug& operator<<(const T& value)
has taken precedence over the global mDebug operator<<(mDebug& dbg, const Vector<T> &o)
operator and my “catchall” function now also catches the Vector and tries to stream it directly into logStream, which won’t work. I don’t really understand the order of things here. How can I accomplish that all my objects can be streamed into my mDedug class using global operators while passing references AND have the catchall function declared for all primitive types?