Add members dynamically to a class using Lua + SWIG

我的未来我决定 提交于 2019-12-30 11:35:46

问题


This Lua code, creates a table and dynamically adds a new member. Running this I can get "hello" on the screen as expected:

foo = {}
foo.x = "hello"
print(foo.x)

But now I'm using SWIG to bind some C++ classes to Lua. For that purpose, in a test.i (SWIG module file) I created a simple class like this:

%module test

%inline
%{

class Foo
{
public:
  Foo() { X = 0; }
  void SetX(int x) { X = x; }
  int GetX() { return X; }
private:
  int X;
};

%}

Then I wrote a test Lua code like that:

obj = test.Foo()
obj:SetX(5)
print("Number: " .. obj:GetX())

Running and getting "Number 5" as expected. The problem is that when I dynamically add a new member to my SWIG-binded object, and I try to access it, like so:

obj.Y = 7
print("Number: " .. obj.Y)

I get this error message:

"attempt to concatenate field 'Y' (a nil value)"

Is it possible to dynamically add new members on objects binded using SWIG? Is there some option without having to move to another Lua binding library?


回答1:


SWIG doesn't use tables for its objects; it uses userdata. After all, those objects are C++ objects, and need to store C++ data that Lua code shouldn't be able to touch.

And I wouldn't bother looking for "another Lua binding library"; pretty much all of them use userdata, which Lua code explicitly cannot modify (in order to provide the ability to do exactly this).

However, that doesn't mean you can't cheat.

You can always wrap the object you get from C++ code into your own Lua table, which would have a metatable that forwards unknown calls to the C++ object. The code to do so would look something like this:

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

The returned proxy object is a Lua table that can have keys and values set on it. When you get a value, such as to call a function, it will see if that value was set in the table. If not, it attempts to fetch it from the C++ object that you wrapped, which will go through its metatable.

You'll need to expand this metatable if your C++ class uses other metafunctions like __add, __sub, __tostring and so forth.



来源:https://stackoverflow.com/questions/13326412/add-members-dynamically-to-a-class-using-lua-swig

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!