使用 C++ 语言调用 Lua 函数。






4.84/5 (15投票s)
使用 C++ 语言调用 Lua 函数。
目标读者
本文面向希望使用 Lua 编程语言扩展应用程序的 C++ 开发者。
引言
在 C++ 应用程序中使用 Lua 时,最常见的任务之一是调用 Lua 函数,但这可能很繁琐。您需要使用 Lua C API 的许多函数(lua_getglobal、lua_pushnumber、lua_pushstring、lua_tointeger 等)才能调用一个简单的 Lua 函数。在这里,我将展示可以简化您操作的 C++ 模板。
接口
接口非常简单,请看:假设您有这四个 Lua 函数,并且希望在您的应用程序中调用它们
列表 1 – Lua 函数 – test.lua
--------------------------------------------------------------------------------------
var = 10;
function sum4(a, b, c, d)
return a+b+c+d;
end
function catenate(a, b)
return a.." and "..b;
end
function incVar(value)
var = var+value;
end
function getVar()
return var;
end
--------------------------------------------------------------------------------------
那么,要调用这些函数,您需要使用
-
LuaCall 模板类。
基本方法是使用 Lua 函数接收和返回的类型来实例化 LuaCall,例如
float a = LuaCall<float, int, float, int, int>(L, "sum4").call(5, 1.5, 5, 5);
请参阅下面的完整示例(列表 2)。
列表 2 – 使用 LuaCall – main.cpp
--------------------------------------------------------------------------------------
#include <iostream>#include "LuaCall.h"
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
int main()
{
try
{
lua_State *L;
L = luaL_newstate();
if(luaL_loadfile(L, "list1.lua") || lua_pcall(L, 0, 0, 0))
{
throw std::string(std::string(lua_tostring(L, -1)));
}
std::cout << LuaCall<float, int, float, int, int>(L, "sum4").call(5, 1.5, 5, 5) << std::endl;
std::cout << LuaCall<std::string, std::string, std::string>(L, "catenate").call("Renato", "Bianca") << std::endl;
LuaCall<NullT, int>(L, "incVar").call(10);
std::cout << LuaCall<int>(L, "getVar").call() << std::endl;
if(L != NULL)
{
lua_close(L);
}
}
catch (const std::string &e)
{
std::cout << e << std::endl;
}
return 0;
}
Implementation
This is the implementation of LuaCall:
Listing 3 –LuaCall imp – LuaCall.h
--------------------------------------------------------------------------------------
template <typename T1,
typename T2
>
class Duo
{
};
// type that represents unused type parameters
class NullT
{
};
class LuaCallBase
{
public:
LuaCallBase(lua_State *luaState, const std::string& functionName)
{
L = luaState;
lua_getglobal(L, functionName.c_str());
}
protected:
void push(const int &value)
{
lua_pushinteger(L, value);
}
void push(const float &value)
{
lua_pushnumber(L, value);
}
void push(const double &value)
{
lua_pushnumber(L, value);
}
void push(const std::string &value)
{
lua_pushstring(L, value.c_str());
}
void get(int &value) const
{
value = lua_tointeger(L, -1);
}
void get(float &value) const
{
value = lua_tonumber(L, -1);
}
void get(double &value) const
{
value = lua_tonumber(L, -1);
}
void get(std::string &value) const
{
value = (char*)lua_tostring(L, -1);
}
void get(NullT &value) const
{
}
protected:
lua_State *L;
};
template <
typename TR,
typename T1 = NullT,
typename T2 = NullT,
typename T3 = NullT,
typename T4 = NullT
>
class LuaCall
: public Duo<TR, typename LuaCall<T1,T2,T3,T4,NullT> >
, public LuaCallBase
{
public:
LuaCall(lua_State *L, const std::string& functionName)
: LuaCallBase(L, functionName)
{
}
TR call(T1 a1, T2 a2, T3 a3, T4 a4)
{
TR returnValue;
push(a1);
push(a2);
push(a3);
push(a4);
if(lua_pcall(L, 4, 1, 0) != 0)
{
throw std::string(std::string(lua_tostring(L, -1)));
}
get(returnValue);
return returnValue;
}
};
template <
typename TR,
typename T1,
typename T2,
typename T3
>
class LuaCall<TR,T1,T2,T3,NullT>
: public Duo<TR,T1>
, public LuaCallBase
{
public:
LuaCall(lua_State *L, const std::string& functionName)
: LuaCallBase(L, functionName)
{
}
TR call(T1 a1, T2 a2, T3 a3)
{
TR returnValue;
push(a1);
push(a2);
push(a3);
if(lua_pcall(L, 3, 1, 0) != 0)
{
throw std::string(std::string(lua_tostring(L, -1)));
}
get(returnValue);
return returnValue;
}
};
template <
typename TR,
typename T1,
typename T2
>
class LuaCall<TR,T1,T2,NullT,NullT>
: public Duo<TR,T1>
, public LuaCallBase
{
public:
LuaCall(lua_State *L, const std::string& functionName)
: LuaCallBase(L, functionName)
{
}
TR call(T1 a1, T2 a2)
{
TR returnValue;
push(a1);
push(a2);
if(lua_pcall(L, 2, 1, 0) != 0)
{
throw std::string(std::string(lua_tostring(L, -1)));
}
get(returnValue);
return returnValue;
}
};
template <
typename TR,
typename T1
>
class LuaCall<TR,T1,NullT,NullT,NullT>
: public Duo<TR,T1>
, public LuaCallBase
{
public:
LuaCall(lua_State *L, const std::string& functionName)
: LuaCallBase(L, functionName)
{
}
TR call(T1 a1)
{
TR returnValue;
push(a1);
if(lua_pcall(L, 1, 1, 0) != 0)
{
throw std::string(std::string(lua_tostring(L, -1)));
}
get(returnValue);
return returnValue;
}
};
template <typename TR>
class LuaCall<TR,NullT,NullT,NullT,NullT>
: public Duo<TR,NullT>
, public LuaCallBase
{
public:
LuaCall(lua_State *L, const std::string& functionName)
: LuaCallBase(L, functionName)
{
}
TR call(void)
{
TR returnValue;
if(lua_pcall(L, 0, 1, 0) != 0)
{
throw std::string(std::string(lua_tostring(L, -1)));
}
get(returnValue);
return returnValue;
}
};
template <>
class LuaCall<NullT,NullT,NullT,NullT,NullT>
: public LuaCallBase
{
public:
LuaCall(lua_State *L, const std::string& functionName)
: LuaCallBase(L, functionName)
{
}
void call(void)
{
if(lua_pcall(L, 0, 0, 0) != 0)
{
throw std::string(std::string(lua_tostring(L, -1)));
}
}
};