Calling Lua functions : using C++ language.






4.84/5 (15 votes)
Calling Lua functions : using C++ language.
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
--------------------------------------------------------------------------------------
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: The basic way are you instantiate LuaCall with types of your Lua function receive and return, for sample: Listing 2 – using LuaCall – main.cpp --------------------------------------------------------------------------------------
float a = LuaCall<float, int, float, int, int>(L, "sum4").call(5, 1.5, 5, 5);
See complete sample below (listing 2).
#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 --------------------------------------------------------------------------------------
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)));
}
}
};Bibliography
Roberto Ierusalimschy
Programming in Lua – 2nd ed. (http://www.inf.puc-rio.br/~roberto/pil2/)
ISBN 85-903798-2-5
David Vandevoorde - Nicolai M. Josuttis
C++ Templates - The Complete Guide
ISBN 0-201-73484-2Lua.org
http://www.lua.org/ Mailing list
http://www.lua.org/lua-l.html Community
http://www.lua.org/community.html Embeddable scripting with Lua
http://www-128.ibm.com/developerworks/linux/library/l-lua.html The Web Links listed here may not be valid in the future.