在C / C ++宏中的__VA_ARGS__上迭代添加分隔符

时间:2018-05-10 19:37:36

标签: c lua metaprogramming boilerplate variadic-macros

背景

我试图使用C宏制作Lua-C接口的自动生成器。最大的问题是让它适用于不同数量的参数,我在这个答案的帮助下使用__VA_ARGS__解决了这个问题:Is it possible to iterate over arguments in variadic macros?

简单易用的解决方案

此解决方案几乎可以正常工作,但它会产生一些减少号逗号(输出中的,,,,字段)

// 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; }'

工作但不太好的解决方案

我必须复制LUA_GET_宏,以便它在参数列表中第一个(没有逗号)和其他情况(在前面用逗号)

// 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; }

是否可以使其更简单/更好?

注意 - 为了进行调试,我发现这个Seeing expanded C macros非常有用,特别是https://stackoverflow.com/a/31460434/1291544

0 个答案:

没有答案