我在我的项目中使用X宏,以便在名称列表需要对它们执行相同操作(例如创建、初始化、填充和销毁)的地方使用不重复我自己。
由于我试图指定的数据涉及几个相同的可宏翻译(忽略参数、前缀和后缀),所以我决定通过将它们重写为广义元X宏来增强我原来的单曲X宏,从这些宏中可以定义多个导数最终用例拟合的X宏,使用解释元宏参数的转换宏:
// 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)在大多数用例中,这都是可行的:然而,在一些边缘案例中,我遇到了麻烦。首先,试图连接参数会导致转换宏的名称连接起来,而不是转换后的名称:
#define X(name) layer_set_update_proc(s_ ## name, name ## _update_proc);
FOR_MAIN_WINDOW_LAYER_NAMES(X)
#undef X错误:函数“s_IDENTITY_MACRO”的隐式声明
其次,转换两个参数的宏不会被扩展--它们作为单个令牌(对转换宏的调用)传递给X:
#define X(name, id) name = fonts_load_custom_font(resource_get_handle(id));
FOR_STATIC_GFONTS_WITH_RESOURCE_IDS(X)
#undef X错误:宏"X“需要两个参数,但只有一个给定的错误:未知类型名称'X‘
#define X(name, id) name = gbitmap_create_with_resource(id);
FOR_STATIC_GBITMAP_POINTERS_WITH_RESOURCE_IDS(X)
#undef X错误:宏"X“需要两个参数,但只有一个给定的错误:预期的'=','__attribute__‘之前的'X’
我怎样才能让这些东西按照我想要的方式工作呢?
发布于 2016-12-30 11:22:08
正如其他 堆栈 溢出 问题中提到的C预处理器,通过向宏引入另一层间接调用,可以避免第一个问题(宏的标识符被连接而不是其内容):
#define X_(name) layer_set_update_proc(s_ ## name, name ## _update_proc);
#define X(name) X_(name)
FOR_MAIN_WINDOW_LAYER_NAMES(X)
#undef X
#undef X_第二个问题更隐秘,但它有一个类似的解决方案:另一层间接。这里的关键技巧是,与复制最终宏的签名不同,第一层必须使用单个参数传递到下一层,然后将其扩展到多个参数:
#define X_(name, id) name = fonts_load_custom_font(resource_get_handle(id));
#define X(args) X_(args)
FOR_STATIC_GFONTS_WITH_RESOURCE_IDS(X)
#undef X
#undef X_当然,将这些类型的解决方案卸载到使用点,而不是在定义它们的点上修复它们,并不是一个健壮的工程,因此应该将这一层间接方向定义为元宏本身的一部分。
#define APPLY_MACRO(x, t) x(t)
#define MAIN_WINDOW_TEXT_LAYERS_METAMACRO(X, tr) \
APPLY_MACRO(X,tr(hour_layer)) \
APPLY_MACRO(X,tr(min_layer)) \
APPLY_MACRO(X,tr(date_layer))
/* etc... */但是,请注意,无论您选择用于APPLY_MACRO的任何令牌,与X或X_这样的标识符不同,该标识符可以是#defined,并且在调用点附近立即使用#undef,这里使用的间接宏必须保持定义,只要可以使用这些宏本身(显然),因此应该选择一个不会引起与代码基的其他部分冲突的名称(即,不仅仅是X_)。甚至像APPLY_MACRO,就像我以前在这里一样这样的东西也不是特别可取的:更大的项目(尤其是任何可能被重新分发以用于其他解决方案的代码)应该考虑在名称空间前缀中加上前缀,以限制其范围以避免干扰其他上下文(如这个SoftwareEngineering.se的答案中所描述的)。
然而,就我的目的而言,最终最终解决了这个问题,我重写了转换宏,将宏用于应用并使用转换后的参数调用它,简化了解释,并允许我完全重构上面描述的APPLY_MACRO宏。
https://stackoverflow.com/questions/41395464
复制相似问题