C++与Lua交互 使用模板特化封装

发布于 2021-10-18 07:23

当前 Lua 的版本已经是 Lua 5.4.3 了。创建工程使用的 Lua 版本是:Lua 5.1.5。

版本比较老,原因比较复杂,因为后续文章使用的 tolua++ 和 luaJIT 对 lua 的支持都停留在 5.1 的版本。

但是不用担心,在此文章使用了一些比较新而且好用的函数,并且将这些函数手动移植到了 Lua 5.1.5 。

VS 2017 中搭建 Lua 5.1

创建静态链接库的空工程、添加lua代码文件。

修改工程配置:

lua_project_lua_setting

lua_project_lua_setting

编译工程,生成 lua.lib。

C++ 对原生 Lua 的处理

在封装代码之前,我们先简单的从原生的代码开始。先对 Lua 有个简单的理解。

hello.lua

str = "I am so cool"  tbl = {name = "shun", id = 20114442}  function add(a,b)      return a + b + math.pi end

main.cpp

extern "C"{#include "lua.h"  #include "lualib.h"  #include "lauxlib.h"  }// 下面的代码 是处理 原生的 lua脚本的using namespace std;void main(){    //1.创建Lua状态      lua_State *L = luaL_newstate();    if (L == NULL)    {        return;    }    //2.加载Lua文件      int bRet = luaL_loadfile(L, "E:\\hello.lua");    if (bRet)    {        cout << "load file error" << endl;        return;    }    //3.运行Lua文件      bRet = lua_pcall(L, 0, 0, 0);    if (bRet)    {        cout << "pcall error" << endl;        return;    }    //4.读取变量      lua_getglobal(L, "str");    string str = lua_tostring(L, -1);    cout << "str = " << str.c_str() << endl;        //str = I am so cool~      //5.读取table      lua_getglobal(L, "tbl");    lua_getfield(L, -1, "name");    str = lua_tostring(L, -1);    cout << "tbl:name = " << str.c_str() << endl; //tbl:name = shun      //6.读取函数      lua_getglobal(L, "add");        // 获取函数,压入栈中      lua_pushnumber(L, 10);          // 压入第一个参数      lua_pushnumber(L, 20);          // 压入第二个参数      int iRet = lua_pcall(L, 2, 1, 0);// 调用函数,调用完成以后,会将返回值压入栈中,2表示参数个数,1表示返回结果个数。    if (iRet)                       // 调用出错      {        const char *pErrorMsg = lua_tostring(L, -1);        cout << pErrorMsg << endl;        lua_close(L);        return;    }    if (lua_isnumber(L, -1))        //取值输出      {        double fValue = lua_tonumber(L, -1);        cout << "Result is " << fValue << endl;    }    system("pause");    //至此,栈中的情况是:    //=================== 栈顶 ===================       //  索引  类型      值      //   4   int:30       //   3   string:shun       //   2   table:     tbl      //   1   string:    I am so cool~      //=================== 栈底 ===================       //7.关闭state      lua_close(L);    return;}

使用 C++ 模板封装 Lua

配置 Lua 环境、植入新版本的 Lua 库函数

将 Lua 的头文件和编译的库文件,添加到工程文件中。

我们需要植入一些先版本的 Lua 库函数。因为它们比较好用~ 可以更方便的让 C++ 和 Lua 的相互交互。

创建一个 LuaEx.hpp 文件,包含头文件,并植入函数:

/***************************************************************************************************************************************************        vic.MINg        2021/10/11        lua 函数扩展,由于使用 lua 版本 5.1.5,一些比较有用的函数 没有,这里将这些函数 扩展到这里,也可以了解 lua 的实现**************************************************************************************************************************************************/#pragma onceextern "C"{#include "lua.h"  #include "lualib.h"  #include "lauxlib.h"  #include "lstate.h"}#define LUAI_UACINT        LUA_INTEGERinline const char *luaL_tolstring(lua_State *L, int idx, size_t *len) {    if (luaL_callmeta(L, idx, "__tostring")) {  /* metafield? */        if (!lua_isstring(L, -1))            luaL_error(L, "'__tostring' must return a string");    }    else {        switch (lua_type(L, idx)) {        case LUA_TNUMBER: {            // if (lua_isinteger(L, idx))            //    lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx));            // else            lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx));            break;        }        case LUA_TSTRING:            lua_pushvalue(L, idx);            break;        case LUA_TBOOLEAN:            lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false"));            break;        case LUA_TNIL:            lua_pushliteral(L, "nil");            break;        default: {            int tt = luaL_getmetafield(L, idx, "__name");  /* try name */            const char *kind = (tt == LUA_TSTRING) ? lua_tostring(L, -1) :                luaL_typename(L, idx);            lua_pushfstring(L, "%s: %p", kind, lua_topointer(L, idx));            if (tt != LUA_TNIL)                lua_remove(L, -2);  /* remove '__name' */            break;        }        }    }    return lua_tolstring(L, -1, len);}inline void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup){    luaL_checkstack(L, nup, "too many upvalues");    for (; l->name != NULL; l++) {  /* fill the table with given functions */        int i;        for (i = 0; i < nup; i++)  /* copy upvalues to the top */            lua_pushvalue(L, -nup);        lua_pushcclosure(L, l->func, nup);  /* closure with those upvalues */        lua_setfield(L, -(nup + 2), l->name);    }    lua_pop(L, nup);  /* remove upvalues */}#define lua_newtable(L)        lua_createtable(L, 0, 0)#define luaL_newlibtable(L,l)    \  lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)#define luaL_newlib(L,l)  \  (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))#define ispseudo(i)        ((i) <= LUA_REGISTRYINDEX)#ifndef cast#define cast(t, exp)    ((t)(exp))#endif#define cast_int(i)    cast(int, (i))#define LUA_LOADED_TABLE    "_LOADED"struct lua_State;inline int lua_absindex(lua_State *L, int idx) {    return (idx > 0 || ispseudo(idx))        ? idx        : cast_int(L->top - L->ci->func) + idx;}inline int luaL_getsubtable(lua_State *L, int idx, const char *fname){        lua_getfield(L, idx, fname);        lua_pop(L, 1);  /* remove previous result */        idx = lua_absindex(L, idx);        lua_newtable(L);        lua_pushvalue(L, -1);  /* copy to be left at top */        lua_setfield(L, idx, fname);  /* assign new table to field */        return 0;  /* false, because did not find table there */}inline void luaL_requiref(lua_State *L, const char *modname,    lua_CFunction openf, int glb) {    luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);    lua_getfield(L, -1, modname);  /* LOADED[modname] */    if (!lua_toboolean(L, -1)) {  /* package not already loaded? */        lua_pop(L, 1);  /* remove field */        lua_pushcfunction(L, openf);        lua_pushstring(L, modname);  /* argument to open function */        lua_call(L, 1, 1);  /* call 'openf' to open module */        lua_pushvalue(L, -1);  /* make copy of module (call result) */        lua_setfield(L, -3, modname);  /* LOADED[modname] = module */    }    lua_remove(L, -2);  /* remove LOADED table */    if (glb) {        lua_pushvalue(L, -1);  /* copy of module */        lua_setglobal(L, modname);  /* _G[modname] = module */    }}

模板封装,C++ 调用 Lua 函数

通过封装实现,C++ 调用 Lua 函数。存在 无返回值、一个返回值、多个返回值情况。

LuaHelp.h,面向过程 模板封装。

/*************************************************        vic.MINg        2021/10/11        使用 模板  lua 的封装************************************************/#pragma once#include <iostream>#include <stdexcept>#include <vector>#include "LuaEx.hpp"// 面向过程 封装namespace LuaHelp {    union LH_LuaData {        bool            lh_bool_data;        int            lh_int_data;        double        lh_number_data;        char*        lh_string_data;    };    enum LH_LuaType {        LH_Lua_Bool = 0,        LH_Lua_Int,        LH_Lua_Number,        LH_Lua_String    };    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////    // 全局变量 设置    inline bool GetGlobal(lua_State* lua_s, const char* g_name)    {        //if (lua_gettop(lua_s) < 1)    //        return false;        lua_getglobal(lua_s, g_name);        return true;    }    inline bool SetGlobal(lua_State* lua_s, const char* g_name)    {        if (lua_gettop(lua_s) < 1)            return false;        lua_setglobal(lua_s, g_name);        return true;    }    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////    // 打印 堆 信息    inline void PrintStack_Info(lua_State* lua_s,const char* tag = NULL)    {        int lua_size = lua_gettop(lua_s);        if (tag)            std::cout << "***************************** " << tag << " *****************************" << std::endl;        printf("lua_State:0x%x ! \n", lua_s);        printf("lua_Size:%d ! \n", lua_size);        for (int i = 1; i <= lua_size; i++)        {            printf("[%d](%s):%s\n", i, luaL_typename(lua_s, i), luaL_tolstring(lua_s, i, NULL));            lua_pop(lua_s, 1);        }    }    inline void PrintStack_Size(lua_State* lua_s, const char* tag = NULL)    {        int lua_size = lua_gettop(lua_s);        if (tag)            std::cout << "***************************** " << tag << " *****************************" << std::endl;        std::cout <<  "lua_Size:" << lua_size << std::endl;    }    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////    // 特化 LuaCheck    template<typename _Ty>    bool LuaCheck(lua_State* lua_s, int index = -1);    /// 检查是否是字符串    template<> inline    bool LuaCheck<char*>(lua_State* lua_s, int index)    {        return lua_isstring(lua_s, index) == 0 ? false : true;    }    template<> inline    bool LuaCheck<std::string>(lua_State* lua_s, int index)    {        return lua_isstring(lua_s, index) == 0 ? false : true;    }    /// 检查是否是整数    template<> inline    bool LuaCheck<int>(lua_State* lua_s, int index)    {        return lua_isnumber(lua_s, index) == 0 ? false : true;    }    /// 检查是否是浮点数    template<>    inline bool LuaCheck<double>(lua_State* lua_s, int index)    {        return lua_isnumber(lua_s, index) == 0 ? false : true;    }    template<>    inline bool LuaCheck<float>(lua_State* lua_s, int index)    {        return lua_isnumber(lua_s, index) == 0 ? false : true;    }    /// 检查是否是布尔值    template<>    inline bool LuaCheck<bool>(lua_State* lua_s, int index)    {        return lua_isboolean(lua_s, index) == 0 ? false : true;    }    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////    // 特化 LuaGet    template<typename _Ty>    _Ty LuaGet(lua_State* lua_s, int index = -1, bool _pop = false);            // _pop 表示 是否弹出    /// 获取字符串    template<> inline    char* LuaGet<char*>(lua_State* lua_s, int index, bool _pop)    {        if (!LuaCheck<char*>(lua_s, index))        {            throw std::logic_error("LuaHelp::LuaCheck<char*> Error!");        }        char* tmp = (char*)lua_tostring(lua_s, index);        if (_pop)        {            lua_remove(lua_s, index);        }        return tmp;    }    template<> inline std::string LuaGet<std::string>(lua_State*lua_s, int index, bool _pop)    {        if (!LuaCheck<char*>(lua_s, index))        {            throw std::logic_error("LuaHelp::LuaCheck<std::string> Error!");        }        std::string tmpstr = (char*)lua_tostring(lua_s, index);        if (_pop)        {            lua_remove(lua_s, index);        }        return std::move(tmpstr);    }    /// 获取整型    template<> inline int LuaGet<int>(lua_State* lua_s, int index, bool _pop)    {        if (!LuaCheck<int>(lua_s, index))        {            throw std::logic_error("LuaHelp::LuaCheck<int> Error!");        }        int  tmp = lua_tointeger(lua_s, index);        if (_pop)        {            lua_remove(lua_s, index);        }        return  tmp;    }    /// 获取浮点数    template<> inline double LuaGet<double>(lua_State* lua_s, int index, bool _pop)    {        if (!LuaCheck<double>(lua_s, index))        {            throw std::logic_error("LuaHelp::LuaCheck<double> Error!");        }        double  tmp = lua_tonumber(lua_s, index);        if (_pop)        {            lua_remove(lua_s, index);        }        return  tmp;    }    template<> inline float LuaGet<float>(lua_State*lua_s, int index, bool _pop)    {        if (!LuaCheck<float>(lua_s, index))        {            throw std::logic_error("LuaHelp::LuaCheck<float> Error!");        }        float  tmp = (float)lua_tonumber(lua_s, index);        if (_pop)        {            lua_remove(lua_s, index);        }        return  tmp;    }    /// 获取布尔值    template<> inline bool LuaGet<bool>(lua_State*lua_s, int index, bool _pop)    {        if (!LuaCheck<bool>(lua_s, index))        {            throw std::logic_error("LuaHelp::LuaCheck<bool> Error!");        }        bool  tmp = (bool)lua_toboolean(lua_s, index);        if (_pop)        {            lua_remove(lua_s, index);        }        return  tmp;    }    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////    // 特化 LuaPush    template<typename _TY>    void LuaPush(lua_State* lua_s, _TY);    /// 压栈字符串    template<> inline void LuaPush<char*>(lua_State* lua_s, char* value)    {        lua_pushstring(lua_s, value);    }    template<> inline void LuaPush<const char*>(lua_State* lua_s, const char* value)    {        lua_pushstring(lua_s, value);    }    /// 压栈整型    template<> inline void LuaPush<int>(lua_State* lua_s, int value)    {        lua_pushnumber(lua_s, value);    }    /// 压栈浮点数    template<> inline void LuaPush<double>(lua_State* lua_s, double value)    {        lua_pushnumber(lua_s, value);    }    template<> inline void LuaPush<float>(lua_State* lua_s, float value)    {        lua_pushnumber(lua_s, value);    }    /// 压栈布尔值    template<> inline void LuaPush<bool>(lua_State* lua_s, bool value)    {        lua_pushboolean(lua_s, value);    }    /// 压栈函数    template<> inline void LuaPush<lua_CFunction>(lua_State*lua_g, lua_CFunction fun)    {        lua_pushcfunction(lua_g, fun);    }    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////    // 特化 全局变量    /// 特化 获取全局变量    template<typename _Ty>    _Ty LuaGetGlobal(lua_State* lua_s, char*global, bool _pop = true)    {        if (GetGlobal(lua_s, global) == false)        {            throw std::logic_error("LuaHelp::LuaGetGlobal Error!");        }        _Ty tmp = LuaGet<_Ty>(lua_s, -1, _pop);        return tmp;    }    /// 特化 设置全局变量    template<typename _Ty>    bool LuaSetGlobal(lua_State* lua_s, char* global, _Ty value)    {        LuaPush<_Ty>(lua_s, value);        if (SetGlobal(lua_s, global) == false)        {            throw std::logic_error("LuaHelp::LuaSetGlobal Error!");            return false;        }        return true;    }    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////    // 调用 lua 函数模板    // __CallLua  压栈 无参数     inline void __CallLua(lua_State* lua_g, int& argSize) {    }        template<typename _FirstArg, typename... _Args>    void __CallLua(lua_State* lua_g, int& argSize, _FirstArg arg1, _Args...args)    //压入参数    {        argSize++;        LuaPush<_FirstArg>(lua_g, arg1);        __CallLua(lua_g, argSize, args...);                    // 递归 压栈调用    }    template<typename _Ret, typename... _Args>    _Ret  CallLuaFuction_return_oneValue(lua_State* lua_g, const char* FunctionName, _Args...args)            // 调用lua函数, 一个返回值    {        if (GetGlobal(lua_g, FunctionName))        {            int argSize = 0;                                // 参数个数            __CallLua(lua_g, argSize, args...);            PrintStack_Info(lua_g, "CallLuaFuction_return_oneValue");            if (lua_pcall(lua_g, argSize, 1, 0) != 0)            {                lua_pop(lua_g, 1);                        // 弹出错误值                 throw std::logic_error("LuaHelp::CallLuaFuction_return_oneValue Error!");            }            _Ret value = LuaGet<_Ret>(lua_g);            lua_pop(lua_g, 1);            return value;        }        throw std::logic_error("LuaHelp::CallLuaFuction_return_oneValue No Function!");    }    template< typename... _Args>    void CallLuaFuction_return_void(lua_State* lua_g,const char* FunctionName, _Args...args)    {        if (GetGlobal(lua_g, FunctionName))        {            int argSize = 0;                                // 参数个数            __CallLua(lua_g, argSize, args...);            PrintStack_Info(lua_g, "CallLuaFuction_return_void");            if (lua_pcall(lua_g, sizeof...(args), 0, 0) != 0)            {                lua_pop(lua_g, 1);                        // 弹出错误值                 throw std::logic_error("LuaHelp::CallLuaFuction_return_void Error!");            }            return;        }        throw std::logic_error("LuaHelp::CallLuaFuction_return_void No Function!");    }    template< typename... _Args>    void CallLuaFuction_return_multValues(lua_State* lua_g, const char* FunctionName, _Args...args)    {        if (GetGlobal(lua_g, FunctionName))        {            int argSize = 0;                                // 参数个数            __CallLua(lua_g, argSize, args...);            PrintStack_Info(lua_g, "CallLuaFuction_return_multValues");            if (lua_pcall(lua_g, sizeof...(args), -1, 0) != 0)            {                lua_pop(lua_g, 1);                        //弹出错误值                 throw std::logic_error("LuaHelp::CallLuaFuction_return_multValues Error!");            }            return;        }        throw std::logic_error("LuaHelp::CallLuaFuction_return_multValues No Function!");    }    template< typename... _Args>    std::vector<LH_LuaData> GetResult(lua_State* lua_g, _Args...args)    {        int _argsize = sizeof...(args);        int argarray[sizeof...(args)] = { args... };        std::cout << _argsize << std::endl;        std::vector<LH_LuaData> __array = {};        int __index = -_argsize + 1;        for (int v : argarray)        {            LH_LuaData tmp = { 0 };            std::cout << "v:" << v << std::endl;            switch (v)            {            case  LH_LuaType::LH_Lua_Bool:                tmp.lh_bool_data = LuaGet<bool>(lua_g, -1 + __index);                break;            case  LH_LuaType::LH_Lua_Int:                tmp.lh_int_data = LuaGet<int>(lua_g, -1 + __index);                __array.push_back(tmp);                break;            case  LH_LuaType::LH_Lua_Number:                tmp.lh_number_data = LuaGet<double>(lua_g, -1 + __index);                __array.push_back(tmp);                break;            case  LH_LuaType::LH_Lua_String:                tmp.lh_string_data = LuaGet<char*>(lua_g, -1 + __index);                __array.push_back(tmp);                break;            default:                throw std::logic_error("LuaHelp::GetResult LH_LuaType Error!");                break;            }            __index++;        }        lua_pop(lua_g, _argsize);        return __array;    }};

LuaScript.h,面向对象 模板封装。

/*************************************************        vic.MINg        2021/10/11        使用 模板  lua 的封装************************************************/#pragma once#include <iostream>#include <stdexcept>#include <vector>#include "LuaHelper.h"// 面向对象 封装class LuaScript{public:    LuaScript():m_lua(NULL) {}    ~LuaScript() {        if (m_lua)        lua_close(m_lua);    }    bool CreateLuaState()    {        if (m_lua)        return true;        m_lua = luaL_newstate();        if (m_lua == NULL)            return false;        luaL_openlibs(m_lua);        return true;    }    void PrintStack_Info(const char* tag = NULL)    {        LuaHelp::PrintStack_Info(m_lua, tag);    }    void PrintStack_Size(const char* tag = NULL)    {        LuaHelp::PrintStack_Size(m_lua, tag);    }    bool DoFile(const char* file_name) {        if (file_name == NULL)        return false;        if (luaL_dofile(m_lua, file_name) != 0)        {            char* error_string = (char*)lua_tostring(m_lua, -1);            throw std::logic_error(error_string);            lua_pop(m_lua, 1);            return false;        }        return true;    }    bool DoString(char* lua_string) {        if (lua_string == NULL)        {            return false;        }        if (luaL_dostring(m_lua, lua_string) != 0)        {            char* error_string = (char*)lua_tostring(m_lua, -1);            throw std::logic_error(error_string);            lua_pop(m_lua, 1);            return false;        }        return  true;    }    inline bool GetGlobal(const char* name)     {         return LuaHelp::GetGlobal(m_lua, name);     }    inline bool SetGlobal(const char* name)    {         return LuaHelp::SetGlobal(m_lua, name);     }    inline lua_State* GetLuaState()    {        return m_lua;    }    template<typename _Ty>    inline bool LuaCheck(int index = -1)    {        return LuaHelp::LuaCheck<_Ty>(index);    }    template<typename _Ty>    inline _Ty LuaGet(int index = -1, bool _pop = false)    {        return LuaHelp::LuaGet<_Ty>(GetLuaState(), index, _pop);    }    template<typename _Type>    inline void LuaPush(_Type data)    {        LuaHelp::LuaPush<_Type>(GetLuaState(), data);    }    template<typename _Ty>    inline _Ty LuaGetGlobal(char*global, bool _pop = true)    {        return LuaHelp::LuaGetGlobal<_Ty>(GetLuaState(), global, _pop);    }    template<typename _Ty>    inline bool LuaSetGlobal(_Ty data, char*global)    {        return LuaHelp::LuaSetGlobal<_Ty>(m_lua, data, global);    }    template<typename _Ret, typename... _Args>    inline _Ret CallLuaFuction_return_oneValue(const char* FunctionName, _Args...args)    {        return LuaHelp::CallLuaFuction_return_oneValue<_Ret>(GetLuaState(), FunctionName, args...);    }    template< typename... _Args>    inline void CallLuaFuction_return_void(const char* FunctionName, _Args...args)    {        LuaHelp::CallLuaFuction_return_void(GetLuaState(), FunctionName, args...);    }    template< typename... _Args>    inline LuaScript& CallLuaFuction_return_multValues(const char* FunctionName, _Args...args)    {        LuaHelp::CallLuaFuction_return_multValues(GetLuaState(), FunctionName, args...);        return *this;    }    template< typename... _Args>    std::vector<LuaHelp::LH_LuaData> GetResult(_Args...args)    {        auto tmp = std::move(LuaHelp::GetResult(m_lua, args...));        return tmp;    }private:    lua_State * m_lua;};

函数封装, Lua 调用 C++ 函数

Lua 调用 C++ 函数时,C++注册函数的五种方法。

LuaRegFuncs.h

#pragma once#include "../include/LuaScript.h"#include "../include/LuaEx.hpp"class LuaRegFuncs : public LuaScript{public:    void RegFuncs();};

LuaRegFuncs.cpp

#include "LuaRegFuncs.h"#include <functional>int show_luaproject_info1(lua_State *L){    std::cout << __FUNCTION__ << std::endl;    printf("Show LuaProject C++ Info 1.\n");    return 0;}int show_luaproject_info2(lua_State *L){    std::cout << __FUNCTION__ << std::endl;    printf("Show LuaProject C++ Info 2.\n");    return 0;}int show_luaproject_openlib(lua_State *L){    std::cout << __FUNCTION__ << std::endl;    struct luaL_Reg regfuc[]{        { "show_luaproject_info1", show_luaproject_info1 },        { "show_luaproject_info2", show_luaproject_info2 },        { NULL,NULL }    };    luaL_newlib(L, regfuc);    return 1;}void LuaRegFuncs::RegFuncs(){    struct luaL_Reg regfuc[]{        { "show_luaproject_info1", show_luaproject_info1 },        { "show_luaproject_info2", show_luaproject_info2 },        { NULL,NULL }    };    std::function<void()>  lua_pushcfunction_RegFuncs = [&]()    {        lua_pushcfunction(GetLuaState(), &show_luaproject_info1);        SetGlobal("show_luaproject_info1");        lua_pushcfunction(GetLuaState(), &show_luaproject_info2);        SetGlobal("show_luaproject_info2");    };    std::function<void()>  luaL_newlib_RegFuncs = [&]()    {        luaL_newlib(GetLuaState(), regfuc);        SetGlobal("luaL_newlib_RegFuncs");    };    std::function<void()>  lua_newtable_luaL_setfuncs_RegFuncs = [&]()    {        lua_newtable(GetLuaState());                            luaL_setfuncs(GetLuaState(), regfuc, 0);        SetGlobal("lua_newtable_luaL_setfuncs_RegFuncs");    };    std::function<void()>  lua_table_reg_RegFuncs = [&]()    {        // 创建一个Table 压入键值对        lua_newtable(GetLuaState());        for (auto& v : regfuc)        {            if (v.func == NULL || v.name == NULL)            {                break;            }            LuaPush<const char*>(v.name);            LuaPush<lua_CFunction>(v.func);            lua_rawset(GetLuaState(), -3);        }        SetGlobal("lua_table_reg_RegFuncs");    };    std::function<void()>  luaL_requiref_RegFuncs = [&]()    {        luaL_requiref(GetLuaState(), "luaL_requiref_RegFuncs", show_luaproject_openlib, 1);        lua_pop(GetLuaState(), 1);    };    if (CreateLuaState())    {        lua_pushcfunction_RegFuncs();        luaL_newlib_RegFuncs();        lua_newtable_luaL_setfuncs_RegFuncs();        lua_table_reg_RegFuncs();        luaL_requiref_RegFuncs();    }}

类封装,Lua 调用 C++ 类

这里有个 Teacher 类,这里实现对该类的封装,看看如何 在 Lua 中调用 C++ 类。

Teacher.h

#pragma once#include <iostream>#include <string>class Teacher{public:    //构造/析构函数    Teacher();    ~Teacher();    //get/set函数    std::string get_name();    void set_name(std::string name);    unsigned get_age();    void set_age(unsigned age);    //打印函数    void print();private:    std::string _name;    unsigned _age;};

Teacher.cpp

#include "Teacher.h"Teacher::Teacher()    :_name("Empty"),    _age(0){    std::cout << "Teacher Constructor" << std::endl;}Teacher::~Teacher(){    std::cout << "Teacher Destructor" << std::endl;}std::string Teacher::get_name(){    return _name;}void Teacher::set_name(std::string name){    _name = name;}unsigned Teacher::get_age(){    return _age;}void Teacher::set_age(unsigned age){    _age = age;}void Teacher::print(){    std::cout << "name :" << _name << " age : " << _age << std::endl;}

编写对 Teacher 的封装代码:

TeacherRegFuncs.h

#pragma once#include "LuaEx.hpp"#include "Teacher.h"//------定义相关的全局函数------//创建对象int lua_create_new_teacher(lua_State* L);//get/set函数int lua_get_name(lua_State* L);int lua_set_name(lua_State* L);int lua_get_age(lua_State* L);int lua_set_age(lua_State* L);//打印函数int lua_print(lua_State* L);//转换为字符串函数int lua_teacher2string(lua_State* L);//自动GCint lua_auto_gc(lua_State* L);//------注册全局函数供Lua使用------//构造函数static const luaL_Reg lua_reg_teacher_constructor_funcs[] = {    { "create", lua_create_new_teacher },    { NULL, NULL }};//成员操作函数static const luaL_Reg lua_reg_teacher_member_funcs[] = {    { "get_name", lua_get_name },    { "set_name", lua_set_name },    { "get_age", lua_get_age },    { "set_age", lua_set_age },    { "print", lua_print },    { "__gc", lua_auto_gc }, //注册Lua内部函数__gc    { "__tostring", lua_teacher2string },    { NULL, NULL },c++};int luaopen_teacher_libs(lua_State* L);

TeacherRegFuncs.cpp

#include "TeacherRegFuncs.h"int lua_create_new_teacher(lua_State* L){    //创建一个对象指针放到stack里,返回给Lua中使用,userdata的位置-1    Teacher** t = (Teacher**)lua_newuserdata(L, sizeof(Teacher*));    *t = new Teacher();    //Lua->stack,得到全局元表位置-1,userdata位置-2    luaL_getmetatable(L, "TeacherClass");    //将元表赋值给位置-2的userdata,并弹出-1的元表    lua_setmetatable(L, -2);    return 1;}int lua_get_name(lua_State* L){    //得到第一个传入的对象参数(在stack最底部)    Teacher** t = (Teacher**)luaL_checkudata(L, 1, "TeacherClass");    luaL_argcheck(L, t != NULL, 1, "invalid user data");    //清空stack    lua_settop(L, 0);    //将数据放入stack中,供Lua使用    lua_pushstring(L, (*t)->get_name().c_str());    return 1;}int lua_set_name(lua_State* L){    //得到第一个传入的对象参数    Teacher** t = (Teacher**)luaL_checkudata(L, 1, "TeacherClass");    luaL_argcheck(L, t != NULL, 1, "invalid user data");    luaL_checktype(L, -1, LUA_TSTRING);    std::string name = lua_tostring(L, -1);    (*t)->set_name(name);    return 0;}int lua_get_age(lua_State* L){    Teacher** t = (Teacher**)luaL_checkudata(L, 1, "TeacherClass");    luaL_argcheck(L, t != NULL, 1, "invalid user data");    lua_pushinteger(L, (*t)->get_age());    return 1;}int lua_set_age(lua_State* L){    Teacher** t = (Teacher**)luaL_checkudata(L, 1, "TeacherClass");    luaL_argcheck(L, t != NULL, 1, "invalid user data");    luaL_checktype(L, -1, LUA_TNUMBER);    (*t)->set_age((unsigned)lua_tointeger(L, -1));    return 0;}int lua_print(lua_State* L){    Teacher** t = (Teacher**)luaL_checkudata(L, 1, "TeacherClass");    luaL_argcheck(L, t != NULL, 1, "invalid user data");    (*t)->print();    return 0;}int lua_teacher2string(lua_State* L){    Teacher** t = (Teacher**)luaL_checkudata(L, 1, "TeacherClass");    luaL_argcheck(L, t != NULL, 1, "invalid user data");    lua_pushfstring(L, "This is teacher name : %s age : %d !", (*t)->get_name().c_str(), (*t)->get_age());    return 1;}int lua_auto_gc(lua_State* L){    Teacher** t = (Teacher**)luaL_checkudata(L, 1, "TeacherClass");    luaL_argcheck(L, t != NULL, 1, "invalid user data");    if (t) {        delete *t;    }    return 0;}int luaopen_teacher_libs(lua_State* L){    //创建全局元表(里面包含了对LUA_REGISTRYINDEX的操作),元表的位置为-1    luaL_newmetatable(L, "TeacherClass");    //将元表作为一个副本压栈到位置-1,原元表位置-2    lua_pushvalue(L, -1);    //设置-2位置元表的__index索引的值为位置-1的元表,并弹出位置-1的元表,原元表的位置为-1    lua_setfield(L, -2, "__index");    //将成员函数注册到元表中(到这里,全局元表的设置就全部完成了)    luaL_setfuncs(L, lua_reg_teacher_member_funcs, 0);    //注册构造函数到新表中,并返回给Lua    luaL_newlib(L, lua_reg_teacher_constructor_funcs);    return 1;}

为了方便,我们把注册的代码添加到之前的 LuaRegFuncs 类中,相关代码如下:

#include "Teacher.h"#include "TeacherRegFuncs.h"...    static const luaL_Reg regclass[] = {        { "base", luaopen_base },                        // 系统模块        { "Teacher", luaopen_teacher_libs },    // 模块名字 Teacher,注册函数 luaopen_teacher_libs        { NULL, NULL }    };    ...    const luaL_Reg* lua_reg = regclass;    for (; lua_reg->func; ++lua_reg) {            luaL_requiref(GetLuaState(), lua_reg->name, lua_reg->func, 1);            lua_pop(GetLuaState(), 1);    }...

C++ 和 Lua 相互调用测试

我们完成了相关代码的封装,现在我们来做一些必要的测试:

先写一份 Lua 脚本,需求如下:

编写无返回值、一个返回值、多个返回值函数。编写函数,调用 C++ 中的函数和类。最终,我们会在 C++ 中调用 这些 Lua 函数。

luascript_test.lua

function show_luascript_test1(a,b)    print("Test1",a,b)    return a+bendfunction show_luascript_test2(A,B,C)    print("Test3 Lua",A,B,C)    return 111,"LUA",333.6endfunction teacher_print()    local teacher_obj = Teacher.create()    teacher_obj:set_name("Jack")    teacher_obj:print()--使用内部的__tostring函数进行打印    print(teacher_obj)--下面的代码也是可行的    --teacher_obj.set_name(teacher_obj,"Jack")    --teacher_obj.print(teacher_obj)--让其进行自动gc    teacher_obj = nil--手动强制gc    --collectgarbage("collect")end function reg_funcs()    print("-----------------lua_pushcfunction_RegFuncs-----------------")    show_luaproject_info1()    show_luaproject_info2()    print("-----------------luaL_newlib_RegFuncs-----------------")    luaL_newlib_RegFuncs.show_luaproject_info1()    luaL_newlib_RegFuncs.show_luaproject_info2()    print("-----------------lua_newtable_luaL_setfuncs_RegFuncs-----------------")    lua_newtable_luaL_setfuncs_RegFuncs.show_luaproject_info1()    lua_newtable_luaL_setfuncs_RegFuncs.show_luaproject_info2()    print("-----------------lua_table_reg_RegFuncs-----------------")    lua_table_reg_RegFuncs.show_luaproject_info1()    lua_table_reg_RegFuncs.show_luaproject_info2()    print("-----------------luaL_requiref_RegFuncs-----------------")    --local luaL_requiref_RegFuncs = require "luaL_requiref_RegFuncs"    luaL_requiref_RegFuncs.show_luaproject_info1()    luaL_requiref_RegFuncs.show_luaproject_info2()end

编写代码,加载 这个 Lua 文件,并且实现调用上面的 Lua 函数。

main.cpp

#include <stdio.h>#include <string>#include <assert.h>#include <iostream>#include "DirectoryManager.h"#include "LuaRegFuncs.h"int main(int argc, char** argv) {    LuaRegFuncs* lua_reg_funcs = new LuaRegFuncs();    lua_reg_funcs->RegFuncs();    std::string strLuaScript;#ifdef _WIN32    strLuaScript = DirectoryManager::GetExeDirectory() + "scripts/luascript_test.lua";#else    strLuaScript = "scripts/luascript_test.lua";#endif    //  加载一个lua脚本    if (!lua_reg_funcs->DoFile(strLuaScript.c_str()))    {        delete lua_reg_funcs;        return -1;    }    // 一返回值函数的调用    auto sum_ab = lua_reg_funcs->CallLuaFuction_return_oneValue<int>("show_luascript_test1", 1, 10);    std::cout << "show_luascript_test1 Result:" << sum_ab << std::endl;    // 无返回值函数的调用    // Lua 函数中,调用 C++ 函数的应用    lua_reg_funcs->CallLuaFuction_return_void("reg_funcs");    // 多返回值函数的调用    lua_reg_funcs->CallLuaFuction_return_multValues<int, const char*, float>("show_luascript_test2", 2, "vic.MINg", 3.14f);    auto arrResult = lua_reg_funcs->GetResult(LuaHelp::LH_LuaType::LH_Lua_Int, LuaHelp::LH_LuaType::LH_Lua_String, LuaHelp::LH_LuaType::LH_Lua_Number);    std::cout << "show_luascript_test2 Result:" << arrResult[0].lh_int_data << std::endl;    std::cout << "show_luascript_test2 Result:" << arrResult[1].lh_string_data << std::endl;    std::cout << "show_luascript_test2 Result:" << arrResult[2].lh_number_data << std::endl;    // Lua 函数中,调用 C++ 类的应用    lua_reg_funcs->CallLuaFuction_return_void("teacher_print");    system("pause");    delete lua_reg_funcs;    return 0;}

运行程序,看一下成果物:

test

本文来自网络或网友投稿,如有侵犯您的权益,请发邮件至:aisoutu@outlook.com 我们将第一时间删除。

相关素材