There are many ways to do this. The most simple is to predefine a version of the loop for each possible length (building on smaller versions), and simply choose the right one based on the number of arguments to iterate over:
#define M_NARGS(...) M_NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) #define M_NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N #define M_CONC(A, B) M_CONC_(A, B) #define M_CONC_(A, B) A##B #define M_ID(...) __VA_ARGS__ #define M_FOR_EACH(ACTN, ...) M_CONC(M_FOR_EACH_, M_NARGS(__VA_ARGS__)) (ACTN, __VA_ARGS__) #define M_FOR_EACH_0(ACTN, E) E #define M_FOR_EACH_1(ACTN, E) ACTN(E) #define M_FOR_EACH_2(ACTN, E, ...) ACTN(E) M_FOR_EACH_1(ACTN, __VA_ARGS__) #define M_FOR_EACH_3(ACTN, E, ...) ACTN(E) M_FOR_EACH_2(ACTN, __VA_ARGS__) #define M_FOR_EACH_4(ACTN, E, ...) ACTN(E) M_FOR_EACH_3(ACTN, __VA_ARGS__) #define M_FOR_EACH_5(ACTN, E, ...) ACTN(E) M_FOR_EACH_4(ACTN, __VA_ARGS__) //...etc #define FUNCTION_DEF(func) extern int func(void); #define FUNCTION_DEFS(...) M_FOR_EACH(FUNCTION_DEF, __VA_ARGS__)
You could also cook up a more general solution using traditional recursive techniques, but that usually requires a support library (such as [1], [2]) to provide the mechanism since directly-defined macros don't support recursion.
This is because all looping in the preprocessor has to have a predetermined upper limit, a a consequence of no direct macro recursion: you can either hard-code that limit into your loop implementation in simple cases like the above code, or you can have the recursion-driver underlying your loop-construction operators contain the limit instead, and provide N iterations to constructs that request them (the advantage of the latter is that it lets you centralize, and then forget about, the limit as long as it's high enough, e.g. Order-PP has a limit in the billions of iterations that you won't ever hit in practice).