在Lua和C/C++库,lua user org上面有罗列,但是代码量小,代码容易读,容易学习的库很少.要么提供功能少,例如autoToC 仅仅提供struct绑定。luabind 必须使用Boost库,代码量大,增加了学习难点,同时,luabind库本身代码量就多。
在筛选过程中,我选择了luabrige lua_tinker 以及luna作为学习的选择。
通过lua_call()调用Lua Code函数已经能够实现.在C++中可以通过模板技术,简单方便的实现C++调用Lua Code全局函数。
sample_2.cpp
#include <iostream>
using namespace std;
extern "C"
{
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
namespace lua_tinker
{
//利用C++编译时模板技术,对push()操作进行模板化
// push a value to lua stack
template<typename T>
void push(lua_State *L, T ret);
//对push函数模板进行显示专用化,对char类型进行特殊处理
template<>
void lua_tinker::push(lua_State *L, char ret)
{
lua_pushnumber(L, ret);
}
template<>
void lua_tinker::push(lua_State *L, unsigned char ret)
{
lua_pushnumber(L, ret);
}
template<>
void lua_tinker::push(lua_State *L, short ret)
{
lua_pushnumber(L, ret);
}
template<>
void lua_tinker::push(lua_State *L, unsigned short ret)
{
lua_pushnumber(L, ret);
}
template<>
void lua_tinker::push(lua_State *L, long ret)
{
lua_pushnumber(L, ret);
}
template<>
void lua_tinker::push(lua_State *L, unsigned long ret)
{
lua_pushnumber(L, ret);
}
template<>
void lua_tinker::push(lua_State *L, int ret)
{
lua_pushnumber(L, ret);
}
template<>
void lua_tinker::push(lua_State *L, unsigned int ret)
{
lua_pushnumber(L, ret);
}
template<>
void lua_tinker::push(lua_State *L, float ret)
{
lua_pushnumber(L, ret);
}
template<>
void lua_tinker::push(lua_State *L, double ret)
{
lua_pushnumber(L, ret);
}
template<>
void lua_tinker::push(lua_State *L, char* ret)
{
lua_pushstring(L, ret);
}
template<>
void lua_tinker::push(lua_State *L, const char* ret)
{
lua_pushstring(L, ret);
}
template<>
void lua_tinker::push(lua_State *L, bool ret)
{
lua_pushboolean(L, ret);
}
template<>
void lua_tinker::push(lua_State *L, long long ret)
{
*(long long*)lua_newuserdata(L, sizeof(long long)) = ret;
lua_pushstring(L, "__s64");
lua_gettable(L, LUA_GLOBALSINDEX);
lua_setmetatable(L, -2);
}
template<>
void lua_tinker::push(lua_State *L, unsigned long long ret)
{
*(unsigned long long*)lua_newuserdata(L, sizeof(unsigned long long)) = ret;
lua_pushstring(L, "__u64");
lua_gettable(L, LUA_GLOBALSINDEX);
lua_setmetatable(L, -2);
}
/*---------------------------------------------------------------------------*/
/* read */
/*---------------------------------------------------------------------------*/
//对指定堆栈的索引进行读取数据
// read a value from lua stack
template<typename T>
T read(lua_State *L, int index);
template<>
char* lua_tinker::read(lua_State *L, int index)
{
return (char*)lua_tostring(L, index);
}
template<>
const char* lua_tinker::read(lua_State *L, int index)
{
return (const char*)lua_tostring(L, index);
}
template<>
char lua_tinker::read(lua_State *L, int index)
{
return (char)lua_tonumber(L, index);
}
template<>
unsigned char lua_tinker::read(lua_State *L, int index)
{
return (unsigned char)lua_tonumber(L, index);
}
template<>
short lua_tinker::read(lua_State *L, int index)
{
return (short)lua_tonumber(L, index);
}
template<>
unsigned short lua_tinker::read(lua_State *L, int index)
{
return (unsigned short)lua_tonumber(L, index);
}
template<>
long lua_tinker::read(lua_State *L, int index)
{
return (long)lua_tonumber(L, index);
}
template<>
unsigned long lua_tinker::read(lua_State *L, int index)
{
return (unsigned long)lua_tonumber(L, index);
}
template<>
int lua_tinker::read(lua_State *L, int index)
{
return (int)lua_tonumber(L, index);
}
template<>
unsigned int lua_tinker::read(lua_State *L, int index)
{
return (unsigned int)lua_tonumber(L, index);
}
template<>
float lua_tinker::read(lua_State *L, int index)
{
return (float)lua_tonumber(L, index);
}
template<>
double lua_tinker::read(lua_State *L, int index)
{
return (double)lua_tonumber(L, index);
}
template<>
bool lua_tinker::read(lua_State *L, int index)
{
if(lua_isboolean(L, index))
return lua_toboolean(L, index) != 0;
else
return lua_tonumber(L, index) != 0;
}
template<>
void lua_tinker::read(lua_State *L, int index)
{
return;
}
template<>
long long lua_tinker::read(lua_State *L, int index)
{
if(lua_isnumber(L,index))
return (long long)lua_tonumber(L, index);
else
return *(long long*)lua_touserdata(L, index);
}
template<>
unsigned long long lua_tinker::read(lua_State *L, int index)
{
if(lua_isnumber(L,index))
return (unsigned long long)lua_tonumber(L, index);
else
return *(unsigned long long*)lua_touserdata(L, index);
}
// pop a value from lua stack
template<typename T>
T pop(lua_State *L)
{ //利用C++模板,把栈顶返回值读取到C code中
T t = read<T>(L, -1);
//把栈顶弹出
lua_pop(L, 1);
//返回值
return t;
}
// call
template<typename RVal>
RVal call(lua_State* L, const char* name)
{
lua_pushstring(L, name);
lua_gettable(L, LUA_GLOBALSINDEX);
lua_pcall(L, 0, 1, errfunc);
return pop<RVal>(L);
}
template<typename RVal, typename T1>
RVal call(lua_State* L, const char* name, T1 arg)
{
lua_pushstring(L, name);
lua_gettable(L, LUA_GLOBALSINDEX);
push(L, arg);
lua_call(L, 1, 1);
return pop<RVal>(L);
}
//定义对Lua Code 全局函数的调用。有一个返回值,二个参数。
template<typename RVal, typename T1, typename T2>
RVal call(lua_State* L, const char* name, T1 arg1, T2 arg2)
{ //把Lua Code 函数名字压入虚拟栈上面
lua_pushstring(L, name);
//获取_G[name] 函数到虚拟栈顶
lua_gettable(L, LUA_GLOBALSINDEX);
//利用C++模板,把第一个参数压入虚拟栈
push(L, arg1);
//把第二个参数压入虚拟栈中
push(L, arg2);
//调用lua_call()函数,实际调Lua Code函数,并把Lua Code函数结果压入虚拟栈
lua_call(L, 2, 1);
//返回C Code值
return pop<RVal>(L);
}
template<typename RVal, typename T1, typename T2, typename T3>
RVal call(lua_State* L, const char* name, T1 arg1, T2 arg2, T3 arg3)
{
lua_pushstring(L, name);
lua_gettable(L, LUA_GLOBALSINDEX);
push(L, arg1);
push(L, arg2);
push(L, arg3);
lua_call(L, 3, 1);
return pop<RVal>(L);
}
}
int main(int argc, char **argv)
{
//创建lua_State
lua_State *L = lua_open(); /* create state */
//注册标准库
luaL_openlibs (L);
//执行sample_1.lua
luaL_dofile (L, "sample_2.lua");
//对Lua Code 函数进行调用
int result = lua_tinker::call<int>(L, "lua_func", 3,1);
printf("lua_func(3,4) = %d\n", result);
lua_close(L);
return 1;
}
sample_2.lua 如下代码是 定义的Lua Code函数:
--在Lua Code中定义全局函数
function lua_func(arg1, arg2)
return arg1 + arg2
end
代码还是很简洁的。把luabind 和boost库实现的东西进行简化过。 在通过c++模板实现,具有很高的学习lua和C++进行交换 的价值。