我正在使用 SWIG 将 C++ 代码绑定到 Lua。到目前为止看起来不错,但现在我需要“作弊”并从 Lua 中扩展单个用户数据,添加自定义字段和方法等。
在 SWIG 的指令中工作时,我找不到完成它的方法。我知道魔术发生在包装器代码的哪个位置,但我不完全理解 __index 和 __newindex 是如何工作的。此外,SWIG 使用 __setitem 和 __getitem,它们被注释为“/* NEW:查找 __setitem() fn 这是用户提供的 set fn */”——也不知道这意味着什么。最后,我的环境会在每次构建之前自动调用脚本将 SWIG 指令绑定到 C++ 包装器,因此如果我选择重新编译或添加更多 Lua 绑定,那么之后修改源代码会非常乏味。
到目前为止,我唯一的结论是使用 toLua++,它记录了这个特性。请帮我避免大量的过渡工作!
编辑:我还发现 5.2 中的“lua_setuservalue”API 调用 - 它似乎很有用,但我不明白在所有 SWIG 绑定代码中我会在哪里调用它。
编辑:清理事情:
我通过 C 函数创建对象
SoundObj *loadSound(const char *name)
{
return g_audio->loadSound(name); // Returns SoundObj pointer
}
通过在 *.i swig 定义中包含它的原型,此函数受 SWIG 的约束。
在 Lua 中,我编写如下代码:
sound = audio.loadSound("beep.mp3")
sound.scale = 0.2
sound:play()
编辑:进步!我按照 Schollii 的说明编写了以下 Lua 代码。这里,“ground”是之前使用绑定 C++ 代码获取的用户数据。代码存储了 swig 的 __index 和 __newindex 版本,然后我重新创建了这些函数,这些函数首先查询另一个(“_other”)表。
我目前的问题是存储在“_other”表中的新值在该类型的所有用户数据对象之间共享。换句话说,如果 ground.nameFoo = "ha!",所有其他对象都有 nameFoo 字段存储 "ha!"。我该如何解决?
mt = getmetatable(ground)
mt._other = {}
mt.__oldindex = mt.__index
mt.__oldnewindex = mt.__newindex
mt.__index = function(tbl, key)
if mt.__oldindex(tbl, key) == nil then
if mt._other[key] ~= nil then
return mt._other[key]
end
else
return mt.__oldindex(tbl, key)
end
end
mt.__newindex = function(tbl, key, val)
if mt.__oldnewindex(tbl, key, val) == nil then
mt._other[key] = val
end
end
编辑:我从这个答案中实现了解决方案:Add members dynamic to a class using Lua + SWIG
问题是现在我的对象类型不再是 userdata,它是一个表。这意味着我不能再有机地将它作为参数传递给其他以 userdata 作为参数的绑定 C++ 函数。有什么解决办法吗?而且我必须对每个返回 userdata 对象的函数执行此操作。