C++调用LUA函数,可变參模板实现
极其方便调用LUA函数,支持返回值方式:
调用演示样例:
luax_vcall("func_1", 12, 33, 4.0, "helloworld");
int result = luax_pvicall("utils.math.add", 20, 30, 100);
直接贴出代码:
/* powerful lua call, vardic template. */ #ifndef _POWERFUL_LUA_CALL_HELPER_ #define _POWERFUL_LUA_CALL_HELPER_ /// helper inline bool luax_assume_func(lua_State* L, const char* func); /// FUNCTION TEMPLATE: luax_vcall template<typename..._Args> inline void luax_vcall(const char* func, const _Args&...args); template<typename _Result, typename..._Args> inline _Result luax_vxcall(const char* func, const _Args&...args); /// TEMPLATE luax_vxcall alias template<typename..._Args> inline int luax_vicall(const char* func, const _Args&...args); template<typename..._Args> inline float luax_vfcall(const char* func, const _Args&...args); template<typename..._Args> inline double luax_vdcall(const char* func, const _Args&...args); template<typename..._Args> inline std::string luax_vvcall(const char* func, const _Args&...args); /// FUNCTION TEMPLATE: luax_vpcall template<typename..._Args> inline void luax_pvcall(const char* func, const _Args&...args); template<typename _Result, typename..._Args> inline _Result luax_pvxcall(const char* func, const _Args&...args); /// TEMPLATE luax_pvxcall alias template<typename..._Args> inline int luax_pvicall(const char* func, const _Args&...args); template<typename..._Args> inline float luax_pvfcall(const char* func, const _Args&...args); template<typename..._Args> inline double luax_pvdcall(const char* func, const _Args&...args); template<typename..._Args> inline std::string luax_pvvcall(const char* func, const _Args&...args); /// arg push helper inline void luax_vpusharg(lua_State* L, int& carg, int& narg) { } inline void luax_vpusharg(lua_State* L, int& carg, int& narg, int arg) { ++carg; if (lua_checkstack(L, 1)) lua_pushinteger(L, arg), ++narg; } inline void luax_vpusharg(lua_State* L, int& carg, int& narg, float arg) { ++carg; if (lua_checkstack(L, 1)) lua_pushnumber(L, arg), ++narg; } inline void luax_vpusharg(lua_State* L, int& carg, int& narg, double arg) { ++carg; if (lua_checkstack(L, 1)) lua_pushnumber(L, arg), ++narg; } inline void luax_vpusharg(lua_State* L, int& carg, int& narg, const char* arg) { ++carg; if (lua_checkstack(L, 1)) lua_pushstring(L, arg), ++narg; } inline void luax_vpusharg(lua_State* L, int& carg, int& narg, const std::string& arg) { ++carg; if (lua_checkstack(L, 1)) lua_pushlstring(L, arg.c_str(), arg.length()), ++narg; } inline void luax_vpusharg(lua_State* L, int& carg, int& narg, void* arg) { ++carg; if (lua_checkstack(L, 1)) tolua_pushuserdata(L, arg), ++narg; } /// cocos2d-x object support #define LUAX_VCALL_ADD_CCOBJ_SUPPORT(type) \ inline \ void luax_vpusharg(lua_State* L, int& carg, int& narg, cocos2d::type* arg) \ { \ ++carg; \ if (lua_checkstack(L, 1)) \ object_to_luaval<cocos2d::type>(L, "cc." #type, arg),/*tolua_pushuserdata(L, arg),*/ ++narg; \ } #define LUAX_VCALL_ADD_CCUI_SUPPORT(type) \ inline \ void luax_vpusharg(lua_State* L, int& carg, int& narg, type* arg) \ { \ ++carg; \ if (lua_checkstack(L, 1)) \ object_to_luaval<cocos2d::ui::type>(L, "ccui." #type, arg),/*tolua_pushuserdata(L, arg),*/ ++narg; \ } LUAX_VCALL_ADD_CCOBJ_SUPPORT(Node) LUAX_VCALL_ADD_CCOBJ_SUPPORT(Scene) LUAX_VCALL_ADD_CCOBJ_SUPPORT(Layer) LUAX_VCALL_ADD_CCOBJ_SUPPORT(LayerColor) LUAX_VCALL_ADD_CCOBJ_SUPPORT(Sprite) template<typename _Ty, typename..._Args> inline void luax_vpusharg(lua_State* L, int& carg, int& narg, _Ty arg1, const _Args&...args) { luax_vpusharg(L, carg, narg, arg1); luax_vpusharg(L, carg, narg, args...); } template<typename _Ty> inline _Ty luax_getretval(lua_State* L); template<> inline int luax_getretval<int>(lua_State* L) { if (lua_isnumber(L, -1)){ return lua_tointeger(L, -1); } return 0; } template<> inline float luax_getretval<float>(lua_State* L) { if (lua_isnumber(L, -1)){ return lua_tonumber(L, -1); } return 0; } template<> inline double luax_getretval<double>(lua_State* L) { if (lua_isnumber(L, -1)){ return lua_tonumber(L, -1); } return 0; } template<> inline std::string luax_getretval<std::string>(lua_State* L) { if (lua_isstring(L, -1)){ return lua_tostring(L, -1); } return 0; } template<typename..._Args> inline void luax_vcall(const char* func, const _Args&...args) { auto L = luax_get_L(); auto top = lua_gettop(L); // store stack int carg = 0, narg = 0; lua_getglobal(L, func); if (!lua_isfunction(L, -1)) { cocos2d::log("luax_vcall failed, function:%s not exist!", func); goto err_exit; } luax_vpusharg(L, carg, narg, args...); if (carg != narg) { cocos2d::log("luax_vcall failed, argument exception:carg:%d,narg:%d", carg, narg); goto err_exit; } if (lua_pcall(L, narg, 0, 0) != 0) { cocos2d::log("luax_vcall failed, func:%s", func); goto err_exit; } lua_settop(L, top); // resume stack err_exit: lua_settop(L, top); // resume stack } inline bool luax_assume_func(lua_State* L, const char* func) { std::string source = func; const char* orig = source.c_str(); const char* name = orig; auto offst = 0; auto end = 0; end = source.find_first_of('.', offst); if (end == std::string::npos) { // assume _G.func lua_getglobal(L, name); if (lua_isfunction(L, -1)) return true; else return false; } // assume table source[end] = '\0'; lua_getglobal(L, name); if (!lua_istable(L, -1)) return false; offst = end + 1; // continue check sub table while ((end = source.find_first_of('.', offst)) != std::string::npos) { // assume table source[end] = '\0'; name = orig + offst; lua_getfield(L, -1, name); if (!lua_istable(L, -1)) { return false; } offst = end + 1; } // now assume function name = orig + offst; lua_getfield(L, -1, name); return !!lua_isfunction(L, -1); } template<typename _Result, typename..._Args> inline _Result luax_vxcall(const char* func, const _Args&...args) { auto L = luax_get_L(); auto top = lua_gettop(L); // store stack _Result result; int carg = 0, narg = 0; lua_getglobal(L, func); if (!lua_isfunction(L, -1)) { cocos2d::log("luax_vcall failed, function:%s not exist!", func); goto err_exit; } luax_vpusharg(L, carg, narg, args...); if (carg != narg) { cocos2d::log("luax_vcall failed, argument exception:carg:%d,narg:%d", carg, narg); goto err_exit; } if (lua_pcall(L, narg, 1, 0) != 0) { cocos2d::log("luax_vcall failed, lua_pcall failed"); goto err_exit; } result = luax_getretval<_Result>(L); lua_settop(L, top); // resume stack return std::move(result); err_exit: lua_settop(L, top); // resume stack return _Result(); } // TEMPLATE luax_vxcall alias template<typename..._Args> inline int luax_vicall(const char* func, const _Args&...args) { return luax_vxcall<int>(func, args...); } template<typename..._Args> inline float luax_vfcall(const char* func, const _Args&...args) { return luax_vxcall<float>(func, args...); } template<typename..._Args> inline double luax_vdcall(const char* func, const _Args&...args) { return luax_vxcall<double>(func, args...); } template<typename..._Args> inline std::string luax_vvcall(const char* func, const _Args&...args) { return luax_vxcall<std::string>(func, args...); } // support any talbe prefix template<typename..._Args> inline void luax_pvcall(const char* func, const _Args&...args) { auto L = luax_get_L(); auto top = lua_gettop(L); // store stack int carg = 0, narg = 0; if (!luax_assume_func(L, func)) { cocos2d::log("luax_vcall failed, function:%s not exist!", func); goto err_exit; } do_call: luax_vpusharg(L, carg, narg, args...); if (carg != narg) { goto err_exit; } if (lua_pcall(L, narg, 0, 0) != 0) { goto err_exit; } lua_settop(L, top); // resume stack err_exit: lua_settop(L, top); // resume stack } template<typename _Result, typename..._Args> inline _Result luax_pvxcall(const char* func, const _Args&...args) { auto L = luax_get_L(); auto top = lua_gettop(L); // store stack _Result result; int carg = 0, narg = 0; if (!luax_assume_func(L, func)) { cocos2d::log("luax_vcall failed, function:%s not exist!", func); goto err_exit; } luax_vpusharg(L, carg, narg, args...); if (carg != narg) { cocos2d::log("luax_vcall failed, argument exception:carg:%d,narg:%d", carg, narg); goto err_exit; } if (lua_pcall(L, narg, 1, 0) != 0) { cocos2d::log("luax_vcall failed, lua_pcall failed"); goto err_exit; } result = luax_getretval<_Result>(L); lua_settop(L, top); // resume stack return std::move(result); err_exit: lua_settop(L, top); // resume stack return _Result(); } template<typename..._Args> inline int luax_pvicall(const char* func, const _Args&...args) { return luax_pvxcall<int>(func, args...); } template<typename..._Args> inline float luax_pvfcall(const char* func, const _Args&...args) { return luax_pvxcall<float>(func, args...); } template<typename..._Args> inline double luax_pvdcall(const char* func, const _Args&...args) { return luax_pvxcall<double>(func, args...); } template<typename..._Args> inline std::string luax_pvvcall(const char* func, const _Args&...args) { return luax_pvxcall<std::string>(func, args...); } #endif /* powerful lua call, vardic template. */