【发布时间】:2017-05-15 13:21:30
【问题描述】:
我需要一个想法,如何存储 lua 闭包以便稍后异步调用它们。
- 我的第一个想法是
lua_tocfunction,但闭包不是 cfunction,不能直接从 C 调用 - 第二个想法是将闭包保存在元表中,我可以推送它并稍后调用它,但似乎我无法复制一个闭包。 (
Error: attempt to index a function value)。
所以我需要你的帮助。如何存储闭包?
我承认,我不完全理解为什么我的 lua ctor 中有一个 __index 字段,因为我从某个地方复制了该部分。
顺便说一句:没有onrender 的程序按预期工作。我正在使用 qt gui 并且 lua 状态已关闭,在 qt 的主循环之后,因此创建的窗口不会在脚本之后被__gc 删除。
bootstrap.lua
local w = w_render() -- create window object
w:show()
w:onrender(function()
print('render')
end)
w_lua.cpp
// chlua_* are helper macros/templates/methods
// 1: self
// 2: render closure
int w_render_onrender(lua_State *L) {
auto *self = chlua_this<GLWindow *>(L, 1, w_render_table);
lua_pushvalue(L, 2); // copy closure to top
lua_setfield(L, 2, "onrender_cb"); // save closure in metatable
// !!! ERROR: attempt to index a function value
self->onrender([L](){
lua_getfield(L, 2, "onrender_cb");
qDebug() << "onrender";
lua_call(L, 0, 0);
});
return 0;
}
// Creates the object
int w_render(lua_State *L) {
auto *&self = chlua_newuserdata<GLWindow *>(L);
self = new GLWindow;
if (luaL_newmetatable(L, w_render_table)) {
luaL_setfuncs(L, w_render_methods, 0);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
}
lua_setmetatable(L, -2);
return 1;
}
【问题讨论】:
-
您确定
w_render_onrender中的索引正确吗?我假设代表您的GLWindow *的 self udata 首先是,其次是闭包。在哪种情况下不应该是lua_setfield(L, -3, "onrender_cb");或lua_setfield(L, 1, "onrender_cb");? -
我认为您需要做的是
lua_getmetatable(L, 1); lua_insert(L, -2);,然后才能真正尝试设置该字段。我不确定这里是否真的需要 pushvalue。无论如何,这不会在您的onrenderlambda 中使用,因为您正在执行lua_getfield来取回闭包。 -
@greatwolf 我已经尝试了你的 2 个解决方案:-3 或 1 给我
attempt to index a userdata value,第二个解决方案也给我attempt to index a userdata value。我注意到的一件事是,应该使用1调用 get/setfield,因为 doc 说,索引是表存储在堆栈中的位置,现在我想知道 lambda 的实现如何可以肯定的是,桌子在那里,同时没有人改变堆栈。 -
你是说
lua_getmetatable(L, 1);给attempt to index a userdata value?这真的没有意义。那是元表集正确的GLWindow *udata? -
@greatwolf 不管我的 impl 出了什么问题,你的 answer 有效;)
标签: c++ c lua lua-api lua-c++-connection