Динамическое добавление членов в класс с использованием 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 ответ
SWIG не использует таблицы для своих объектов; он использует userdata. В конце концов, эти объекты являются объектами C++ и должны хранить данные C++, которые код Lua не должен касаться.
И я не стал бы искать "другую библиотеку привязок 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++, который пройдет через его метатабельность.
Вам нужно будет расширить эту метатаблицу, если ваш класс C++ использует другие метафункции, такие как __add
, __sub
, __tostring
и так далее.