• C++调用lua函数的一种通用办法 【转载】


    在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

  • 相关阅读:
    [原创] 毕设---在myeclipes中安装Hadoop开发插件
    [转]Linux下RPM软件包的安装及卸载 yum操作
    [转]结构化、半结构化和非结构化数据
    [转]这5种必知的大数据处理框架技术
    [转]浅谈Hive vs. HBase 区别在哪里
    前端资源整理
    每个程序员都应该知道的10大基础算法
    Python Day14(HTML)
    Python Day13(yaml)
    Python Day12(补充)
  • 原文地址:https://www.cnblogs.com/fanqs/p/lua.html
Copyright © 2020-2023  润新知