A bit of zest on X-Macro


Back in 1994 I came across a technique of generating C++ code through Macros.

Macros in modern C++ are generally avoided like the plague by developers these days … but they still have their uses even in modern code … especially when memory is tight.

I’ve used this pattern many times over the years but I have never had a name for it.

A colleague asked me to review some of their code the other day and I was surprised to see something very similar to the pattern I knew … except I was stumped for a moment or two as to how it worked.

My colleague was using the X Macro technique.

My difficulty with the code was … where is X defined … I was scouring the list of #includes and the files to find it … but I couldn’t.

Then it dawned on me that it would just use X when instantiated and X would be replaced if it was also #defined somewhere … then I searched for definitions of macro X … low and behold I found loads of #defines and #undef of X all over the place along with lots of comments explaining what is happening … because X is not a very discriptive name for a macro.

It works obviously … but it was not the refined technique I knew … and I was kind of left with the feeling that it was half defined.

The zest that I add for the world on the X Macro pattern is this … and using the same terms as the X Macro wiki page above … instead of …

#define LIST_OF_VARIABLES \
    X(value1) \
    X(value2) \
    X(value3)

… I do this …

#define LIST_OF_VARIABLES(X) \
    X(value1) \
    X(value2) \
    X(value3)

… but when I use it I am a lot more descriptive … and I also group many related things together … to illustrate I will use a familiar if artificial example … in the definition of where I want to gather the related information I define a generator that takes a selector …

#define EVENT_CODE_GENERATOR(SELECTOR) \
    SELECTOR(LeftMouseDown, LBUTTONDOWN, 0x0201) \
    SELECTOR(LeftMouseUp, LBUTTONUP, 0x0202) \
    SELECTOR(LeftMouseDoubleClick, LBUTTONDBLCLK, 0x0203)

… and then when it is used … say to generate an enumeration definition …


#define EVENT_ENUMS(function, message, number) WM_##message=number, 

typedef enum { EVENT_CODE_GENERATOR( EVENT_ENUMS ) MaxEventNumber } Events;

This actually generates this code (ignoring whitespace)…


typedef enum { WM_LBUTTONDOWN=0x0201, WM_LBUTTONUP=0x0202,
               WM_LBUTTONDBLCLK=0x0203, MaxEventNumber } Events;

… the beauty of this is that the EVENT_CODE_GENERATOR can be reused for many things like generating human readable strings or function definitions for these events … and the SELECTOR parameter can be given a nice name that flows with the code in context around it.

A fuller example can be found at Compiler Explorer or if that is tampered with then on my github repo Zesty X Macro Repo