自己动手做 C++ 绑定

lua-users home
wiki

在我的游戏引擎编程过程中,特别是从一开始就集成 Lua,我考虑过很多绑定生成器,比如 SWIG, tolua, SimplerCppBinding 等等。但没有一个完全满足我的需求。

以下是我发现的一些技巧,主要是以代码形式呈现,它们可以协同工作。

创建元表

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;
}

placement 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

现在,不用进行包装指针的怪异操作,而是要将一个元表是通过 luaL_newmetatable 创建的类型对象推送到堆栈上,可以这样做:

lua_pushobject(L, MyClass)(arg1, arg2, arg3);

……这样你就可以直接在一个新的 MyClass 对象将要使用的内存区域中构造它了!

模板化的 __gc 方法

看这里

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);

另请参阅


RecentChanges · preferences
编辑 · 历史
最后编辑于 2014 年 2 月 23 日 上午 11:22 GMT (diff)