使用Lua + SWIG将成员动态添加到类中

时间:2012-11-10 21:50:27

标签: c++ scripting lua swig

此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绑定库?

1 个答案:

答案 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等,则需要扩展此元表。