What are some tricks I can use with macros?
Coolest macro is: assert, include guards, __FILE__, __LINE__.
Avoid using other macro in your code.
EDIT:
Use macros only when you don't have legal solution w/o them.
In C, it's common to define macros that do some stuff getting the verbatim argument, and at the same time define functions to be able to get the address of it transparently.
// could evaluate at compile time if __builtin_sin gets
// special treatment by the compiler
#define sin(x) __builtin_sin(x)
// parentheses avoid substitution by the macro
double (sin)(double arg) {
return sin(arg); // uses the macro
}
int main() {
// uses the macro
printf("%f\n", sin(3.14));
// uses the function
double (*x)(double) = &sin;
// uses the function
printf("%f\n", (sin)(3.14));
}
SHOW() for debugging:
#define SHOW(X) cout << # X " = " << (X) << endl
The double-evaluation to expand the arguments trick: (E.g. Use the actual line number and not "__LINE__".)
/* Use CONCATENATE_AGAIN to expand the arguments to CONCATENATE */
#define CONCATENATE( x,y) CONCATENATE_AGAIN(x,y)
#define CONCATENATE_AGAIN(x,y) x ## y
Static compile-time assertions.
E.g.:
#define CONCATENATE_4( a,b,c,d) CONCATENATE_4_AGAIN(a,b,c,d)
#define CONCATENATE_4_AGAIN(a,b,c,d) a ## b ## c ## d
/* Creates a typedef that's legal/illegal depending on EXPRESSION. *
* Note that IDENTIFIER_TEXT is limited to "[a-zA-Z0-9_]*". *
* (This may be replaced by static_assert() in future revisions of C++.) */
#define STATIC_ASSERT( EXPRESSION, IDENTIFIER_TEXT) \
typedef char CONCATENATE_4( static_assert____, IDENTIFIER_TEXT, \
____failed_at_line____, __LINE__ ) \
[ (EXPRESSION) ? 1 : -1 ]
Used via:
typedef int32_t int4;
STATIC_ASSERT( sizeof(int4) == 4, sizeof_int4_equal_4 );
Initializing an instance of class CodeLocation: (Storing File/Line/Function from the point of invocation -- this can *ONLY* be done with a macro or by directly accessing the __FILE__/__LINE__/etc macros at the source point.)
/* Note: Windows may have __FUNCTION__. C99 defines __func__. */
#define CURRENT_CODE_LOCATION() \
CodeLocation( __PRETTY_FUNCTION__, __FILE__, __LINE__ )
Subsequently used by MESSAGE/WARN/FAIL macros as a convenient source-location printing mechanism. For example:
#define WARN_IF_NAN(X) \
do \
{ \
if ( isnan(X) != 0 ) \
WARN( # X " is NaN (Floating Point NOT-A-NUMBER)" ); \
if ( isinf(X) != 0 ) \
WARN( # X " is INF (Floating Point INFINITY)" ); \
} while ( false )
Assert/Unless macros. You can pass any token, including operators like '==', through a macro. So constructs like:
ASSERT( foo, ==, bar )
Or
UNLESS( foo, >=, 0, value=0; return false; );
Are legal. Assert/Unless macros can automatically add all sorts the nice useful info like CodeLocation, stack traces, or throwing exceptions / coredumping / exiting gracefully.
Making errno simplier:
#define ERRNO_FORMAT "errno= %d (\"%s\")"
#define ERRNO_ARGS errno, strerror(errno)
#define ERRNO_STREAM "errno= " << errno << " (\"" << strerror(errno) << "\") "
E.g. printf( "Open failed. " ERRNO_FORMAT, ERRNO_ARGS );
There is also the X Macro idiom which can be useful for DRY and simple code generation :
One defines in a header gen.x a kind of table using a not yet defined macro :
/** 1st arg is type , 2nd is field name , 3rd is initial value , 4th is help */
GENX( int , "y" , 1 , "number of ..." );
GENX( float , "z" , 6.3 , "this value sets ..." );
GENX( std::string , "name" , "myname" , "name of ..." );
Then he can use it in different places defining it for each #include with a usually different definition :
class X
{
public :
void setDefaults()
{
#define GENX( type , member , value , help )\
member = value ;
#include "gen.x"
#undef GENX
}
void help( std::ostream & o )
{
#define GENX( type , member , value , help )\
o << #member << " : " << help << '\n' ;
#include "gen.x"
#undef GENX
}
private :
#define GENX( type , member , value , help )\
type member ;
#include "gen.x"
#undef GENX
}