1

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

4

1 回答 1

4

SWIG 不为其对象使用表;它使用userdata。毕竟,那些对象是 C++ 对象,需要存储 Lua 代码不应该接触到的 C++ 数据。

而且我不会费心寻找“另一个 Lua 绑定库”;几乎所有这些都使用用户数据,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++ 对象中获取它,该对象将通过元表。

如果您的 C++ 类使用其他元函数(如__add、等) __sub,则需要扩展此元表__tostring

于 2012-11-10T22:14:20.723 回答