Да, вы можете сделать это.Для реализации, созданной вручную, вы, вероятно, захотите начать с базового счетчика аргументов, например:
#define COUNT(...) \
COUNT_I(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1,)
#define COUNT_I(_ ,_9,_8,_7,_6,_5,_4,_3,_2, X,...) X
Счетчик аргументов работает как «сдвиговый регистр», вставляя список аргументов перед счетчиком.Если вызывается с одним аргументом, все выравнивает X с 1. Каждый дополнительный аргумент сдвигает этот список по ... 2 аргумента сдвигает 2 в X, 3 сдвигает 3 в и так далее.Это просто базовая форма, поддерживающая до 9 аргументов, чтобы передать идею.
... теперь вы можете генерировать различные утилиты макросов, как эта:
#define GLUE(A,B) GLUE_I(A,B)
#define GLUE_I(A,B) A##B
#define TRANSFORM_CD(MACRO, ...) GLUE(TRANSFORM_CD_,COUNT(__VA_ARGS__))(MACRO,__VA_ARGS__)
#define TRANSFORM_CD_1(MACRO,X) MACRO(X)
#define TRANSFORM_CD_2(MACRO,X,...) MACRO(X),TRANSFORM_CD_1(MACRO,__VA_ARGS__)
#define TRANSFORM_CD_3(MACRO,X,...) MACRO(X),TRANSFORM_CD_2(MACRO,__VA_ARGS__)
#define TRANSFORM_CD_4(MACRO,X,...) MACRO(X),TRANSFORM_CD_3(MACRO,__VA_ARGS__)
#define TRANSFORM_CD_5(MACRO,X,...) MACRO(X),TRANSFORM_CD_4(MACRO,__VA_ARGS__)
#define TRANSFORM_CD_6(MACRO,X,...) MACRO(X),TRANSFORM_CD_5(MACRO,__VA_ARGS__)
#define TRANSFORM_CD_7(MACRO,X,...) MACRO(X),TRANSFORM_CD_6(MACRO,__VA_ARGS__)
#define TRANSFORM_CD_8(MACRO,X,...) MACRO(X),TRANSFORM_CD_7(MACRO,__VA_ARGS__)
#define TRANSFORM_CD_9(MACRO,X,...) MACRO(X),TRANSFORM_CD_8(MACRO,__VA_ARGS__)
Концептуально TRANSFORM_CD
предназначен для "преобразования" списка с разделителями-запятыми (аргументы 2 и выше) в другой список с разделителями-запятыми, применяя к нему макрос.В этом случае мы начнем с разделенного запятыми списка базовых имен (что вы называете IDENT
здесь) и применим к нему один из ваших макросов преобразования;например, TRANSFORM(CONCATH, TRIG, CONT, DUPL)
расширяется до CODE_GEN_TRIG_HDR, CODE_GEN_CONT_HDR, CODE_GEN_DUPL_HDR
.
Далее нам нужно что-то для генерации вызовов с несколькими макросами и одним и тем же набором параметров;как эта утилита:
#define INVOKE_ALL(TUPLE_, ...) GLUE(INVOKE_ALL_,COUNT(__VA_ARGS__))(TUPLE_,__VA_ARGS__)
#define INVOKE_ALL_1(TUPLE_, X) X TUPLE_
#define INVOKE_ALL_2(TUPLE_, X,...) X TUPLE_ INVOKE_ALL_1(TUPLE_,__VA_ARGS__)
#define INVOKE_ALL_3(TUPLE_, X,...) X TUPLE_ INVOKE_ALL_2(TUPLE_,__VA_ARGS__)
#define INVOKE_ALL_4(TUPLE_, X,...) X TUPLE_ INVOKE_ALL_3(TUPLE_,__VA_ARGS__)
#define INVOKE_ALL_5(TUPLE_, X,...) X TUPLE_ INVOKE_ALL_4(TUPLE_,__VA_ARGS__)
#define INVOKE_ALL_6(TUPLE_, X,...) X TUPLE_ INVOKE_ALL_5(TUPLE_,__VA_ARGS__)
#define INVOKE_ALL_7(TUPLE_, X,...) X TUPLE_ INVOKE_ALL_6(TUPLE_,__VA_ARGS__)
#define INVOKE_ALL_8(TUPLE_, X,...) X TUPLE_ INVOKE_ALL_7(TUPLE_,__VA_ARGS__)
#define INVOKE_ALL_9(TUPLE_, X,...) X TUPLE_ INVOKE_ALL_8(TUPLE_,__VA_ARGS__)
Здесь TUPLE_
предназначен для того, чтобы быть списком аргументов в скобках (это делает утилиту немного более общей, чем требование, чтобы она поддерживала ровно три параметра);и каждый другой параметр представляет макрос, который будет вызываться с этими аргументами.
Комбинируя их, это:
INVOKE_ALL((p1 a1, p2 a2, p3 a3),TRANSFORM_CD(CONCATH,MATH,TRIG,CONT,DUPL))
... должно быть расширено (переформатировано для ясности):
CODE_GEN_TRIG_HDR(p1 a1, p2 a2, p3 a3)
CODE_GEN_CONT_HDR(p1 a1, p2 a2, p3 a3)
CODE_GEN_DUPL_HDR(p1 a1, p2 a2, p3 a3)
... и если вы действительно хотите, вы можете сохранить форму и функцию MASTER_MACRO
, просто сделав ее вариативной, например:
#define MASTER_MACRO(PARAM1, PARAM2, PARAM3, ...) \
INVOKE_ALL((PARAM1, PARAM2, PARAM3),TRANSFORM_CD(CONCATH,__VA_ARGS__)) \
INVOKE_ALL((PARAM1, PARAM2, PARAM3),TRANSFORM_CD(CONCATC,__VA_ARGS__))
демонстрация в стеке-crooked