This page describes why we use a macro instead of an inline function for Dout()
.
Good C++ code whenever possible, should not use macros but inline
functions which have the advantage of type checking, overloading and easier debugging with a debugger. It is therefore a very relevant question to ask why a macro was used for Dout()
.
Using a macro has its advantages however:
ostream
. Points 1, 2 and 3 are the most important reasons that lead to the decision to use a macro. Please note that the author of libcwd used the alternative for two years before finally deciding to rewrite the debug facility, being convinced that it was better to do it the way it is done now. While points 4 and 5 are trivial, the first three advantages might need some explanation:
operator<<
functions because they might be used for non-debug code too, so we'd need to use a trick and write to something else than an ostream
(let's say to a class no_dstream
). Each call to template<class T> no_dstream operator<<(T) { };
would actually be done(!), without inlining (point 5 above) ].Let's start with writing some example debug output to cerr
.
This line calls seven functions. If we want to save CPU time when we don't want to write this output, then we need to test whether the debugging output (for this specific channel) is turned on or off before calling the operator<<()
's. After all, such an operator call can use a lot of CPU time for arbitrary objects.
We cannot pass "i = " << i << "; j = " << j << "; s = " << s << std::endl
to an inline function without causing all operator<<
functions to be called. The only way, not using a macro, to achieve that no operator<<
is called is by not calling them in the first place: We can't write to an ostream
. It is necessary to write to a new class (let's call that class dstream
) which checks if the debug channel we are writing to is turned on before calling the ostream operator<<()
:
Nevertheless, even with inlining (often requiring the highest level of optimization), most compilers would turn that into:
checking on
seven times.
With a macro we can easily achieve the best result, even without any optimization:
Dout()
calls, then these variables still need to exist: they are passed to the Dout()
function (or actually, to the no_dstream operator<<()
's). Using a macro allows one to really get rid of such variables by surrounding them with #ifdef CWDEBUG ... #endif
preprocessor directives.Example: