gpt4 book ai didi

c++ - 在 lua 中有没有办法将 upvalue 绑定(bind)到 userdata 值而不是函数?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:48:35 27 4
gpt4 key购买 nike

在下面的示例中,创建了一个 userdata 值,类型为 MyType,并使用元函数 __tostring 创建了一个表,该元函数调用 LI_MyType__tostring。该代码创建了一个基于闭包的 lua OOP。我对所提供示例的不满是,似乎只有一种方法可以通过上值将 userdata 与方法调用相关联。就其本身而言,这不是问题,除非我想跨实例共享相同的元表。

在一个理想的世界中——我希望通过这个问题来挖掘——有没有一种方法可以将上值与值(例如 userdata)相关联,而无需通过以下方式将其与函数调用相关联升值?我希望有一个技巧可以让我继续使用基于闭包的 lua OOP 跨实例共享相同的元表。我并不乐观,但我想我会问问是否有人有建议或不明显的技巧。

using FuncArray = std::vector<const ::luaL_Reg>;
static const FuncArray funcs = {
{ "__tostring", LI_MyType__tostring },
};

int LC_MyType_newInstance(lua_State* L) {
auto userdata = static_cast<MyType*>(lua_newuserdata(L, sizeof(MyType)));
new(userdata) MyType();

// Create the metatable
lua_createtable(L, 0, funcs.size()); // |userdata|table|
lua_pushvalue(L, -2); // |userdata|table|userdata|
luaL_setfuncs(L, funcs.data(), 1); // |userdata|table|
lua_setmetatable(L, -2); // |userdata|
return 1;
}

int LI_MyType__tostring(lua_State* L) {
// NOTE: Blindly assume that upvalue 1 is my userdata
const auto n = lua_upvalueindex(1);
lua_pushvalue(L, n); // |userdata|
auto myTypeInst = static_cast<MyType*>(lua_touserdata(L, -1));
lua_pushstring(L, myTypeInst->str()); // |userdata|string|
return 1; // |userdata|string|
}

我希望有一种方法可以执行类似的操作(这是伪代码!):

// Assume that arg 1 is userdata
int LI_MyType__tostring(lua_State* L) {
const int stackPosition = -1;
const int upvalueIndex = 1;
const auto n = lua_get_USERDATA_upvalue(L, stackPosition, upvalueIndex);
lua_pushvalue(L, n); // |userdata|
auto myTypeInst = static_cast<MyType*>(lua_touserdata(L, -1));
lua_pushstring(L, myTypeInst->str()); // |userdata|string|
return 1; // |userdata|string|
}

我知道这类似于 OOP 的“正常”元表样式的情况,但我想保持基于闭包的方式并避免引入冒号语法。

问这个问题的另一种方式是,在使用基于闭包的 OOP 时,有没有一种方法可以在 userdata 实例之间共享元表?从脚本方面使用 lua 的语法,我认为这是不可能的,但我希望在 C 方面可以做一些事情。


更新 (2013-10-10):基于@lhf's answer to use lua_setuservalue() and lua_getuservalue()我已经确定的允许我重用元表的协议(protocol)是这样的:

  1. 使用 luaL_newmetatable() 注册一个元表对象。这个元表现在可以在 userdata 实例之间共享,因为在注册元表时没有使用上值。
  2. 创建一个userdata值(lua_newuserdata())。
  3. 将正确的元表分配给 userdata 值 (lua_setmetatable())。
  4. 使用一个上值(userdata)创建并填充实例方法调用/属性表。
  5. userdata 上使用 lua_setuservalue() 来存储对每个实例属性/方法表的引用。
  6. 更改各种元方法(例如 __index)以使用 userdata 的用户值表。

因此:

  • 从不在元方法中使用上值
  • upvalues 仅在值的实例方法中使用
  • 给定类的每个实例只有一个额外的表

仍然不可能避免为每个用户数据创建一个方法/属性表,但这种开销是微不足道的。如果 obj.myMethod() 能以某种方式将 obj 传递给 function myMethod() 而不使用 就好了: ,但这正是 : 所做的,因为这是不可能的另一种方式(除非您确实使用了上值)。

最佳答案

lua_setuservalue似乎正是你所需要的。当然还有lua_getuservalue .

(我跳过 C++ 代码并回答标题中的问题。)

关于c++ - 在 lua 中有没有办法将 upvalue 绑定(bind)到 userdata 值而不是函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19262746/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com