将用户数据元表添加到lua表

时间:2015-01-11 17:53:03

标签: c++ lua metatable lua-api

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

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

我现有的代码如下:

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 metamethod用于删除LuaWrapped::Ptr类(它是boost::shared_ptr的包装器)。我想我会留下它,并将指针存储在普通表上的lightuserdata字段中。


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

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上的预期输出:

  

table,string

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

  

boolean,userdata

1 个答案:

答案 0 :(得分:3)

存储任意数据和用户数据是userdata环境/用户值的用途。

执行此操作的lua 5.2方法是使用lua_setuservaluelua_getuservalue函数将表与userdata相关联。然后,该表可用于存储和检索与userdata相关的任意值。

在lua 5.1中,通过lua_setfenvlua_getfenv将更一般的环境概念用于此目的,但这个想法是相同的。