Do pre-processor macros for debug log statements have a place in C++?
c++, c-preprocessor, debugging, logging, macros
Solution
First, Scott's statement was made at a time when macros were considerably overused, for historical reasons. While it is generally true, there are a few cases where macros make sense. Of of these is logging, because only a macro can automatically insert `__FILE__` and `__LINE__`. Also, only a macro can resolve to absolutely nothing (although based on my experience, this isn't a big deal).
Macros such as you show aren't very frequent in C++. There are two usual variants for logging:
#define LOG( message ) ... << message ...
which allows messages in the form `" x = " << x`, and can be completely suppressed by redefining the macro, and
#define LOG() logFile( __FILE__, __LINE__ )
where `logFile` returns a wrapper for an `std::ostream`, which defines `operator<<`, and permits such things as:
LOG() << "x = " << x;
Done this way, all of the expressions to the right of `LOG()` will always be evaluated, but done correctly, no formatting will be done unless the log is active.
Problem
Recently I have been reading Effective C++ Second Edition by Scott Meyers to improve on C++ best practices. One of his listed items encourages C++ programmers to avoid pre-processor macros and 'prefer the compiler'. He went as far as saying there are almost no reasons for macro in C++ aside from #include and #ifdef/#ifndef. I agree with his reasoning, as you can accomplish the following macro ``` #define min(a,b) ((a) < (b) ? (a) : (b)) ``` with the following C++ language features ``` template<class T> inline const T & min(const T & a, const T & b) { return a < b ? a : b; } ``` where inline gives the compiler the option to remove the function call and insert inline code and template which can handle multiple data types who have an overloaded or built in > operator. EDIT-- This template declaration will not completely match the stated macro if the data type of a and b differ. See Pete's comment for an example. However, I am curious to know if using macros for debug logging is a valid use in C++. If the method I present below is not good practice, would someone be kind to suggest an alternative way? I have been coding in Objective-C for the last year and one of my favorite 2D engines (cocos2d) utilized a macro to create logging statements. The macro is as follows: ``` /* * if COCOS2D_DEBUG is not defined, or if it is 0 then * all CCLOGXXX macros will be disabled * * if COCOS2D_DEBUG==1 then: * CCLOG() will be enabled * CCLOGERROR() will be enabled * CCLOGINFO() will be disabled * * if COCOS2D_DEBUG==2 or higher then: * CCLOG() will be enabled * CCLOGERROR() will be enabled * CCLOGINFO() will be enabled */ #define __CCLOGWITHFUNCTION(s, ...) \ NSLog(@"%s : %@",__FUNCTION__,[NSString stringWithFormat:(s), ##__VA_ARGS__]) #define __CCLOG(s, ...) \ NSLog(@"%@",[NSString stringWithFormat:(s), ##__VA_ARGS__]) #if !defined(COCOS2D_DEBUG) || COCOS2D_DEBUG == 0 #define CCLOG(...) do {} while (0) #define CCLOGWARN(...) do {} while (0) #define CCLOGINFO(...) do {} while (0) #elif COCOS2D_DEBUG == 1 #define CCLOG(...) __CCLOG(__VA_ARGS__) #define CCLOGWARN(...) __CCLOGWITHFUNCTION(__VA_ARGS__) #define CCLOGINFO(...) do {} while (0) #elif COCOS2D_DEBUG > 1 #define CCLOG(...) __CCLOG(__VA_ARGS__) #define CCLOGWARN(...) __CCLOGWITHFUNCTION(__VA_ARGS__) #define CCLOGINFO(...) __CCLOG(__VA_ARGS__) #endif // COCOS2D_DEBUG ``` This macro provides for incredible utility which I will want to incorporate in my C++ programs. Writing a useful log statement is as simple as ``` CCLOG(@"Error in x due to y"); ``` What is even better, is that if the COCOS2D_DEBUG is set to 0, then these statements never see the light of day. There is no overhead for checking a conditional statement to see if logging statements should be used. This is convenient when making the transition from development to production. How could one recreate this same effect in C++? So does this type of macro belong in a C++ program? Is there a better, more C++ way of doing this?