我有很多最终生成代码的宏。例如:
#define CODE_GEN_IDENT1_HDR(PARAM1, PARAM2, PARAM3) \
// code generated
#define CODE_GEN_IDENT2_HDR(PARAM1, PARAM2, PARAM3) \
// code generated
#define CODE_GEN_IDENT1_SRC(PARAM1, PARAM2, PARAM3) \
// code generated
#define CODE_GEN_IDENT2_SRC(PARAM1, PARAM2, PARAM3) \
// code generated
这个想法是HDR
生成函数定义,SRC
生成它们的实现。所有宏都具有相同数量的参数(在本示例中为3)。 IDENT
可以是MATH
,TRIG
,ALGS
,CONTAINERS
等任何名称。这就是我要重点关注的。
我正在尝试建立一个宏,该宏可以使用可变参数宏使用不同的IDENT
生成所有这些宏。例如:
// Concatenate macros to a standard form
#define CONCATH_(C) CODE_GEN_##C##_HDR
#define CONCATC_(C) CODE_GEN_##C##_SRC
// CONCATH concatenates to HDR
// CONCATC concatenates to SRC
#define CONCATH(C) CONCATH_(C)
#define CONCATC(C) CONCATC_(C)
#define MASTER_MACRO(PARAM1, PARAM2, PARAM3, ...) \
// Code that generates all other macros
// using CONCATH and CONCATC
// how could this be done?
我写的时候:
MASTER_MACRO(int, "Hello", char *, MATH, TRIG, CONT)
我想要类似的东西:
CODE_GEN_MATH_HDR(int, "Hello", char *)
CODE_GEN_TRIG_HDR(int, "Hello", char *)
CODE_GEN_CONT_HDR(int, "Hello", char *)
CODE_GEN_MATH_SRC(int, "Hello", char *)
CODE_GEN_TRIG_SRC(int, "Hello", char *)
CODE_GEN_CONT_SRC(int, "Hello", char *)
要以某种方式访问给定的参数并连接每个参数,使它们既是标头又是源。
我目前拥有的是一个固定长度的宏,例如:
MASTER_MACRO(PARAM1, PARAM2, PARAM3, MATH, TRIG, CONT, DUPL, SORT) \
CONCATH(MATH)(PARAM1, PARAM2, PARAM3)
CONCATH(TRIG)(PARAM1, PARAM2, PARAM3)
...
CONCATC(MATH)(PARAM1, PARAM2, PARAM3)
...
并且当用户不想生成CONT
,DUPL
或任何其他宏时,他必须传递一个像_
这样的预定义参数,这意味着他不想生成并具有一个空宏:
#define CODE_GEN___SRC(PARAM1, PARAM2, PARAM3) // Empty
但这还不够好。在不同的项目中,这些不同的IDENT
具有不同的名称,因此不得不制作新的主宏有点烦人。
但是最大的问题是:
答案 0 :(得分:1)
是的,您可以这样做。对于手动实施,您可能想从一个基本的参数计数器开始,如下所示:
#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__))