在C++中调用lua函数的一般方式如下:
1 void callfunc1(lua_State* L, int arg1, const string& arg2)//调用脚本中的func1函数,参数为一个number,一个string 2 { 3 lua_getglobal(L, "func1"); 4 lua_pushnumber(L, arg1); 5 lua_pushstring(L, arg2.c_str()); 6 lua_pcall(L, 2, LUA_MULTRET, 0); 7 } 8 void callfunc2(lua_State* L, int arg1, int arg2)//调用脚本中的func2函数,参数为两个number 9 { 10 lua_getglobal(L, "func2"); 11 lua_pushnumber(L, arg1); 12 lua_pushnumber(L, arg2); 13 lua_pcall(L, 2, LUA_MULTRET, 0); 14 }
如果有很多个脚本函数需要调用,按上面的方式就要写很多个与之对应的C++函数,当然也可以利用C++的重载,把函数名作为参数,每种参数组合实现一个重载函数,则上面的代码可以改为:
1 void common_call(lua_State* L, const char* funname, int arg1, const string& arg2) 2 { 3 lua_getglobal(L, funname); 4 lua_pushnumber(L, arg1); 5 lua_pushstring(L, arg2.c_str()); 6 lua_pcall(L, 2, LUA_MULTRET, 0); 7 } 8 void common_call(lua_State* L, const char* funname, int arg1, int arg2) 9 { 10 //... 11 }
如果有两个不同的lua函数,它们的参数是一样的,则可以共用同一个common_call,但是不同的参数组合就必须有一个与之对应的 common_call,实现起来还是很麻烦,重复代码仍然很多。《Programming in Lua》上提供了一种通用的办法,用变长参数实现的,见http://www.lua.org/pil/25.3.html 但是仍然觉得不是太好,那个描述字符串很难看!一番思考后折腾出了下面这个方法:
对于不同类型的参数,唯一不同的就是压栈时的API不一样,数字使用lua_pushnumber,bool型是用lua_pushbool,字符 串是用lua_pushstring等,所以抽象出一个参数基类来,提供一个虚拟的pushvalue接口,然后各种实际类型实现自己的 pushvalue就可以了,代码如下:
1 #define my_lua_dofile(L, filename) ( luaL_loadfile((L), (filename)) || lua_pcall((L), 0, LUA_MULTRET, 0) ) 2 class TArg 3 { 4 public: 5 TArg(){} 6 virtual void pushvalue(lua_State* L)const = 0; 7 }; 8 class TArgInt:public TArg 9 { 10 int _intv; 11 public: 12 explicit TArgInt(int v):_intv(v){} 13 virtual void pushvalue(lua_State* L) const {lua_pushinteger(L, _intv);} 14 }; 15 class TArgStr:public TArg 16 { 17 string _strv; 18 public: 19 explicit TArgStr(const string& v):_strv(v){} 20 virtual void pushvalue(lua_State* L) const {lua_pushstring(L, _strv.c_str());} 21 }; 22 class TArgBool:public TArg 23 { 24 bool _boolv; 25 public: 26 explicit TArgBool(bool v):_boolv(v){} 27 virtual void pushvalue(lua_State* L) const {lua_pushboolean(L, _boolv);} 28 }; 29 int call(lua_State* L, const char* fname, const vector<TArg*>& arglist) 30 { 31 lua_getglobal(L, fname); 32 if (lua_isfunction(L, -1) ) 33 { 34 for (size_t i = 0; i < arglist.size(); i++) 35 { 36 arglist[i]->pushvalue(L); 37 } 38 } 39 return 0; 40 } 41 int main() 42 { 43 lua_State* L = luaL_newstate(); 44 luaL_openlibs(L); 45 my_lua_dofile(L, "luacall.lua"); //luacall.lua中有一个test函数 46 47 TArgInt ai(3); 48 TArgStr as("abc"); 49 TArgBool ab(true); 50 vector<TArg*> list; 51 list.push_back(&ai); 52 list.push_back(&as); 53 list.push_back(&ab); 54 call(L, "test", list); //调用test函数,参数为 3, "abc", true 55 return 0; 56 }
看起来问题已经解决了,但是仍然不够彻底,用户需要自己去构造一个TArg*的vector,对于每一种参数类型,用户需要知道它对于的基类是什么,下面把参数做进一步的封装:
1 class TArgPool 2 { 3 std::vector<TArg*> ArgList; 4 public: 5 TArgPool(){} 6 void AddArg(double Value); 7 void AddArg(const std::string& Str); 8 void AddArg(bool Value); 9 int Push(lua_State* L)const; 10 ~TArgPool(); 11 };
1 void TArgPool::AddArg(int Value) 2 { 3 TArgInt* pObj = new TArgInt(Value); 4 ArgList.push_back(pObj); 5 } 6 void TArgPool::AddArg(const std::string& Str) 7 { 8 TArgStr* pObj = new TArgStr(Str); 9 ArgList.push_back(pObj); 10 } 11 void TArgPool::AddArg(bool Value) 12 { 13 TArgBool* pObj = new TArgBool(Value); 14 ArgList.push_back(pObj); 15 } 16 int TArgPool::Push(lua_State* L)const 17 { 18 for (size_t i = 0; i < ArgList.size(); i++) 19 { 20 ArgList[i]->pushvalue(L); 21 } 22 return ArgList.size(); 23 } 24 TArgPool::~TArgPool() 25 { 26 for (size_t i = 0; i < ArgList.size(); i++) 27 { 28 delete ArgList[i]; 29 } 30 ArgList.clear(); 31 } 32 int CallLua(lua_State* L, const char* fname, const TArgPool& ArgPoolObj) 33 { 34 lua_getglobal(L, fname); 35 if (lua_isfunction(L, -1) ) 36 { 37 if ( 0 == lua_pcall(L, ArgPoolObj.Push(L), LUA_MULTRET, 0) ) 38 return 0; 39 fprintf(stderr, "%s:%d call function failed:%s/n", __FILE__, __LINE__, luaL_checkstring(L, -1)); 40 } 41 return -1; 42 }
然后用户需要调用lua函数的时候只需要构造一个TArgPool对象就行了:
1 ... 2 TArgPool ArgPoolObj; 3 ArgPoolObj.AddArg(socket_fd); 4 ArgPoolObj.AddArg(std::string(dataptr, length)); 5 CallLua(LState, read_ref, ArgPoolObj); 6 ...
本文转载自:http://blog.csdn.net/nightfallrove/article/details/5729636