问题
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