自己动手做 C++ 绑定 |
|
以下是我发现的一些技巧,主要是以代码形式呈现,它们可以协同工作。
lauxlib 提供了非常非常实用的函数来操作 userdata 的元表。这些在参考手册的 [Lua 辅助库] 中有充分的介绍。我建议给每个元表一个与类名相同的名字;这将启用有趣的、邪恶的预处理器技巧,就像接下来的例子一样。对于不熟悉该运算符的人:# 运算符在 #define 语句中,会在宏展开时将后面的参数放在引号中。
一个有用的宏,用于简化检查给定堆栈位置的对象是否为给定用户数据类型(通过 luaL_newmetatable 注册)
#define lua_userdata_cast(L, pos, T) static_cast<T*>(luaL_checkudata((L), (pos), #T))
我在我的元方法中经常使用类似这样的东西。
if(const MyClass* myclass = lua_userdata_cast(L, 1, MyClass))
{
MyClass->SomeMethod();
return 0;
}
瞧瞧
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
现在,不用进行包装指针的怪异操作,而是要将一个元表是通过 luaL_newmetatable 创建的类型对象推送到堆栈上,可以这样做:
lua_pushobject(L, MyClass)(arg1, arg2, arg3);
……这样你就可以直接在一个新的 MyClass 对象将要使用的内存区域中构造它了!
看这里
template<typename T>
int GCMethod(lua_State* L)
{
static_cast<T*>(lua_touserdata(L, 1))->~T();
return 0;
}
这个模板化方法非常适合作为 __gc 方法。像这样:
lua_pushstring(L, "__gc"); lua_pushcfunction(L, GCMethod<MyClass>); lua_settable(L, 1);