我正在使用 SWIG 将 C++ 代码绑定(bind)到 Lua。到目前为止它看起来不错,但现在我需要“欺骗”并从 Lua 中扩展单个用户数据,添加自定义字段和方法等。
在 SWIG 的指令中工作时,我找不到完成它的方法。我知道魔术发生在包装代码的什么地方,但我不完全理解 __index 和 __newindex 是如何工作的。此外,SWIG 使用 __setitem 和 __getitem,它们被注释为“/* NEW:查找 __setitem() fn 这是用户提供的 set fn */”——也不知道那是什么意思。最后,我的环境会在每次构建之前自动调用脚本将 SWIG 指令绑定(bind)到 C++ 包装器,因此如果我选择重新编译或添加更多 Lua 绑定(bind),之后修改源代码将非常乏味。
到目前为止,我唯一的结论是使用 toLua++,它记录了这个特性。请帮助我避免大量的过渡工作!
编辑:我还发现 5.2 中的“lua_setuservalue”API 调用 - 它似乎很有用,但我不明白在所有 SWIG 绑定(bind)代码中我会在哪里调用它。
编辑:清理问题:
我通过 C 函数创建对象
SoundObj *loadSound(const char *name)
{
return g_audio->loadSound(name); // Returns SoundObj pointer
}
此函数通过将其原型(prototype)包含在 *.i swig 定义中而受 SWIG 约束。
在Lua中我这样写代码:
sound = audio.loadSound("beep.mp3")
sound.scale = 0.2
sound:play()
编辑:进步!我按照 Schollii 的指示编写了以下 Lua 代码。这里,“ground”是之前使用绑定(bind)的 C++ 代码获取的用户数据。代码存储了 __index 和 __newindex 的 swig 版本,然后我重新创建了这些首先查询另一个(“_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 dynamically to a class using Lua + SWIG
问题是现在我的对象类型不再是userdata,而是一个表。这意味着我不能再有机地将它作为参数传递给其他将用户数据作为参数的绑定(bind) C++ 函数。对此有什么解决办法吗?而且我必须对每个返回用户数据对象的函数执行此操作。
最佳答案
我在这里要马虎:在 Lua 中,一个表通过将另一个表用作元表来“继承”它。因此,如果您将 C++ Foo 导出到 Lua 并想要从 Foo 派生的 Lua“类”,您可以创建一个表并将其元表设置为 Foo。然后,当您使用表中不存在的字段访问新表时,它将在元表中查找它是否存在。示例伪代码:
baseTable = {a=123}
assert( getmetatable(baseTable) == nil )
derived={b=456}
assert(derived.a == nil)
setmetatable(derived, baseTable )
assert(derived.a == 123)
baseTable 是通过 SWIG 导出到 Lua 的 C++ 类,您不能更改其元表,但可以更改您在 Lua 中创建的表的元表。因此,您不必对 SWIG 代码进行任何修改或使用 SWIG 指令,您只需在 Lua 中操作即可。示例:
-- define Foo class:
Foo = {}
Foo.__index = Foo -- make Foo a Lua "class"
setmettable(Foo, YourCppBaseClass) -- derived from your C++ class
-- instantiate it:
foo = {}
setmetatable(foo, Foo) -- foo is of "class" Foo
关于c++ - 如何在 Lua 代码中扩展 SWIG 的用户数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20941253/