The X-macro approach can be generalized a bit by making the name of the "X" macro an argument of the master macro. This has the advantages of helping to avoid macro name collisions and of allowing use of a general-purpose macro as the "X" macro.
As always with X macros, the master macro represents a list of items whose significance is specific to that macro. In this variation, such a macro might be defined like so:
/* declare list of items */
#define ITEM_LIST(X) \
X(item1) \
X(item2) \
X(item3) \
/* end of list */
One might then generate code to print the item names like so:
/* define macro to apply */
#define PRINTSTRING(value) printf( #value "\n");
/* apply macro to the list of items */
ITEM_LIST(PRINTSTRING)
That expands to this code:
printf( "item1" "\n"); printf( "item2" "\n"); printf( "item3" "\n");
In contrast to standard X macros, where the "X" name is a built-in characteristic of the master macro, with this style it may be unnecessary or even undesirable to afterward undefine the macro used as the argument (PRINTSTRING
in this example).