В следующем примере userdata
значение создается типа MyType
и таблица создается с мета-функцией __tostring
какие звонки LI_MyType__tostring
, Код создает закрытие lua ООП. Мой пример с приведенным примером выглядит так, как будто есть только один способ связать userdata
с помощью вызова метода, с помощью повышения значений. Само по себе это не проблема, если я не хочу делиться одним и тем же метатабором между экземплярами.
В идеальном мире — и что я надеюсь выяснить с этим вопросом — есть ли способ связать повышение стоимости со значением (например, userdata
) не связывая это с вызовом функции через значение? Я надеюсь, что есть хитрость, которая позволит мне продолжать использовать lua OOP на основе замыканий а также разделить одну и ту же метатаблицу между экземплярами. Я не оптимистичен, но я решил спросить, есть ли у кого-то предложение или неочевидный трюк.
using FuncArray = std::vector<const ::luaL_Reg>;
static const FuncArray funcs = {
{ "__tostring", LI_MyType__tostring },
};
int LC_MyType_newInstance(lua_State* L) {
auto userdata = static_cast<MyType*>(lua_newuserdata(L, sizeof(MyType)));
new(userdata) MyType();
// Create the metatable
lua_createtable(L, 0, funcs.size()); // |userdata|table|
lua_pushvalue(L, -2); // |userdata|table|userdata|
luaL_setfuncs(L, funcs.data(), 1); // |userdata|table|
lua_setmetatable(L, -2); // |userdata|
return 1;
}
int LI_MyType__tostring(lua_State* L) {
// NOTE: Blindly assume that upvalue 1 is my userdata
const auto n = lua_upvalueindex(1);
lua_pushvalue(L, n); // |userdata|
auto myTypeInst = static_cast<MyType*>(lua_touserdata(L, -1));
lua_pushstring(L, myTypeInst->str()); // |userdata|string|
return 1; // |userdata|string|
}
Я надеюсь, что есть способ выполнить что-то вроде (это псевдокод!):
// Assume that arg 1 is userdata
int LI_MyType__tostring(lua_State* L) {
const int stackPosition = -1;
const int upvalueIndex = 1;
const auto n = lua_get_USERDATA_upvalue(L, stackPosition, upvalueIndex);
lua_pushvalue(L, n); // |userdata|
auto myTypeInst = static_cast<MyType*>(lua_touserdata(L, -1));
lua_pushstring(L, myTypeInst->str()); // |userdata|string|
return 1; // |userdata|string|
}
Я знаю, что это похоже на то, как обстоят дела с «нормальным» метатабельным стилем ООП, но я хочу, чтобы все было основано на закрытии и не вводил синтаксис двоеточия.
Другой способ задать этот вопрос, есть ли способ поделиться метатаблицы между userdata
экземпляры при использовании ООП на основе замыкания? Используя синтаксис lua со стороны сценариев, я не думаю, что это возможно, но я надеюсь, что есть кое-что, что можно сделать на стороне C.
ОБНОВИТЬ (2013-10-10): на основе ответ @ lhf для использования lua_setuservalue()
а также lua_getuservalue()
протокол, на котором я остановился, который позволяет мне повторно использовать метатаблицы, таков:
luaL_newmetatable()
, Этим метатабелем теперь можно поделиться через userdata
экземпляры, потому что при регистрации метатаблицы не используются никакие значения.userdata
значение (lua_newuserdata()
).userdata
значение (lua_setmetatable()
).userdata
,lua_setuservalue()
на userdata
хранить ссылку на таблицу атрибутов / методов для каждого экземпляра.__index
) использовать userdata
Таблица пользовательских значений.Как следствие:
По-прежнему невозможно избежать создания таблицы методов / атрибутов для пользовательских данных, но эти издержки являются номинальными. Было бы хорошо, если obj.myMethod()
пройдет obj
в function myMethod()
как-то без использования :
, но это именно то, что :
делает, потому что это невозможно другим способом (если вы не используете повышение стоимости).
lua_setuservalue
кажется именно то, что вам нужно. Там тоже конечно lua_getuservalue
.
(Я пропускаю код C ++ и отвечаю на вопрос в заголовке.)
Я не думаю, что вы должны пытаться сделать это точно по нескольким причинам.
Просто возьмите объект из слота 1 и проверьте, соответствует ли его тип вашим пользовательским данным. (LuaL_checkudata)
Если это не объект, а tostring, например, вызывается, просто выведите его как класс имени объекта, а не детали экземпляра. Это имеет гораздо больше смысла и может значительно упростить отладку, если объект сообщает о том, чем он является на самом деле, вместо того, чтобы пытаться быть слишком умным и вводить вас в заблуждение.