Click here to Skip to main content
15,881,172 members
Articles / Programming Languages / C++
Article

Cool Techniques - Metamacros

Rate me:
Please Sign up or sign in to vote.
3.92/5 (6 votes)
1 Dec 19992 min read 61.3K   17   5
A technique to allow macros to call other macros

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralActually it's #define _STR_WEEKDAY( Name ) # Name, Pin
pg--az16-May-07 11:57
pg--az16-May-07 11:57 
GeneralSmall bug Pin
Ingo K. hunsinger11-Apr-00 1:39
sussIngo K. hunsinger11-Apr-00 1:39 
GeneralRe: Small bug Pin
John Bates11-Feb-02 15:23
John Bates11-Feb-02 15:23 
GeneralNeat Pin
Rob Deary20-Mar-00 8:43
sussRob Deary20-Mar-00 8:43 
GeneralRe: Neat Pin
14-Jun-02 15:04
suss14-Jun-02 15:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.