此Lua代码创建一个表并动态添加新成员。运行此项我可以按预期在屏幕上显示"hello"
:
foo = {}
foo.x = "hello"
print(foo.x)
但现在我使用SWIG将一些C ++类绑定到Lua。
为此,在test.i
(SWIG模块文件)中,我创建了一个这样的简单类:
%module test
%inline
%{
class Foo
{
public:
Foo() { X = 0; }
void SetX(int x) { X = x; }
int GetX() { return X; }
private:
int X;
};
%}
然后我写了一个测试Lua代码:
obj = test.Foo()
obj:SetX(5)
print("Number: " .. obj:GetX())
按预期运行并获取"Number 5"
。问题是,当我动态地将新成员添加到SWIG绑定对象时,我尝试访问它,如下所示:
obj.Y = 7
print("Number: " .. obj.Y)
我收到此错误消息:
"attempt to concatenate field 'Y' (a nil value)"
是否可以在使用SWIG绑定的对象上动态添加新成员?是否有一些选项而无需移动到另一个Lua绑定库?
答案 0 :(得分:4)
SWIG不为其对象使用表格;它使用 userdata 。毕竟,这些对象是C ++对象,需要存储Lua代码无法触及的C ++数据。
我不会费心寻找“另一个Lua绑定库”;几乎所有所有都使用了userdata,这是Lua代码明确无法修改的(为了提供这样做的能力)。
然而,这并不意味着你不能作弊。
您始终可以将从C ++代码中获取的对象包装到您自己的Lua表中,该表将具有将未知调用转发给C ++对象的元表。这样做的代码看起来像这样:
local function WrapObject(cppObject)
local proxy = {}
local wrapper_metatable = {}
function wrapper_metatable.__index(self, key)
local ret = rawget(self, key)
if(not ret) then
ret = cppObject[key]
if(type(ret) == "function") then
return function(self, ...)
return ret(cppObject, ...)
end
else
return ret
end
else
return ret
end
end
setmetatable(proxy, wrapper_metatable)
return proxy
end
返回的代理对象是一个Lua表,可以在其上设置键和值。当你得到一个值,比如调用一个函数时,它会看到是否在表中设置了该值。如果没有,它会尝试从你包装的C ++对象中获取它,它将通过它的 metatable。
如果您的C ++类使用其他元函数,例如__add
,__sub
,__tostring
等,则需要扩展此元表。