I'm using X Macros in my project, so as to not repeat myself in places where a list of names all need to have identical operations performed on them (such as creation, initialization, population, and destruction).
As the data I'm trying to specify once involves a few of the same macro-able translations (ignoring arguments, prefixing vs. suffixing), I decided to enhance my original single-fit X Macros by rewriting them as generalized Meta X-Macros, from which multiple derivative end-use-case-fitting X Macros could be defined, using transformation macros that interpret the meta-macro's arguments:
// Meta-macros //
#define MAIN_WINDOW_TEXT_LAYERS_METAMACRO(macro, tr) \
macro(tr(hour_layer)) \
macro(tr(min_layer)) \
macro(tr(date_layer))
#define MAIN_WINDOW_LAYERS_METAMACRO(macro, tr) \
macro(tr(colon_layer)) \
macro(tr(phone_batt_layer)) \
macro(tr(watch_batt_layer))
#define GBITMAPS_WITH_RESOURCE_IDS_METAMACRO(macro, tr) \
macro(tr(watch_icon, ICON_WATCH_6X11)) \
macro(tr(watch_charging_icon, ICON_WATCH_CHARGING_6X11)) \
macro(tr(phone_icon, ICON_PHONE_6X11)) \
macro(tr(phone_charging_icon, ICON_PHONE_CHARGING_6X11))
#define GFONTS_WITH_RESOURCE_IDS_METAMACRO(macro, tr) \
macro(tr(time_font, FONT_ARVO_BOLD_48)) \
macro(tr(date_font, FONT_ARVO_BOLD_20))
// Transformation macros //
#define IDENTITY_MACRO(x) x
#define STATIC_PREFIX_MACRO(x) s_ ## x
#define STATIC_PREFIX_DISCARD_MACRO(x, _) s_ ## x
#define STATIC_PREFIX_RESOURCE_ID_PREFIX_MACRO(x, id) \
s_ ## x, RESOURCE_ID_ ## s
// Derived X-Macros //
#define FOR_MAIN_WINDOW_STATIC_TEXT_LAYER_POINTERS(macro) \
MAIN_WINDOW_TEXT_LAYERS_METAMACRO(macro, STATIC_PREFIX_MACRO)
#define FOR_MAIN_WINDOW_STATIC_LAYER_POINTERS(macro) \
MAIN_WINDOW_LAYERS_METAMACRO(macro, STATIC_PREFIX_MACRO)
#define FOR_MAIN_WINDOW_LAYER_NAMES(macro) \
MAIN_WINDOW_LAYERS_METAMACRO(macro, IDENTITY_MACRO)
#define FOR_STATIC_GFONTS(macro) \
GFONTS_WITH_RESOURCE_IDS_METAMACRO(macro, STATIC_PREFIX_DISCARD_MACRO)
#define FOR_STATIC_GFONTS_WITH_RESOURCE_IDS(macro) \
GFONTS_WITH_RESOURCE_IDS_METAMACRO(macro, STATIC_PREFIX_RESOURCE_ID_PREFIX_MACRO)
#define FOR_STATIC_GBITMAP_POINTERS_WITH_RESOURCE_IDS(macro) \
GBITMAPS_WITH_RESOURCE_IDS_METAMACRO(macro, STATIC_PREFIX_RESOURCE_ID_PREFIX_MACRO)
#define FOR_STATIC_GBITMAP_POINTERS(macro) \
GBITMAPS_WITH_RESOURCE_IDS_METAMACRO(macro, STATIC_PREFIX_DISCARD_MACRO)
This works, in most use cases: however, there are a few edge cases where I run into trouble. Firstly, trying to concatenate arguments results in the transformation macro's name getting concatenated, rather than the transformed name:
#define X(name) layer_set_update_proc(s_ ## name, name ## _update_proc);
FOR_MAIN_WINDOW_LAYER_NAMES(X)
#undef X
error: implicit declaration of function 's_IDENTITY_MACRO'
Secondly, macros that transform two arguments aren't getting expanded - they're being passed to X
as a single token (the call to the transformation macro):
#define X(name, id) name = fonts_load_custom_font(resource_get_handle(id));
FOR_STATIC_GFONTS_WITH_RESOURCE_IDS(X)
#undef X
error: macro "X" requires 2 arguments, but only 1 given error: unknown type name 'X'
#define X(name, id) name = gbitmap_create_with_resource(id);
FOR_STATIC_GBITMAP_POINTERS_WITH_RESOURCE_IDS(X)
#undef X
error: macro "X" requires 2 arguments, but only 1 given error: expected '=', ',', ';', 'asm' or '__attribute__' before 'X'
How can I make these work the way I want them to?