In the past I've used a style like
#define FOR_EACH(macro, ...) __VA_OPT__(FOR_EACH1(macro, __VA_ARGS__))
#define FOR_EACH1(macro, arg, ...) macro(arg) __VA_OPT__(FOR_EACH2(macro, __VA_ARGS__))
#define FOR_EACH2(macro, arg, ...) macro(arg) __VA_OPT__(FOR_EACH3(macro, __VA_ARGS__))
#define FOR_EACH3(macro, arg, ...) macro(arg) __VA_OPT__(FOR_EACH4(macro, __VA_ARGS__))
[etc...]
which doesn't provide exponential growth in the maximum argument count, but does decouple the maximum count from the number of expansions. Even if you continue the pattern up to FOR_EACH100, calling FOR_EACH with 3 arguments will still only do 3+1 expansions.The author chose N=4 for the recursive macro approach, supporting up to 256 arguments, at the cost of performing 342 expansions for each use. That sounds reasonable; preprocessing is much faster than other compiler passes and you probably won't notice the cost at all. So it's probably better than my approach.
On the other hand, if I bump the recursive approach up to N=10, supporting up to 1048576 arguments at the cost of performing around that many expansions per use, then performance becomes obviously unacceptable (when running `clang -E`, you can watch the tokens being emitted one by one). So you do have to set a limit somewhere.
I wonder if there is some way to get the best of both worlds – exponential maximum number of arguments per line of code, but still only a linear number of expansions per actual argument.