As https://stackoverflow.com/a/11994395/1938348 do not work well in every case for GCC 12, there is improved version using __VA_OPT__ to remove superfluous commas:
#include <assert.h>
// Make a FOREACH macro
#define FE_0(WHAT)
#define FE_1(WHAT, X) WHAT(X)
#define FE_2(WHAT, X, ...) WHAT(X)FE_1(WHAT, __VA_ARGS__)
#define FE_3(WHAT, X, ...) WHAT(X)FE_2(WHAT, __VA_ARGS__)
#define FE_4(WHAT, X, ...) WHAT(X)FE_3(WHAT, __VA_ARGS__)
#define FE_5(WHAT, X, ...) WHAT(X)FE_4(WHAT, __VA_ARGS__)
//... repeat as needed
#define GET_MACRO(_1,_2,_3,_4,_5,NAME,...) NAME
#define FOR_EACH(action,...) \
GET_MACRO(__VA_ARGS__ __VA_OPT__(,) FE_5,FE_4,FE_3,FE_2,FE_1,FE_0)(action __VA_OPT__(,) __VA_ARGS__)
#define F(X) _Generic((X), int:1, long: 2, float: 4),
#define CALL(FF, ...) FF((int[]){ FOR_EACH(F, __VA_ARGS__) 0 } __VA_OPT__(,) __VA_ARGS__)
int foo(int* p, ...){ int i = 0; while(*p != 0) { i += *p; ++p; } return i; }
int main()
{
assert(CALL(foo) == 0);
assert(CALL(foo, 1) == 1);
assert(CALL(foo, 1l) == 2);
assert(CALL(foo, 1.f) == 4);
assert(CALL(foo, 1.f, 1) == 5);
assert(CALL(foo, 3l, 1.f, 1) == 7);
}
Working example: https://godbolt.org/z/q7nbj7PxY