在以下示例中,将userdata创建一个类型的值,MyType并使用__tostring调用的元函数创建一个表LI_MyType__tostring.该代码创建了一个基于闭包的lua OOP.我对提供的示例的抱怨似乎只有一种方法可以userdata通过upvalues与方法调用相关联.除非我想跨实例共享相同的元表,否则这本身并不成问题.
在一个理想的世界 - 以及我希望用这个问题发掘的东西 - 有没有办法将upvalue与值(例如userdata)相关联,而不通过upvalue将它与函数调用相关联?我希望有一个技巧可以让我继续使用基于闭包的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的"普通"metatable样式的方式类似,但我想保持闭包并避免引入冒号语法.
问这个问题的另一种方法是,有没有办法userdata在使用基于闭包的OOP时跨实例共享元表?从脚本方面使用lua的语法,我不认为这是可能的,但我希望在C方面可以做些事情.
更新(2013-10-10):基于@ lhf的使用答案lua_setuservalue()以及lua_getuservalue()我已经确定的允许我重用metatables的协议是:
luaL_newmetatable().此metatable现在可以跨userdata实例共享,因为在注册metatable时不使用upvalues.userdata值(lua_newuserdata()).userdata值(lua_setmetatable()).userdata.lua_setuservalue()上userdata存储对每个实例属性/方法表的引用.__index)以使用用户userdata值表.作为结果:
仍然无法逃脱为每个用户数据创建方法/属性表,但这种开销是名义上的.如果不使用obj.myMethod()会obj以function myMethod()某种方式传递会很好:,但这正是:因为这是不可能的另一种方式(除非你确实使用了upvalue).
| 归档时间: | 
 | 
| 查看次数: | 1110 次 | 
| 最近记录: |