lua — реализация метафункции __index в C / Stack Overflow

У меня есть скрипт для системы обратного вызова / функтора C ++, который может вызывать любую «зарегистрированную» функцию C ++, используя строки и / или варианты.

//REMOVED ERROR CHECKS AND ERRONEOUS STUFF FOR THIS POST
int LuaGameObject::LuaCallFunction( lua_State *luaState )
{
if ( lua_isuserdata( luaState, 1 ) == 1 )
{
int nArgs = lua_gettop( luaState );

//Get GameObject
OGameObject* pGameObject = static_cast<OGameObject*>(lua_touserdata( luaState, 1 ));
if ( pGameObject )
{
//Get FunctionName
const char* functionNameString = lua_tostring( luaState, 2 );

//Get Args
std::vector<OVariant> args;
for ( int i = 3; i <= nArgs; ++i )
{
OVariant variant;
variant.SetFromLua( luaState, i );
args.push_back( variant );
}

//Call it!
CallGameObjectFunction( luaState, pGameObject, functionNameString, args );

return 1;
}
}

return 0;
}

OVariant LuaGameObject::ExecuteLua()
{
lua_State *lState = luaL_newstate();

luaL_openlibs( lState );
lua_register( lState, "Call", LuaCallFunction );

luaL_loadstring( lState, m_pScript );

//now run it
lua_pcall( lState, 0, 1, 0 );

//process return values
OVariant result;
result.SetFromLua( lState, -1 );

lua_close( lState );

return result;
}

В Луа я могу сделать что-то вроде этого …

local king = Call("EmpireManager","GetKing")
Call("MapCamera","ZoomToActor",king)

Однако я чувствую, что могу использовать метаметод __index, чтобы упростить lua …

local king = EmpireManager:GetKing()
MapCamera:ZoomToActor(king)

Я надеялся добиться упрощенного lua с помощью следующей реализации метаметода __index

Вот как я регистрирую метафункцию __index … (в основном, скопировано из онлайн-примеров)

void LuaGameObject::Register( lua_State * l )
{
luaL_Reg sRegs[] =
{
{ "__index", &LuaGameObject::LuaCallFunction },
{ NULL, NULL }
};

luaL_newmetatable( l, "luaL_EmpireManager" );

// Register the C functions into the metatable we just created.
luaL_setfuncs( l, sRegs, 0 );
lua_pushvalue( l, -1 );

// Set the "__index" field of the metatable to point to itself
// This pops the stack
lua_setfield( l, -1, "__index" );

// Now we use setglobal to officially expose the luaL_EmpireManager metatable
// to Lua. And we use the name "EmpireManager".
lua_setglobal( l, "EmpireManager" );
}

К сожалению, я не могу правильно настроить обратный вызов. Lua правильно вызывает мою LuaGameObject :: LuaCallFunction, но в стеке нет того, что я хотел бы. В LuaGameObject :: LuaCallFunction я могу найти имя функции и объект EmpireManager в стеке. Но я не могу найти аргументы в стеке. Как правильно это настроить? Или это невозможно?

2

Решение

Определенно можно добавлять методы к userdata введите Lua, как описано в Программирование на Lua руководство с официального сайта.

Когда вы набираете следующий код Lua:

myUserdata:someMethod(arg1,arg2,arg3)

Если предположить, myUserdata является объектом «userdata», интерпретатор сделает следующее.

  1. Вызов getmetatable(myUserdata).__index(myUserdata,"someMethod") чтобы получить значение someMethod,
  2. Вызов someMethod(myUserdata,arg1,arg2,arg3), someMethod может быть что угодно из Lua. Примеры: функция Lua или C или таблица / userdata с __call Метаметод.

Ваш __index metamethod должен просто возвращать функцию (или другой объект, вызываемый из Lua), реализующий метод. Что-то вроде этого:

// IMO, quite a misleading name for the __index metamethod (there is a __call metamethod)
int LuaGameObject::LuaCallFunction( lua_State *l)
{
// todo: error checking
OGameObject* pGameObject = static_cast<OGameObject*>(lua_touserdata( luaState, 1 ));
std::string memberName = lua_tostring( luaState, 2 );

int result = 1;
if (memberName == "method1") {
lua_pushcfunction(l,LuaGameObject::luaMethod1);
} else if (memberName == "method2") {
lua_pushcfunction(l,LuaGameObject::luaMethod2);
} else {
result = 0;
}

return result;
}

Основной скелет функций, возвращаемых __index Метаметод:

int LuaGameObject::luaMethod1(lua_State* l) {
// todo: error checking.
OGameObject* pGameObject = static_cast<OGameObject*>(lua_touserdata(l, 1));
float arg1 = lua_tonumber(l, 2);
// get other args
pGameObject->method1(arg1 /*, more args if any.*/);
// optionally push return values on the stack.
return 0; // <-- number of return values.
}
2

Другие решения

Итак, после дополнительных исследований я теперь считаю, что не могу использовать метафункцию __index для вызова функтора c с аргументами. Он только передает имя таблицы и ключ к обратному вызову.

Однако, для всех, кто заинтересован, его можно использовать для табличных объектов, но не для функций (поскольку аргументы не помещаются в стек). Я сделаю это для моих «имущественных» объектов. Они не имеют аргументов и могут использоваться в lua следующим образом …

local king = EmpireManager:king
king:name = "Arthur"local name = king:name

Они правильно ссылаются и вызывают соответствующие объекты C ++.

Actor::SetName(std::string name)
std::string Actor::GetName()
0

По вопросам рекламы [email protected]