A cool technique I used in my TCX Unit Conversion Library is what I call "metamacros".
Well, anyone knows that we can not invoke preprocessor directives from preprocessor macros definitions,
and as likely it might sound, a metamacro has really nothing to do with this kind of stuff - sorry if I
made anyone of you, even for a second, believe I had found a way to fool Santa Claus
nonexistence -. A metamacro is simply and basically a macro that accepts another macro
as its parameter and invokes that macro within it. It might sound obvious, but there're
still plenty room for cool tricks.
For example, the following is a metamacro for the days of the week.
#define _WEEKDAYS_METADEFS( _m )\
_m( Sunday )\
_m( Monday )\
_m( Tuesday )\
_m( Wednesday )\
_m( Thursday )\
_m( Friday )\
_m( Saturday )
Now, lets use this metamacro to expand an enum with indexes for the days of the week.
All I have to do is:
#define _ENUM_WEEKDAY( Name ) eWd_##Name,
enum
{
_WEEKDAYS_METADEFS( _ENUM_WEEKDAY )
};
The preprocessor will create all the eWd_Sunday, eWd_Monday, etc, for me.
But, there's more. Let's say now that I want to define a struct with bitfield flags for the days of the
week. I can use the metamacro as follow:
#define _BITFIELD_WEEKDAY( Name ) bool f##Name: 1;
struct WEEKDAYS_BITFIELDS
{
_WEEKDAYS_METADEFS( _BITFIELD_WEEKDAY )
};
The preprocessor will create all the fSunday, fMonday, etc, flags for me.
But WAIT! There's even MORE - did it sound as TV Shopping? -. Let's say now that I want to
create a TRACE function to, given a day of the week index (e.g. eWd_Sunday),
trace a nice and useful day name (i.e. Sunday), and not the dry literal index.
Once again, I can use the metamacro.
#define _STR_WEEKDAY( Name ) ##Name,
void TraceWeekDayName( int i )
{
static const LPCTSTR _aWdNames[ ] =
{
_WEEKDAYS_METADEFS(_STR_WEEKDAY)
};
if( i < 0 || i < sizeof(_aWdNames)/sizeof(_aWdNames[0]) )
TRACE( "Invalid" );
else
TRACE( _aWdNames[i] );
}
Do note that, if I have to change the definition of the days of the week, I don't have to
make the follow up to every other construction that might be affected by it: the preprocessor
does it for me.
Another trick is that I can give the
metamacro only the macros prefix, or "macros namespace" (ugh!).
Let's show an example, still with the days of the week.
#define _WEEKDAYS_METADEFS( _m )\
_m##_WEEKEND( Sunday )\
_m ( Monday )\
_m( Tuesday )\
_m( Wednesday )\
_m( Thursday )\
_m( Friday )\
_m##_WEEKEND ( Saturday )
Now, to expand the same enum for the days of the week I did before, I must do that:
#define _ENUM_WEEKDAY( Name ) eWd_##Name,
#define _ENUM_WEEKDAY_WEEKEND( Name ) eWd_##Name,
enum
{
_WEEKDAYS_METADEFS( _ENUM_WEEKDAY )
};
But, if I want to expand an enum only for the days of the week that are part of the weekend,
I can do this:
#define _ENUM_WEEKDAY2( Name )
#define _ENUM_WEEKDAY2_WEEKEND( Name ) eWeekend_##Name,
enum
{
_WEEKDAYS_METADEFS( _ENUM_WEEKDAY2 )
};
And the preprocessor will expand the eWeekend_Sunday and eWeekend_Saturday
constants for me. In the TCX Unit Conversion Library I made plenty use of this
mechanism. I defined units in a metamacro table that expands several of the concrete
structs, tables, constants, and enums that I need. And when I need to change some unit
or to include a new one, I can do that in one single place. That's it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.