2016-12-30 5 views
1

Я использую X Macros в своем проекте, чтобы not repeat myself в местах, где список имен должен иметь одинаковые операции над ними (например, создание, инициализация, совокупность и уничтожение).Как я могу использовать макрос в макросе для преобразования аргументов макроса?

Как данные, которые я пытаюсь указать один раз включает в себя некоторые из тех же макро-возможности переводов (игнорируя аргументы, предваряя против суффиксов), я решил усилить my original single-fit X Macros переписав их обобщенными Мета 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 
error: implicit declaration of function '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 
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' 

Как я могу сделать это работать так, как я хочу, чтобы они?

ответ

1

Как упоминалось в otherStackOverflowquestions о C препроцессора, первой задачи (идентификатора макроса будучи сцепленного, а не его содержание) можно избежать путем введения другой слой косвенного evaulation к макро:

#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_ 

Конечно, разгрузка этих видов обходных путей до точки использования, а не их фиксация в точке, где они определены, не является надежной техникой, поэтому следует определить этот слой косвенности как часть мета -macro:

#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_, которые могут быть #define d и сразу #undef INED прямо вокруг точки вызова, то окольный макрос используется здесь должен оставаться определенным , пока эти макросы могут быть использованы (очевидно), поэтому следует выбрать имя, которое не может вызвать конфликты с другими частями кодовой базы (то есть не только X_). Даже что-то вроде APPLY_MACRO, as I used here, не особенно целесообразно: более крупные проекты (особенно любой код, который может быть перераспределен для использования в других решениях) должны учитывать префикс имени, используемого с каким-то префиксом пространства имен, чтобы ограничить его область влияния на другие контексты (как описано в this SoftwareEngineering.se answer).

Ultimately, хотя, для моих целей, я в конечном итоге решить эту проблему путем переписывания моих преобразований макросов взять макрос применить и назвать его с трансформированных аргументами, уплощением интерпретации и позволяет мне реорганизовать из макрос APPLY_MACRO, описанный выше.

Смежные вопросы