英文原文在:http://lua-users.org/wiki/DoItYourselfCppBinding
当制作自己的游戏引擎时,特别是结合lua,我考虑过很多绑定库,如SWIG, tolua, SimplerCppBinding,等等。没有一个非常适合我的需求:
- 我想要更多精细控制对象在lua中的处理。
- 我不喜欢额外的间接指针。
- 我想尽可能的通过inline代码帮助编译器。
这有一些我找到的窍门,大部分是代码:
创建 metatables
Lauxlib拥有很实用的函数来操作userdata metatables。他们充分隐藏在LauxLibDocumentation.我建议给每个metatable一个名字在同一个classname;这会使函数预处理程序可用。对不熟悉的操作符:#在#define声明中会导致当宏展开时跟随的参数被放到引用。
检查参数类型
一个有用的宏简单的检查所给栈中的对象是否有一个所给的userdata种类(用luaL_newmetatable已经注册):
#define lua_userdata_cast(L, pos, T) reinterpret_cast<T*>(luaL_checkudata((L), (pos), #T))
我用如下材料在我的metamethods:
if(const MyClass* myclass = lua_userdata_cast(L, 1, MyClass))
{
MyClass->SomeMethod();
return 0;
}
放置new来避免装入的指针
来看:
void* operator new(size_t size, lua_State* L, const char* metatableName)
{
void* ptr = lua_newuserdata(L, size);
luaL_getmetatable(L, metatableName);
// assert(lua_istable(L, -1)) if you're paranoid
lua_setmetatable(L, -2);
return ptr;
}
#define lua_pushobject(L, T) new(L, #T) T
现在,代替使用boxpointer的命运,把一个使用luaL_newmetatable创建了的metatable类型的对象压进栈中,象下面:
lua_pushobject(L, MyClass)(arg1, arg2, arg3);
……这些允许你构造一个新的MyClass直接到内存区域可以被使用!
模板化 __gc 方法
看这个:
template<typename T>
int GCMethod(lua_State* L)
{
reinterpret_cast<T*>(lua_touserdata(L, 1))->~T();
return 0;
}
这个模板方法做了一个完美的__gc方法。象下面:
lua_pushstring(L, "__gc");
lua_pushcfunction(L, GCMethod<MyClass>);
lua_settable(L, 1);