Доступ к экземпляру класса в статичной функции

154
16 февраля 2018, 19:15

Столкнулся с проблемой. Нужно вставить в таблицу, в луа C-функцию, которая должна обращаться к НЕ статичному полу (экземпляру класса). Пробовал использовать лямбды, но не получается привести их к lua_CFunction. Как можно это реализовать?

class Computer {
        private:
                lua_State *luaState;
        public:
                void run() {
                         luaState = luaL_newstate();
                            lua_createtable(luaState, 0, 1);
        lua_pushcfunction(luaState, /* ?? */);
        lua_setfield(luaState, -2, "test");
                            lua_setglobal(luaState, "computer");
                }
}
Computer *c = new Computer;
c.run();
Answer 1

Поскольку вы создаёте lua_State внутри вашего объекта, то можно сохранить указатель на объект в таблице, внутри Lua и использовать его для вызова методов. При этом, для каждого метода, который вы хотите вызвать из Lua, вам придётся писать Си-обёртку, которая будет извлекать этот указатель из таблицы и вызывать соответствующий метод.

Например, если вам надо вызвать такой метод:

void Computer::test(int i) {
    std::cout << "test: " << i;
}

то, вы сохраняете указатель на объект в конструкторе:

Computer::Computer(void) {
    luaState = luaL_newstate();
    luaL_openlibs( luaState );
    lua_createtable(luaState, 0, 2);
    // указатель на объект
    lua_pushlightuserdata(luaState, this);
    lua_setfield(luaState, -2, "_self");
    // указатель на функцию обёртку
    lua_pushcfunction(luaState, test_wrap);
    lua_setfield(luaState, -2, "test");
    lua_setglobal(luaState, "computer");
}

.. и пишите обёртку:

int test_wrap(lua_State *L)
{
    // чтение аргумента(ов) функции
    if(!lua_isnumber(L, -1))
        luaL_error(L, "Expected a Number as a first argument!");
    int i = lua_tonumber(L, -1);
    // загрузка указателя
    Computer * pComp = get_obj_pointer(L);
    // вызов метода
    if (pComp) {
        pComp->test(i);
    }
    return 0;
}

Функция чтения указателя на объект из луа-таблицы:

Computer * get_obj_pointer(lua_State *L)
{
    lua_getglobal(L, "computer");
    if (!lua_istable(L, -1))
        luaL_error(L, "Table 'computer' is not found!");
    lua_pushstring(L, "_self");
    lua_gettable(L, -2);
    if (!lua_isuserdata(L, -1))
        luaL_error(L, "Value 'computer._self' is not found!");
    void *p = lua_touserdata(L, -1);
    lua_pop(L, 1);
    return (Computer *) p;
}

Далее, пишите тестовый скрипт script.lua:

local comp = computer    
print(comp._self) # напечатает "userdata 0xXXXXXX"
print(comp.test(15)) # напечатает "test: 15"

и вызываете его в методе run:

void Computer::run(void) {
    int err = luaL_dofile(luaState, "script.lua");
    if (err) {
       std::cout << "Error: " << lua_tostring(luaState, -1);
       lua_pop(luaState, 1);
    }
}

Тестовый код целиком: https://pastebin.com/FSdsRaAd

READ ALSO
Как использовать файл QML в проекте?

Как использовать файл QML в проекте?

Добрый день, хочу использовать в своём проекте на QT510 преключатель из примера

200
Как из структуры std::tm получить значение в миллисекундах

Как из структуры std::tm получить значение в миллисекундах

Можно ли, задав в структуре std::tm нужную дату и время, получить значение в миллисекундах от начала отсчёта времени, те

149
проблемы с eclipse и javaFX

проблемы с eclipse и javaFX

Когда в eclipse'е я создал свежий проект, то он сразу выдаёт ошибки и это связанно с тем, что eclipse не импортировал javafxЯ устанавливал e(fx)clipse и делал:

219
Возможно ли создать Proxy-класс только из интерфейса

Возможно ли создать Proxy-класс только из интерфейса

Всем добрый деньК примеру есть у меня лишь интерфейс, без реализации каким-либо классом

216