简化Lua函数对C函数的调用
我是Lua的新手 我有一个注册到Lua的C函数,如下所示:简化Lua函数对C函数的调用,lua,Lua,我是Lua的新手 我有一个注册到Lua的C函数,如下所示: call(obj, "func", param0, param1) obj.func(param0, param1) 在调用()中: 在C语言中,我们通过自定义反射逻辑来完成一些复杂的函数分派++ obj(和所有参数)都是固定的包装类型(类似于boost::any) 因此,我们不能使用常规的Lua绑定工具(luabind、luabridge等)进行简单的类成员注册 问题是: 我们如何将Lua调用简化为这样: call(obj,
call(obj, "func", param0, param1)
obj.func(param0, param1)
在调用()
中:
- 在C语言中,我们通过自定义反射逻辑来完成一些复杂的函数分派++
(和所有参数)都是固定的包装类型(类似于obj
)boost::any
call(obj, "func", param0, param1)
obj.func(param0, param1)
或
?
谢谢。您必须在您创建的每个
obj
上设置一个元表(假设它是您控制下的用户数据,并且没有元表),并覆盖其中的\u index
元方法:
local cache = { }
debug.setmetatable(obj, {
__index = function (obj, k)
return function (obj, ...) -- or (...) for [non-canonical] .-syntax
return call(obj, k, ...)
end
-- malloc-optimized version --
local f = cache[k] or function (obj, ...) return call(obj, k, ...) end
cache[k] = f
return f
end,
__metatable = "whatever",
})
f = obj.func
f(obj, param0, param1) --> call(obj, 'func', param0, param1)
obj:func(param0, param1) --> the same via syntactic sugar
如果obj
已经有一个元表,那么必须以类似的方式修改该元表
同样的操作也可以通过C接口完成,因此您可以将obj
创建与\u索引
设置相结合
C端更新: 若创建函数位于外部库中,那个么除了捕获所有对象外观点(返回值和作为参数传递的表中的值)并如上所述将其换行外,并没有其他选项 如果创建函数在您的控制下,您可以在那里看到类似的内容:
ud = lua_newuserdata(L, sizeof(object));
*ud = object;
// this part is missing if objects have no metatable at all
luaL_getmetatable(L, tname); // or 'if (luaL_newmetatable(L, tname)) { ... }'
lua_setmetatable(L, -2);
return 1;
必须在创建元表的位置添加_uindex元方法:
…代码中的某个地方,可能就在*ud=object
行之后
if (luaL_newmetatable(L, tname)) {
... original metatable setup ...
int res = luaL_loadstring(L,
"return function (obj, k)\n"
" return function (obj, ...)\n"
" return call(obj, k, ...)\n"
" end\n"
"end\n");
assert(res == 0);
lua_call(L, 0, 1);
lua_setfield(L, -2, "__index");
}
如果您的userdata根本没有元表,则必须创建并设置它
如果您想去掉全局符号调用
,则将其C实现作为参数传递给luaL_loadstring'ed chunk:
luaL_loadstring(L, "local call = ...\n return function (obj, k)\n" ...);
lua_pushcfunction(L, l_call);
lua_call(L, 1, 1); // instead of (0, 1)
然后,
call
将被本地化到闭包中。还要注意,此方法在每次调用它时都会围绕k
创建一个闭包。为了防止在紧循环中出现这种情况,您可以缓存内部函数(返回函数…
),并从缓存中返回已经看到的k
s。(为此添加了示例代码)包装器可能会返回任何call
返回到调用站点的内容。@greatwolf-谢谢!固定的。此修复的注意事项:由于它现在进行尾部调用,任何与级别相关的lua例程(例如带有级别参数的error
)都应采用级别1,因为匿名函数(obj,…)将被call
@user3125367替换谢谢!lua版本有效!但是,如何通过C接口实现呢?由于obj是由C函数创建的,因此通过lua@ZSaberLv0-更新为C