Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preprocessor: Concatenate string to each argument in __VA_ARGS__

I'd like to append a stringified macro argument to each element in a variadic macro. I think I know what I need, but I couldn't come up with a working solution just yet. Given a variadic macro like:

#define FIELD_DECLARATION(NAME, OTHER_FIELD, ...)

FIELD_DECLARATION(First, Thing)
FIELD_DECLARATION(Second, Thing, Thing, Nothing)

I'd like to generate:

field_First = {ThingArg};
field_Second = {ThingArg, ThingArg, NothingArg};

I guess what I need is to recursively keep expanding __VA_ARGS__ until it reaches no elements, and append "Arg" while doing expansion. Finally, pass the result to another variadic macro that produces a comma-separated-list of arguments.

I've tried this, which wouldn't work (and it isn't what I described, either):

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

While this somewhat works, I couldn't come up with a scalable solution. It'd be great if someone could shed a light.

like image 276
user1150609 Avatar asked Jun 11 '17 00:06

user1150609


2 Answers

Here's one scalable approach. First, some general utility macros:

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

Semantically, VARCOUNT counts arguments; GLUE is a typical indirect paster; FIRST extracts the first argument; EVAL expands to its arguments (with intent to evaluate), and TUPLE_TAIL returns the tail of a tuple (i.e., it discards the first argument).

TRANSFORM here is the main idea; TRANSFORM(FOO,(X,Y,Z)) takes a tuple (X,Y,Z) to (FOO(X),FOO(Y),FOO(Z)).

This in place, here's the special purpose code:

#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__)));

Given the above, this should be readable, but just to explain... Z_ARG pastes Arg to an item; MAKE_INITIALIZER transforms a preprocessor tuple to an initialization list; and FIELD_DECLARATION is your macro. Note that EVAL wraps the MAKE_INITIALIZER/transformed tuple so it will actually call that macro.

Note: Moved EVAL to the top and used it in a few more places, such that this will work in MSVC as well.

Demonstration, original code

Demonstration, current code

like image 151
H Walters Avatar answered Oct 10 '22 16:10

H Walters


I have tested the code above on Visual studio C++, there are some problem and compiler show errors. some prentices specially for VA_ARGS was not necessary and also somewhere we have to use VA_ARGS and ... instead of 'Args' the correct code and also extended to 60 input item is :

#ifndef __MACROS__
#define __MACROS__
#define EVAL(...) __VA_ARGS__
#define VARCOUNT(...) \
   EVAL(VARCOUNT_I(__VA_ARGS__,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,))
#define VARCOUNT_I(_,_59,_58,_57,_56,_55,_54,_53,_52,_51,_50,_49,_48,_47,_46,_45,_44,_43,_42,_41,_40,_39,_38,_37,_36,_35,_34,_33,_32,_31,_30,_29,_28,_27,_26,_25,_24,_23,_22,_21,_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_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,Args) X
#define TUPLE_TAIL(...) EVAL(TUPLE_TAIL_I(__VA_ARGS__))
#define TUPLE_TAIL_I(X,...) __VA_ARGS__

#define TRANSFORM(NAME_, ...) GLUE(TRANSFORM_,VARCOUNT(__VA_ARGS__))(NAME_, __VA_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_))

#define TRANSFORM_10(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_9(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_11(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_10(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_12(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_11(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_13(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_12(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_14(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_13(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_15(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_14(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_16(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_15(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_17(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_16(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_18(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_17(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_19(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_18(NAME_,TUPLE_TAIL( ARGS_))

#define TRANSFORM_20(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_19(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_21(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_20(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_22(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_21(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_23(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_22(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_24(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_23(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_25(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_24(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_26(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_25(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_27(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_26(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_28(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_27(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_29(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_28(NAME_,TUPLE_TAIL( ARGS_))

#define TRANSFORM_30(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_29(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_31(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_30(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_32(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_31(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_33(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_32(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_34(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_33(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_35(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_34(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_36(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_35(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_37(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_36(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_38(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_37(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_39(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_38(NAME_,TUPLE_TAIL( ARGS_))

#define TRANSFORM_40(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_39(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_41(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_40(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_42(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_41(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_43(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_42(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_44(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_43(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_45(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_44(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_46(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_45(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_47(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_46(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_48(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_47(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_49(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_48(NAME_,TUPLE_TAIL( ARGS_))

#define TRANSFORM_50(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_49(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_51(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_50(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_52(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_51(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_53(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_52(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_54(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_53(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_55(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_54(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_56(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_55(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_57(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_56(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_58(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_57(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_59(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_58(NAME_,TUPLE_TAIL( ARGS_))
#endif
like image 36
user13960527 Avatar answered Oct 10 '22 17:10

user13960527