I am trying to fill-in an array with the offset of structure field, I am trying to do the following
#define EXPAND_(X) X
#define TYPE_ARG_N(_0, _1, _2, N, ...) N
#define TYPE_OFFSET_1(S, _0) { sizeof(S), { offsetof(S, _0) } }
#define TYPE_OFFSET_2(S, _0, _1) { sizeof(S), { offsetof(S, _0), offsetof(S, _1) } }
#define TYPE_OFFSET_3(S, _0, _1, _2) { sizeof(S), { offsetof(S, _0), offsetof(S, _1), offsetof(S, _2) } }
#define TYPE_OFFSET_LIST() TYPE_OFFSET_3, TYPE_OFFSET_2, TYPE_OFFSET_1
#define TYPE_OFFSET_N_(...) EXPAND_(TYPE_ARG_N(__VA_ARGS__))
#define TYPE_OFFSET_ARGS(...) EXPAND_(__VA_ARGS__)
#define TYPE_OFFSET_SELECT(...) TYPE_OFFSET_N_(__VA_ARGS__, TYPE_OFFSET_LIST())
#define TYPE_OFFSET(S, ...) TYPE_OFFSET_SELECT(__VA_ARGS__)(S, TYPE_OFFSET_ARGS(__VA_ARGS__))
typedef struct {
size_t size;
size_t* offsets;
} tTable;
tTable t = TYPE_OFFSET(tTable, size, offsets);
MSVC2017 fails with the following:
error C4003: not enough actual parameters for macro 'TYPE_OFFSET_2'
error C2065: 'offsets': undeclared identifier
error C2102: '&' requires l-value
Any idea on how to fix these macros ?
For debugging things like this, try running things through just the preprocessor using the /EP flag. Doing so with your code shows this output:
typedef struct {
size_t size;
size_t* offsets;
} tTable;
tTable t = fxma.h(17) : warning C4003: not enough actual parameters for macro 'TYPE_OFFSET_2'
{ sizeof(tTable), { offsetof(tTable, size, offsets), offsetof(tTable, ) } };
The problem here is that Microsoft's preprocessor has this notion of a single macro argument having commas in it. This happens when the commas are produced by the expansion of another macro.
In particular, TYPE_OFFSET calls TYPE_OFFSET_2 with (tTable, size, offset), but size, offset together (being the expansion of TYPE_OFFSET_ARGS(__VA_ARGS__)) isn't actually two different arguments... it's only 1. TYPE_OFFSET_2 then is getting only two arguments; in other words:
S is tTable1
_0 is size, offset
_1 is missing
(You can see this in the expansion; offsetof(tTable, size, offsets)).
A fix is to add a level of indirection. Replace your version of TYPE_OFFSET with this:
#define TYPE_OFFSET_CALL(X, Y) X Y
#define TYPE_OFFSET(S, ...) TYPE_OFFSET_CALL(TYPE_OFFSET_SELECT(__VA_ARGS__),(S, TYPE_OFFSET_ARGS(__VA_ARGS__)))
Related
I want to implement in C something similar to lambda functions from C++( using macros and function pointers)
I think the biggest problem that I am facing is to define a function inside another function, and this thing is not possible in C. I think a better idea is to treat the lambda function ( passed through a macro ) as a lexical block.
I started some code:
#define func_name(line) func##line
#define line __LINE__
#define lambda(body, ret_type, ...) ret_type func_name(line)(__VA_ARGS__) \
{ \
body; \
} \
//#include <stdio.h>
lambda( printf("Hello from Lambda\n") , void, int a, float b)
int main(void) {
//printf("Hello World\n");
return 0;
}
I used gcc compiler with "-E" option to see preprocessor output:
void funcline(int a, float b) { printf("Hello from Lambda\n"); }
int main(void) {
return 0;
}
It's possible, but the lambdas will have to be stateless (no captures). You can use preprocessor to move function definitions around, but there is no way to use local variables from one function in another, or to introduce some kind of state into a function.
Also it makes the code very hard to debug. Since all functions using those pseudo-lambdas have to be wrapped in a macro, all line breaks in them are removed during preprocessing. It becomes impossible to place a breakpoint inside of such a function, or to advance through it line by line.
Here is an example of the usage. The implementation is at the end of the answer. The explanation of the syntax is right after the example.
Run on gcc.godbolt.org
#include <stdio.h>
#include <stdlib.h>
ENABLE_LAMBDAS(
void example1()
{
int arr[] = {4,1,3,2,5};
FUNC(int)(compare)(const void *a, const void *b)
(
return *(int*)a - *(int*)b;
)
qsort(arr, 5, sizeof(int), compare);
for (int i = 0; i < 5; i++ )
printf("%d ", arr[i]);
putchar('\n');
}
void example2()
{
int arr[] = {4,1,3,2,5};
qsort L_(arr, 5, sizeof(int), LAMBDA(int)(const void *a, const void *b)
(
return *(int*)a - *(int*)b;
));
for (int i = 0; i < 5; i++ )
printf("%d ", arr[i]);
putchar('\n');
}
int main()
{
example1();
example2();
}
) // ENABLE_LAMBDAS
Notice the ENABLE_LAMBDAS macro wrapping the whole snippet.
This example uses two ways of defining functions/lambdas:
FUNC(return_type)(name)(params)(body) just defines a function. The function definition is moved to the beginning of ENABLE_LAMBDAS, so it can be used inside of other functions.
LAMBDA(return_type)(params)(body) defines a pseudo-lambda. A function definition for it is generated at the beginning of ENABLE_LAMBDAS, with an automatically chosen unique name. LAMBDA... expands to that name.
If FUNC or LAMBDA are used inside of parentheses, the parentheses must be preceeded by the L_ macro. This is a limitation of the preprocessor, unfortunately.
The generated functions are always static.
Implementation:
// Creates a lambda.
// Usage:
// LAMBDA(return_type)(params)(body)
// Example:
// ptr = LAMBDA(int)(int x, int y)(return x + y;);
#define LAMBDA LAM_LAMBDA
// Defines a function.
// Usage:
// FUNC(return_type)(name)(params)(body)
// Example:
// FUNC(int)(foo)(int x, int y)(return x + y;)
// some_func(foo);
#define FUNC LAM_FUNC
// Any time a `LAMBDA` or `FUNC` appears inside of parentheses,
// those parentheses must be preceeded by this macro.
// For example, this is wrong:
// foo(LAMBDA(int)()(return 42;));
// While this works:
// foo L_(LAMBDA(int)()(return 42;));
#define L_ LAM_NEST
// `LAMBDA` and `FUNC` only work inside `ENABLE_LAMBDAS(...)`.
// `ENABLE_LAMBDAS(...)` expands to `...`, preceeded by function definitions for all the lambdas.
#define ENABLE_LAMBDAS LAM_ENABLE_LAMBDAS
// Lambda names are composed of this prefix and a numeric ID.
#ifndef LAM_PREFIX
#define LAM_PREFIX LambdaFunc_
#endif
// Implementation details:
// Returns nothing.
#define LAM_NULL(...)
// Identity macro.
#define LAM_IDENTITY(...) __VA_ARGS__
// Concats two arguments.
#define LAM_CAT(x, y) LAM_CAT_(x, y)
#define LAM_CAT_(x, y) x##y
// Given `(x)y`, returns `x`.
#define LAM_PAR(...) LAM_PAR_ __VA_ARGS__ )
#define LAM_PAR_(...) __VA_ARGS__ LAM_NULL(
// Given `(x)y`, returns `y`.
#define LAM_NO_PAR(...) LAM_NULL __VA_ARGS__
// Expands `...` and concats it with `_END`.
#define LAM_END(...) LAM_END_(__VA_ARGS__)
#define LAM_END_(...) __VA_ARGS__##_END
// A generic macro to define functions and lambdas.
// Usage: `LAM_DEFINE(wrap, ret)(name)(params)(body)`.
// In the encloding code, expands to `wrap(name)`.
#define LAM_DEFINE(wrap, ...) )(l,wrap,(__VA_ARGS__),LAM_DEFINE_0
#define LAM_DEFINE_0(name) name,LAM_DEFINE_1
#define LAM_DEFINE_1(...) (__VA_ARGS__),LAM_DEFINE_2
#define LAM_DEFINE_2(...) __VA_ARGS__)(c,
// Creates a lambda.
// Usage: `LAM_LAMBDA(ret)(params)(body)`.
#define LAM_LAMBDA(...) LAM_DEFINE(LAM_IDENTITY, __VA_ARGS__)(LAM_CAT(LAM_PREFIX, __COUNTER__))
// Defines a function.
// Usage: `LAM_FUNC(ret)(name)(params)(body)`.
#define LAM_FUNC(...) LAM_DEFINE(LAM_NULL, __VA_ARGS__)
// `LAM_LAMBDA` and `LAM_FUNC` only work inside of this macro.
#define LAM_ENABLE_LAMBDAS(...) \
LAM_END( LAM_GEN_LAMBDAS_A (c,__VA_ARGS__) ) \
LAM_END( LAM_GEN_CODE_A (c,__VA_ARGS__) )
// Processes lambdas and functions in the following parentheses.
#define LAM_NEST(...) )(open,)(c,__VA_ARGS__)(close,)(c,
// A loop. Returns the original code, with lambdas replaced with corresponding function names.
#define LAM_GEN_CODE_A(...) LAM_GEN_CODE_BODY(__VA_ARGS__) LAM_GEN_CODE_B
#define LAM_GEN_CODE_B(...) LAM_GEN_CODE_BODY(__VA_ARGS__) LAM_GEN_CODE_A
#define LAM_GEN_CODE_A_END
#define LAM_GEN_CODE_B_END
#define LAM_GEN_CODE_BODY(type, ...) LAM_CAT(LAM_GEN_CODE_BODY_, type)(__VA_ARGS__)
#define LAM_GEN_CODE_BODY_c(...) __VA_ARGS__
#define LAM_GEN_CODE_BODY_l(wrap, ret, name, ...) wrap(name)
#define LAM_GEN_CODE_BODY_open() (
#define LAM_GEN_CODE_BODY_close() )
// A loop. Generates lambda definitions, discarding all other code.
#define LAM_GEN_LAMBDAS_A(...) LAM_GEN_LAMBDAS_BODY(__VA_ARGS__) LAM_GEN_LAMBDAS_B
#define LAM_GEN_LAMBDAS_B(...) LAM_GEN_LAMBDAS_BODY(__VA_ARGS__) LAM_GEN_LAMBDAS_A
#define LAM_GEN_LAMBDAS_A_END
#define LAM_GEN_LAMBDAS_B_END
#define LAM_GEN_LAMBDAS_BODY(type, ...) LAM_CAT(LAM_GEN_LAMBDAS_BODY_, type)(__VA_ARGS__)
#define LAM_GEN_LAMBDAS_BODY_c(...)
#define LAM_GEN_LAMBDAS_BODY_l(wrap, ret, name, par, ...) static LAM_IDENTITY ret name par { __VA_ARGS__ }
#define LAM_GEN_LAMBDAS_BODY_open()
#define LAM_GEN_LAMBDAS_BODY_close()
The Issue
Well, I have this really interesting macro set
#define __macro_3_opt_args(_0, _1, _2, _3, name, ...) name
#define _macro_3_opt_args_(arg0, arg1, arg2, arg3, ...) __macro_3_opt_args(, ##__VA_ARGS__, arg3, arg2, arg1, arg0)(__VA_ARGS__)
#define __padding_id(size, id) uint8_t _padding_##id##_ [size]
#define ____padding_line(size, line) __padding_id(size, ln##line) //adding `ln` prefix
#define ___padding_line(size, line) ____padding_line(size, line) //expanding `__LINE__` macro first
#define __padding_line(size) ___padding_line(size, __LINE__)
#define _padding_(...) _macro_2_opt_args_(, __padding_line, __padding_id, __VA_ARGS__)
#define offset_struct union
#define _offset_zero_member(type, name) type name
#define _offset_member(type, name, offset) struct { __padding_id(offset, to_##name); type name; }
#define offset_member(type, name, ...) _macro_3_opt_args_(, , _offset_zero_member, _offset_member, type, name, ##__VA_ARGS__)
But if I try to use it (like this:)
offset_struct Test {
offset_member (int, header);
offset_member (void*, data, 64);
} test;
//Let's say this two code snippets are in a same file
VS highlights the offset_member macro "calls" as errors (I use Microsoft's C/C++ Extension).
When I lookup VS Code's macro expansion
it shows struct { uint8_t _padding_to__ []; void*, data,64 ; }
instead of struct { uint8_t _padding_to_data_ [64]; void* data; } (what GCC sees)
The Question
How do I make VS ignore the macro expansion?
Can I use some magic #pragma for that?
Or is there a config that does it?
Is there a way to define a macro that voids variable list of arguments?
#define VOID_ARGS(...) ((void)##__VA_ARGS__)
The use case is void arguments to suppress compiler error [-Werror=unused-value] when warnings treated as errors:
#define DEBUG 1
#ifdef DEBUG
#define func(fmt, ...) dbg_func(fmt, ##__VA_ARGS__)
#else
#define func(fmt, ...) VOID_ARGS(fmt, ##__VA_ARGS__)
#endif
Does this give you an idea how to solve that problem?
debug.h:
extern int dbg_func(const char *format, ...);
//Does nothing
extern int ignoreDebug(const char *format, ...);
#define DEBUG 1
#ifdef DEBUG
#define func(fmt, ...) dbg_func(fmt, ##__VA_ARGS__)
#else
#define func(fmt, ...) ignoreDebug(fmt, ##__VA_ARGS__)
#endif
debug.c:
int ignoreDebug(const char *format, ...)
{
(void)format;
return 0;
}
int dbg_func(const char *format, ...)
{
TODO: Some code needs to go here.
return 0;
}
Rather than attempting to put the debug logic in the function declaration, add it to the function body instead:
int dbg_func(const char *format, ...)
{
#ifdef DEBUG
// normal debug logic
#else
(void)format;
return 0;
#endif
}
I found a way only using the processor. The idea came from this answer https://stackoverflow.com/a/11763277/6082851 The idea is to define a bunch of macros that void the arguments, one macro per possible number of arguments. With the use of __VA_ARGS__, the correct macro can be chosen depending on the number of arguments. Sadly, i didn't found a way to make it recursive so that a limited number of macros can be used for an arbitrary number of arguments, the only way i found was to define a macro for each possible number of arguments. But it can be expanded to an arbitrary amount.
#include <stdio.h>
#ifndef DEBUG
#define DEBUG 1
#endif
#if DEBUG
#define DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__)
#else
//GET_MACRO will get the 6. argument
#define GET_MACRO(a,b,c,d,e,f,...) f
//Macros that void a number of arguments
#define SET_VOID0()
#define SET_VOID1(a) (void)a;
#define SET_VOID2(a,b) (void)a;(void)b;
#define SET_VOID3(a,b,c) (void)a;(void)b;(void)c;
#define SET_VOID4(a,b,c,d) (void)a;(void)b;(void)c;(void)d;
#define SET_VOID5(a,b,c,d,e) (void)a;(void)b;(void)c;(void)d;(void)e;
//Void all arguments to avoid compiler warnings.
//SET_VOID5 is used when there are 5 arguments used, SET_VOID4 when 4 are used, ...
#define DEBUG_PRINT(...) GET_MACRO(__VA_ARGS__, SET_VOID5, SET_VOID4, SET_VOID3, SET_VOID2, SET_VOID1, SET_VOID0)(__VA_ARGS__)
#endif
int main(void)
{
int foo=5;
int bar=3;
DEBUG_PRINT("Foo %i Bar %i\n",foo,bar);
return 0;
}
Simple idea:
I'm using X-macros to define command list structure and declare command callbacks.
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#define COMMAND_LIST(X) \
X(toto_all) \
X(help) \
//end of list
typedef void (*callback_t)(int a, int b);
typedef struct
{
char * name;
callback_t callback;
}command_t;
#define CALLBACK_DEC(COMMAND_NAME) void _##COMMAND_NAME(int a, int b);
COMMAND_LIST(CALLBACK_DEC)
#define COMMAND_DEF(COMMAND_NAME) { #COMMAND_NAME, & _##COMMAND_NAME },
static command_t commands[] =
{
COMMAND_LIST(COMMAND_DEF)
};
#define COMMAND(COMMAND_NAME,CODE) void _##COMMAND_NAME(int A, int B) { CODE }
COMMAND(toto_all,
printf("helloworld\n");
)
COMMAND(help,
printf("help!\n");
)
int main()
{
commands[0].callback(1,2);
commands[1].callback(1,2);
return 0;
}
it works.
helloworld
help!
Adding some parameters:
If you change the first command list to this (by adding parameters)
#define COMMAND_LIST(X) \
X(toto_all, 1, 3, 5) \
X(help, 0, 0, 0) \
//end of list
typedef struct
{
callback_t callback;
char * name;
int arg_min;
int arg_max;
int arg_num;
}command_t;
then, when running it I get the following error:
macro "CALLBACK_DEC" passed 4 arguments, but takes just 1
I have to use all the parameters for the command list definition (command declaration):
#define COMMAND_DEF(COMMAND_NAME, ARG_MIN, ARG_MAX, ARG_MAX, ARG_NUM) (command_t){ #COMMAND_NAME, & _##COMMAND_NAME, ARG_MIN, ARG_MAX, ARG_NUM},
but it's quite tricky to now use it for the callback declaration...
Is there a clever way for this X-macro to avoid this error?
I thought about the non-macro way to mask unused parameters:
which is by using (void)param;,
which gives the ugly
#define CALLBACK_DEC(COMMAND_NAME, ARG_MIN, ARG_MAX, ARG_NUM) void _##COMMAND_NAME(int a, int b); void(ARG_MIN); void(ARG_MAX); void(ARG_NUM)
and this does not work...I get a strange:
main.c:27:20: error: expected identifier or ‘(’ before numeric constant
X(toto_all,0,0,0) \
I think there is another way:
maybe using something like this...
#define COMMAND_LIST(X,Y) \
X(Y(toto_all, 0, 0, 0)) \
X(Y(help, 0, 0, 0)) \
//command name, arg min, arg max, arg num, string?
//end of list
typedef void (*callback_t)(int a, int b);
typedef struct
{
char * name;
callback_t callback;
}command_t;
#define GET_ONLY_NAME(COMMAND_NAME1, ARG_MIN, ARG_MAX, ARG_NUM) COMMAND_NAME1
#define CALLBACK_DEC(COMMAND_NAME) void _##COMMAND_NAME(int a, int b);
COMMAND_LIST(CALLBACK_DEC,GET_ONLY_NAME);
#undef CALLBACK_DEC
#define GET_FULL_LIST(X) X
#define COMMAND_DEF(COMMAND_NAME, ARG_MIN, ARG_MAX, ARG_NUM) (command_t){ #COMMAND_NAME, & _##COMMAND_NAME, ARG_MIN, ARG_MAX, ARG_NUM},
static command_t commands[] =
{
COMMAND_LIST(COMMAND_DEF,GET_FULL_LIST)
};
#undef COMMAND_DEF
but I still get the following strange error, there is a problem in the expansion but i can't see where...
main.c:27:31: error: expected ‘)’ before numeric constant
X(Y(toto_all, 0, 0, 0)) \
Maybe the truth is elsewhere... :)
any hints?
This is a an issue with X macros overall - you have to write a macro accepting all parameters, even when you are just using a few.
In your case you pass the specific macro as a parameter to the list, so you can add some flexibility there. Using variadic macros might solve the problem. You should be able to do like this:
#define COMMAND_DEF(COMMAND_NAME, ...) { #COMMAND_NAME, & _##COMMAND_NAME },
...
COMMAND_LIST(COMMAND_DEF)
Where you only explicitly name the parameters that this particular macro is interested in, then let the rest of them go into the ... part which is then ignored.
This does however build in a dependency in the data, because it only allows you to expand parameters from left to right, so to speak. So for
X(toto_all, 1, 3, 5, "-")
you can write a macro that uses just toto_all, or toto_all and 1, but you would't be able write a macro that just uses for example 1 and 3. For such special cases I believe you will still have to name all macro parameters.
Yet another option is self-documenting code:
#define COMMAND_DEF(COMMAND_NAME, ignored1, FOO, ignored2, ignored3) \
/* do stuff with COMMAND NAME and FOO only */
background
I'm trying to make automatic generator of Lua-C interface using C macros. The biggest problem was to make it general for varying number of arguments, which I resolved by using __VA_ARGS__ with help of this answer: Is it possible to iterate over arguments in variadic macros?
Simpler almost working solution
this solution almost works, but it produce some redudant commas (nottice ,,,, in output)
// helper macros for iteration over __VA_ARGS__
#define ARG1(WHAT,X,...) WHAT(X)ARG2(WHAT,__VA_ARGS__)
#define ARG2(WHAT,X,...) WHAT(X)ARG3(WHAT,__VA_ARGS__)
#define ARG3(WHAT,X,...) WHAT(X)ARG4(WHAT,__VA_ARGS__)
#define ARG4(WHAT,X,...) WHAT(X)ARG5(WHAT,__VA_ARGS__)
#define ARG5(WHAT,X,...) WHAT(X)ARG6(WHAT,__VA_ARGS__)
#define ARG6(WHAT,X,...) WHAT(X)//ARG2(__VA_ARGS__)
// macros dispatch propper type of Lua::get
#define LUA_GET_int(i) Lua::getInt(L,i)
#define LUA_GET_long(i) Lua::getInt(L,i)
#define LUA_GET_float(i) (float)Lua::getDouble(L,i)
#define LUA_GET_double(i) Lua::getDouble(L,i)
#define LUA_GET_string(i) Lua::getString(L,i)
#define LUA_PUSH_int(a) lua_pushnumber(L,a)
#define LUA_PUSH_float(a) lua_pushnumber(L,a)
#define LUA_PUSH_double(a) lua_pushnumber(L,a)
#define LUA_PUSH_float(a) lua_pushstring(L,a)
#define LUA_GET_(T)
#define LUA_GET(T) ,LUA_GET_##T(i++) // commas come from here
#define MAKE_LUA_FUNC(TR,fname,T1,...) int l_##fname(lua_State * L){ int i=0; LUA_PUSH_##TR( fname( LUA_GET_##T1(i++) ARG1(LUA_GET,__VA_ARGS__) ) ); return 1; }
// interface for function:
// double add3(float, int, double );
MAKE_LUA_FUNC( double, add3, float, int, double )
// output:
// 'int l_add3(lua_State * L){ int i=0; lua_pushnumber(L,add3((float)Lua::getDouble(L,i++) ,Lua::getInt(L,i++),Lua::getDouble(L,i++),,,, )); return 1; }'
Working but less-nice solution
I had to duplicate LUA_GET_ macros for case when it is first in argument list (without comma) and otherwise (with comma in front)
// begin of argument list => no commas
#define LUA_GET_int(i) Lua::getInt(L,i)
#define LUA_GET_long(i) Lua::getInt(L,i)
#define LUA_GET_float(i) (float)Lua::getDouble(L,i)
#define LUA_GET_double(i) Lua::getDouble(L,i)
#define LUA_GET_string(i) Lua::getString(L,i)
// rest of argument list => with commas
#define LUA_GET__int(i) ,Lua::getInt(L,i)
#define LUA_GET__long(i) ,Lua::getInt(L,i)
#define LUA_GET__float(i) ,(float)Lua::getDouble(L,i)
#define LUA_GET__double(i) ,Lua::getDouble(L,i)
#define LUA_GET__string(i) ,Lua::getString(L,i)
#define LUA_PUSH_int(a) lua_pushnumber(L,a)
#define LUA_PUSH_float(a) lua_pushnumber(L,a)
#define LUA_PUSH_double(a) lua_pushnumber(L,a)
#define LUA_PUSH_float(a) lua_pushstring(L,a)
#define LUA_GET_(T)
#define LUA_GET__(T)
#define LUA_GET(T) LUA_GET__##T(i++)
#define MAKE_LUA_FUNC(TR,fname,T1,...) int l_##fname(lua_State * L){ int i=0; LUA_PUSH_##TR( fname( LUA_GET_##T1(i++) ARG1(LUA_GET,__VA_ARGS__) ) ); return 1; }
// MAKE_LUA_FUNC( double, add3, float, int, double )
// output:
// int l_add3(lua_State * L){ int i=0; lua_pushnumber(L,add3( (float)Lua::getDouble(L,i++) ,Lua::getInt(L,i++),Lua::getDouble(L,i++) )); return 1; }
Is it possible to make it simpler / nicer ?
NOTE - for debugging I found very useful this Seeing expanded C macros in particular https://stackoverflow.com/a/31460434/1291544
You need to count the number of arguments you have, and then call the corresponding ARG# macro.
#define ARGS_N(M,...) \
ARGS_N__(__VA_ARGS__, 6, 5, 4, 3, 2, 1)(M, __VA_ARGS__)
#define ARGS_N__(_1, _2, _3, _4, _5, _6, X, ...) ARGS_##X
#define ARGS_1(M, X) M(X)
#define ARGS_2(M, X, ...) M(X)ARGS_1(M, __VA_ARGS__)
#define ARGS_3(M, X, ...) M(X)ARGS_2(M, __VA_ARGS__)
#define ARGS_4(M, X, ...) M(X)ARGS_3(M, __VA_ARGS__)
#define ARGS_5(M, X, ...) M(X)ARGS_4(M, __VA_ARGS__)
#define ARGS_6(M, X, ...) M(X)ARGS_5(M, __VA_ARGS__)
Now, change MAKE_LUA_FUNC to call ARGS_N instead of your ARG1.
The way the counting technique works is that ARGS_N invokes the helper ARGS_N__ with the variable arguments, and then pads out the invocation with additional arguments. ARGS_N__ does the counting by always utilizing the 7th argument. So, if ARGS_N is provided 4 variable arguments after the first one, ARGS_N__ will produce ARGS_4, because in that case, in the padding provided by ARGS_N, 4 would be the 7th argument.
ARGS_N__(__VA_ARGS__, 6, 5, 4, 3, 2, 1)(M, __VA_ARGS__)
. .
/|\ /|\
| |
If this has 4 arguments
|
This would be the 7th argument
This is the same technique that was shown in the answer you pointed to. However, that version was a bit more complicated than the version I am illustrating for you, so hopefully you will find this explanation helpful.