【问题标题】:Adding a userdata metatable to a lua table将 userdata 元表添加到 lua 表
【发布时间】:2015-03-09 12:34:34
【问题描述】:

我有一个使用 userdata 对象运行良好的脚本系统。但是,我现在想在我的用户数据上拥有一个可以采用常规表的属性。

我认为我应该做的是创建一个普通表并将元表设置为使用我当前的元方法集,但是我很难理解如何做到这一点 - 我确信这是一个简单的调整,我可以现在看不到。

我现有的代码如下:

void
LuaContext::push(lua_State* state, boost::shared_ptr<LuaWrapped> wrapped) {
    static struct luaL_Reg methods[] = {
        { "__index", LuaWrapped::static_get },
        { "__newindex", LuaWrapped::static_set },
        { "__len", LuaWrapped::static_len },
        { "__ipairs", LuaWrapped::static_ipairs },
        { "__pairs", LuaWrapped::static_pairs },
        { "__gc", LuaWrapped::static_gc },
        { "__eq", LuaWrapped::static_eq },
        { NULL, NULL }
    };

    LuaWrapped::Ptr **ptr = (LuaWrapped::Ptr **)lua_newuserdata(state, sizeof(LuaWrapped::Ptr *));
    *ptr = new LuaWrapped::Ptr(wrapped);

    if (luaL_newmetatable(state, "LuaWrapped")) {
        lua_pushstring(state, "__index");
        lua_pushvalue(state, -2);
        lua_settable(state, -3);
        luaL_openlib(state, NULL, methods, 0);
    }
    lua_setmetatable(state, -2);
}

__gc 元方法用于删除LuaWrapped::Ptr 类(它是boost::shared_ptr 的包装器)。我想我会保留它,并将指针存储在普通表的 lightuserdata 字段中。


针对正常表问题的实验性自定义元表(根据 cmets 中的讨论):

void
LuaContext::push(lua_State* state, boost::shared_ptr<LuaWrapped> wrapped) {
    static struct luaL_Reg methods[] = {
        { "__index", LuaWrapped::static_get },
        { "__newindex", LuaWrapped::static_set },
        { "__len", LuaWrapped::static_len },
        { "__ipairs", LuaWrapped::static_ipairs },
        { "__pairs", LuaWrapped::static_pairs },
        { "__gc", LuaWrapped::static_gc },
        { "__eq", LuaWrapped::static_eq },
        { NULL, NULL }
    };

    lua_newtable(state);
    LuaContext::push(state, "pointer");
    lua_pushlightuserdata(state, new LuaWrapped::Ptr(wrapped));
    lua_settable(state, -3);

    lua_newtable(state);
    luaL_openlib(state, NULL, methods, 0);
    lua_setmetatable(state, -2);
}

int
LuaWrapped::static_get(lua_State* state) {
    int argc = lua_gettop(state);
    for (int i = 1; i <= argc; i++) {
        const char *type = lua_typename(state, i);
        std::cout << type << std::endl;
    }
    ....

get 的预期输出:

表格,字符串

get 的实际输出(Lua 5.2,Ubuntu 14.04):

布尔值,用户数据

【问题讨论】:

  • 您希望将表存储为用户数据的属性,或者希望表能够作为用户数据/对象运行?
  • @etanreisner 我想要一张桌子作为财产。使用带有 userdata 元表的普通表的想法似乎是实现这一点的方法(但我很乐意使用不同的解决方案)。
  • 我正试图弄清楚为什么要完全弄乱桌子。如果重点是将表存储在 userdata 上,那么这与在 userdata 上存储任何其他值(您只需要将表与 userdata 关联并将引用存储在其中)没有什么不同,不会弄乱元表或任何相关内容。您当前如何在用户数据上存储属性。
  • @EtanReisner 我当前的所有属性都由 C++ 对象上的 __index / __newindex 调用方法处理。
  • 对...并且您还希望能够存储表格。您如何期望在这里使用带有您的方法 metatable 的表?或者,更重要的是,您为什么希望对这张表进行方法调用?您只需要在 __index 函数中处理这个接受表的属性,而不是将值存储在 C++ 中的某个地方,而是将您交给 lua 的表存储在某个地方。

标签: c++ lua metatable lua-api


【解决方案1】:

将任意数据与用户数据一起存储是用户数据环境/用户值的用途。

lua 5.2 的方法是使用lua_setuservalue 和lua_getuservalue 函数将表与用户数据相关联。然后可以使用该表来存储和检索与用户数据相关的任意值。

在 lua 5.1 中,更通用的环境概念通过lua_setfenv 和lua_getfenv 用于此目的,但想法是相同的。

【讨论】:

    猜你喜欢
    • 2016-01-26
    • 2021-12-16
    • 1970-01-01
    • 1970-01-01
    • 2015-07-21
    • 2019-11-22
    • 2017-09-09
    • 1970-01-01
    • 2017-09-13
    相关资源
    最近更新 更多