使用C++调用 LUA 函数收藏
新一篇: 在你的游戏中应用LUA | 旧一篇: 使用模板快速排序
<script>function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</script>- You are signed up for one or more newsletters but your email address is either unconfirmed, or has not been reconfirmed in a long time. Please click here to have an email sent that will allow us to confirm your email address and start sending you newsletters again.
Audience
This article was written for C++ developers that want extend your application with Lua programming Language.
Introduction
One of the most common tasks when you use Lua in C++ application is call Lua functions, but this can be tiresome, you need use a lot of functions of LUA C API (lua_getglobal, lua_pushnumber, lua_pushstring, lua_tointeger and so on) to call one simple Lua function. Here I will show C++ templates that can make your life easy.
Interface
The interface is very easy see:. Think that you have these four Lua function and you want to call in your application:
Listing 1 – Lua Functions – 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
--------------------------------------------------------------------------------------
Then what you need to call these function is use:
-
LuaCall template class.
The basic way are you instantiate LuaCall with types of your Lua function receive and return, for sample:
float a = LuaCall<float, int, float, int, int>(L, "sum4").call(5, 1.5, 5, 5);
See complete sample below (listing 2).
Listing 2 – using 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)));
}
}
};