use*_*609 3 c macros c-preprocessor
我想为可变参数宏中的每个元素追加一个字符串化的宏参数.我想我知道我需要什么,但我还没有想出一个有效的解决方案.给出一个可变宏,如:
#define FIELD_DECLARATION(NAME, OTHER_FIELD, ...)
FIELD_DECLARATION(First, Thing)
FIELD_DECLARATION(Second, Thing, Thing, Nothing)
Run Code Online (Sandbox Code Playgroud)
我想生成:
field_First = {ThingArg};
field_Second = {ThingArg, ThingArg, NothingArg};
Run Code Online (Sandbox Code Playgroud)
我想我需要的是递归地继续扩展__VA_ARGS__直到它没有元素,并"Arg"在进行扩展时追加.最后,将结果传递给另一个可变参数宏,该宏生成以逗号分隔的参数列表.
我试过这个,这是行不通的(也不是我所描述的):
#define UNPACK_VA_1(A1) A1 ## Arg
#define UNPACK_VA_2(A1, A2) UNPACK_VA_1(A1), UNPACK_VA_1(A2)
#define UNPACK_VA_3(A1, A2, A3) UNPACK_VA_2(A1, A2), UNPACK_VA_1(A3)
#define UNPACK_VA_4(A1, A2, A3, A4) UNPACK_VA_2(A1, A2), UNPACK_VA_2(A3, A4)
#define UNPACK_VA(...) UNPACK_VA_4(__VA_ARGS__)
#define FOO(x, y, ...) UNPACK_VA(__VA_ARGS__)
FOO(One, Two, Three, Four, Five, Six)
Run Code Online (Sandbox Code Playgroud)
虽然这有点奏效,但我无法提出可扩展的解决方案.如果有人可以放光,那就太棒了.
这是一种可扩展的方法.首先,一些通用实用程序宏:
#define EVAL(...) __VA_ARGS__
#define VARCOUNT(...) \
EVAL(VARCOUNT_I(__VA_ARGS__,9,8,7,6,5,4,3,2,1,))
#define VARCOUNT_I(_,_9,_8,_7,_6,_5,_4,_3,_2,X_,...) X_
#define GLUE(X,Y) GLUE_I(X,Y)
#define GLUE_I(X,Y) X##Y
#define FIRST(...) EVAL(FIRST_I(__VA_ARGS__,))
#define FIRST_I(X,...) X
#define TUPLE_TAIL(...) EVAL(TUPLE_TAIL_I(__VA_ARGS__))
#define TUPLE_TAIL_I(X,...) (__VA_ARGS__)
#define TRANSFORM(NAME_, ARGS_) (GLUE(TRANSFORM_,VARCOUNT ARGS_)(NAME_, ARGS_))
#define TRANSFORM_1(NAME_, ARGS_) NAME_ ARGS_
#define TRANSFORM_2(NAME_, ARGS_) NAME_(FIRST ARGS_),TRANSFORM_1(NAME_,TUPLE_TAIL ARGS_)
#define TRANSFORM_3(NAME_, ARGS_) NAME_(FIRST ARGS_),TRANSFORM_2(NAME_,TUPLE_TAIL ARGS_)
#define TRANSFORM_4(NAME_, ARGS_) NAME_(FIRST ARGS_),TRANSFORM_3(NAME_,TUPLE_TAIL ARGS_)
#define TRANSFORM_5(NAME_, ARGS_) NAME_(FIRST ARGS_),TRANSFORM_4(NAME_,TUPLE_TAIL ARGS_)
#define TRANSFORM_6(NAME_, ARGS_) NAME_(FIRST ARGS_),TRANSFORM_5(NAME_,TUPLE_TAIL ARGS_)
#define TRANSFORM_7(NAME_, ARGS_) NAME_(FIRST ARGS_),TRANSFORM_6(NAME_,TUPLE_TAIL ARGS_)
#define TRANSFORM_8(NAME_, ARGS_) NAME_(FIRST ARGS_),TRANSFORM_7(NAME_,TUPLE_TAIL ARGS_)
#define TRANSFORM_9(NAME_, ARGS_) NAME_(FIRST ARGS_),TRANSFORM_8(NAME_,TUPLE_TAIL ARGS_)
Run Code Online (Sandbox Code Playgroud)
在语义上,VARCOUNT计算参数; GLUE是一种典型的间接贴纸; FIRST提取第一个参数; EVAL扩展到它的参数(意图评估),并TUPLE_TAIL返回元组的尾部(即,它丢弃第一个参数).
TRANSFORM这是主要的想法; TRANSFORM(FOO,(X,Y,Z))需要一个元组(X,Y,Z)到(FOO(X),FOO(Y),FOO(Z)).
这就到位了,这是特殊用途代码:
#define Z_ARG(X) GLUE(X,Arg)
#define MAKE_INITIALIZER(...) { __VA_ARGS__ }
#define FIELD_DECLARATION(FNAME_, ...) \
GLUE(field_, FNAME_) = EVAL(MAKE_INITIALIZER TRANSFORM(Z_ARG, (__VA_ARGS__)));
Run Code Online (Sandbox Code Playgroud)
鉴于上述情况,这应该是可读的,但只是为了解释... Z_ARG粘贴Arg到项目; MAKE_INITIALIZER将预处理器元组转换为初始化列表; 而且FIELD_DECLARATION是你的宏.请注意,EVAL包装MAKE_INITIALIZER/转换后的元组,以便实际调用该宏.
注意:移动EVAL到顶部并在更多位置使用它,这样也可以在MSVC中使用.