0
votes

There were several questions here regarding variadic macros in C. These include:

My question is related to the iteration technique. I am interested in a macro with this generalized semantics.

ITERATE(Before, Action, Between, After, Empty, ...)

that will place Before prior to all expansions, apply Action to each argument, place Between between every two consecutive applications, and will finally place the expansion of After. Moreover, if the number of argument With such a macro, it should be possible to write

// Loop elements
#define A(x) (x) 
#define Befor (
#define After )
#define Between ||
#define Empty 1

// Define an OR macro
#define OR(...) ITERATE(Before, A, Between, Empty, __VA_ARGS__)

// Use it
OR()      // Expands to 1
OR(a)     // Expands to ((a))
OR(a,b)   // Expands to ((a)||(b))
OR(a,b,c) // Expands to to ((a)||(b)||(c))

The purpose of course is not to write an OR function. A generalized functionality could be for more intricate applications. E.g., a macro for defining classes and functions, something to print the trace, etc.

1
#define Befor ( #define After ) just #define A(x) ((x)) .... I see no point in "before" and "after", just place them inside your Action. Anyway, what have you tried? I would like to write then write it. It is possible. If you want others to do the job for you, pay them.KamilCuk
I could do the OR without it, but there are other applications, e.g.,print trace, etc. I thought your comment was a bit abusive, but I changed the wording to please you.Yossi Gil

1 Answers

1
votes

I never liked the recursive REPEAT() macro idiom - it generates horrible hour long read error messages that are.. recursive, so you don't know where the error is and it's also hard to grasp how the OBSTRUCT(REPEAT_INDIRECT) () stuff works. Overall, overloading the macro on number of arguments and using an external tool (shell script or m4 preprocessor) to generate C source code is waay easier, easier to read, maintain and fix and also you can expand the macros on the tools side removing the burden of recursive expansion on C side. With that in mind, your ITERATE can be generated with existing preprocessor libraries, P99_FOR or BOOST_FOREACH comes to mind.

Also, typing shift all the time is strange - I prefer snake case. Here's a reduced example without Before and After macros with overloading the macro on number of arguments:

#define _in_ITERATE_0(f,b,e)           e()
#define _in_ITERATE_1(f,b,e,_1)        f(_1)
#define _in_ITERATE_2(f,b,e,_1,...)    f(_1)b()_in_ITERATE_1(f,b,e,__VA_ARGS__)
#define _in_ITERATE_3(f,b,e,_1,...)    f(_1)b()_in_ITERATE_2(f,b,e,__VA_ARGS__)
// or you could expand it instead of reusing previous one with same result:
#define _in_ITERATE_4(f,b,e,_1,_2,_3,_4)    f(_1)b()f(_2)b()f(_3)b()f(_4)
// etc.... generate
#define _in_ITERATE_N(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...)  _in_ITERATE_##N
#define ITERATE(func, between, empty, ...)  \
    _in_ITERATE_N(0,##__VA_ARGS__,9,8,7,6,5,4,3,2,1,0)(func, between, empty, ##__VA_ARGS__)


#define _in_OR_OP(x)     (x) 
#define _in_OR_EMPTY()     1
#define _in_OR_BETWEEN()  ||
#define OR(...)   (ITERATE(_in_OR_OP, _in_OR_BETWEEN, _in_OR_EMPTY, ##__VA_ARGS__))

// Use it
OR()      // Expands to (1)
OR(a)     // Expands to ((a))
OR(a,b)   // Expands to ((a)||(b))
OR(a,b,c) // Expands to to ((a)||(b)||(c))

outputs:

(1)
((a))
((a)||(b))
((a)||(b)||(c))

For more examples on overloading macro on count of arguments see this thread. I am using ## GNU extension to remove the comma before __VA_ARGS__ because I am used to using it - I think __VA_OPT__(,) should be nowadays preferred, I am not sure.