使用C API覆盖Lua中的赋值运算符

时间:2016-08-16 16:32:43

标签: c++ c lua variable-assignment metatable

我在C ++程序中有对象,我将其作为userdata传递给Lua,并且我覆盖了此userdata的metatable,以便对象的索引进行赋值(通过__newindex和__index)导致对C的调用,转换赋值以影响C ++对象或将C ++元素转换为Lua值(另一个用户数据或基本类型,如bool,number,string)。 userdata作为参数传递给从我的C ++程序调用的类似事件的Lua函数。

luaL_newmetatable(L, "object");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);  /* pushes the metatable */
lua_settable(L, -3);  /* metatable.__index = metatable */

luaL_openlib(L, NULL, vallib_m, 0);
luaL_openlib(L, "internal", vallib_f, 0);

lua_pushstring(L, "__index");
lua_pushstring(L, "get");
lua_gettable(L, 2);  /* get val.get */
lua_settable(L, 1);  /* metatable.__index = val.get */

lua_pushstring(L, "__newindex");
lua_pushstring(L, "set");
lua_gettable(L, 2); /* get array.set */
lua_settable(L, 1); /* metatable.__newindex = val.set */

然而,这并不允许我自己分配实际变量,只分配变量的索引。没有用于直接覆盖赋值运算符的元事件,因此我正在寻找一种解决方法。

换句话说,我可以这样做:lua_userdata_object_passed_as_arg_to_event["is_it_true"]=true 它将Lua布尔值分配给我的内部C ++对象,但如果我这样做: lua_userdata_object_passed_as_arg_to_event = new_object() 它会改变Lua变量引用的内容,但是根据我的理解,它不会对核心对象做任何事情。

我考虑过的一个解决方法是一些需要开发人员进行的黑客攻击lua_userdata_object_passed_as_arg_to_event["__self"] = new_object() 如果他们想要改变对象本身,但这是不可取的。

所以我找到了一些独特的解决方案,通过使用全局变量和覆盖全局metatable赋值运算符来覆盖赋值运算符,但我希望看看是否有人可以帮我解释这个解决方案。请参阅http://lua-users.org/lists/lua-l/2012-01/msg00413.htmlhttps://www.lua.org/pil/14.2.html。 特别是,我的变量是函数参数,而不是全局变量,所以如何通过C API转换为全局变量,以便任何分配将由自定义C函数捕获,如果分配发生在全局用户数据上,它将采取行动? / p>

顺便说一句,我的userdata是一个指向对象的指针,以避免重复大对象,如果这很重要的话。

1 个答案:

答案 0 :(得分:4)

Lua和C / C ++是具有不同需求的不同语言。在C / C ++中,变量始终引用特定对象。您可以更改此对象的内容,但永远不能使变量处理不同的对象。如果您执行a = b;,则会将b的值复制到a。你永远不能改变a所谈论的对象。

在Lua中,变量不会永久引用任何内容。因此,当前变量所持有的对象与该对象的值之间存在区别。

你的kludge通过全局变量函数,但local变量是不存在的东西。他们在Lua堆栈上的位置;你无法覆盖Lua关于它们的默认行为。

处理此问题的最佳方法是接受 C和Lua之间的区别。在Lua中编写代码就像在Lua中编写代码一样。不要试图让Lua代码像C一样工作;那种方式很愚蠢。它们是不同的语言,你应该接受它们的差异,而不是反对它们。

如果你想让Lua能够做同等级的a = b,那么你应该在你的类型中创建一个名为assign的函数或者允许你分配给对象的函数&#39 ; s值。就像你想要将所有表元素从一个表复制到另一个表一样,你必须编写一个函数来做到这一点。