Reputation: 91
I'd like to know how to apply a unary function (or another macro) to variadic arguments of a macro, like
int f(int a);
#define apply(args...) <the magic>
apply(a, b, c)
which unrolls
f(a)
f(b)
f(c)
Note that the number of arguments is unknown.
Upvotes: 6
Views: 3115
Reputation: 5631
The code below is working for what you've asked for with up to 1024 arguments and without using additional stuff like boost. It defines an EVAL(...)
and also a MAP(m, first, ...)
macro to do recursion and to use for each iteration the macro m
with the next parameter first
.
With the use of that, your apply(...)
looks like: #define apply(...) EVAL(MAP(apply_, __VA_ARGS__))
.
It is mostly copied from C Pre-Processor Magic. It is also great explained there. You can also download these helper macros like EVAL(...)
at this git repository, there are also a lot of explanation in the actual code. It is variadic so it takes the number of arguments you want.
But I changed the FIRST
and the SECOND
macro as it uses a Gnu extension like it is in the source I've copied it from. This is said in the comments below by @HWalters:
Specifically, 6.10.3p4: "Otherwise [the identifier-list ends in a ...] there shall be more arguments in the invocation than there are parameters in the macro definition (excluding the ...)".
Main function part:
int main()
{
int a, b, c;
apply(a, b, c) /* Expands to: f(a); f(b); f(c); */
return 0;
}
Macro definitions:
#define FIRST_(a, ...) a
#define SECOND_(a, b, ...) b
#define FIRST(...) FIRST_(__VA_ARGS__,)
#define SECOND(...) SECOND_(__VA_ARGS__,)
#define EMPTY()
#define EVAL(...) EVAL1024(__VA_ARGS__)
#define EVAL1024(...) EVAL512(EVAL512(__VA_ARGS__))
#define EVAL512(...) EVAL256(EVAL256(__VA_ARGS__))
#define EVAL256(...) EVAL128(EVAL128(__VA_ARGS__))
#define EVAL128(...) EVAL64(EVAL64(__VA_ARGS__))
#define EVAL64(...) EVAL32(EVAL32(__VA_ARGS__))
#define EVAL32(...) EVAL16(EVAL16(__VA_ARGS__))
#define EVAL16(...) EVAL8(EVAL8(__VA_ARGS__))
#define EVAL8(...) EVAL4(EVAL4(__VA_ARGS__))
#define EVAL4(...) EVAL2(EVAL2(__VA_ARGS__))
#define EVAL2(...) EVAL1(EVAL1(__VA_ARGS__))
#define EVAL1(...) __VA_ARGS__
#define DEFER1(m) m EMPTY()
#define DEFER2(m) m EMPTY EMPTY()()
#define IS_PROBE(...) SECOND(__VA_ARGS__, 0)
#define PROBE() ~, 1
#define CAT(a,b) a ## b
#define NOT(x) IS_PROBE(CAT(_NOT_, x))
#define _NOT_0 PROBE()
#define BOOL(x) NOT(NOT(x))
#define IF_ELSE(condition) _IF_ELSE(BOOL(condition))
#define _IF_ELSE(condition) CAT(_IF_, condition)
#define _IF_1(...) __VA_ARGS__ _IF_1_ELSE
#define _IF_0(...) _IF_0_ELSE
#define _IF_1_ELSE(...)
#define _IF_0_ELSE(...) __VA_ARGS__
#define HAS_ARGS(...) BOOL(FIRST(_END_OF_ARGUMENTS_ __VA_ARGS__)())
#define _END_OF_ARGUMENTS_() 0
#define MAP(m, first, ...) \
m(first) \
IF_ELSE(HAS_ARGS(__VA_ARGS__))( \
DEFER2(_MAP)()(m, __VA_ARGS__) \
)( \
/* Do nothing, just terminate */ \
)
#define _MAP() MAP
#define apply_(x) f(x);
#define apply(...) EVAL(MAP(apply_, __VA_ARGS__))
To test macro expansion it is useful to use gcc with the command line argument -E
:
$ gcc -E srcFile.c
because your're getting concrete error messages and understand what's going on.
Upvotes: 7
Reputation: 213276
Everything is possible in C if you throw enough ugly macros at it. For example, you can have an ugly function-like macro:
#include <stdio.h>
int f (int a)
{
printf("%d\n", a);
}
#define SIZEOF(arr) (sizeof(arr) / sizeof(*arr))
#define apply(...) \
{ \
int arr[] = {__VA_ARGS__}; \
for(size_t i=0; i<SIZEOF(arr); i++) \
{ \
f(arr[i]); \
} \
}
int main (void)
{
apply(1, 2, 3);
}
Notice that 1) This would be much better off as a variadic function, and 2) it would be even better if you get rid of the variadic nonsense entirely and simply make a function such as
int f (size_t n, int array[n])
Upvotes: 2