【问题标题】:Lua object introspectionLua 对象自省
【发布时间】:2013-10-12 18:44:21
【问题描述】:

我使用lualite将以下对象包装在lua中:

class SpriteComponent : public Component
{
public:
    SpriteComponent();

    std::string name() const;
    std::string textureId() const;
    void setTextureId(const std::string& id);
    int spriteCoordX() const;
    void setSpriteCoordX(int value);
    int spriteCoordY() const;
    void setSpriteCoordY(int value);
};

绑定代码:

module(L,
    class_<SpriteComponent>("SpriteComponent")
        .constructor("new")
        .def("name", &SpriteComponent::name)
        .property("textureId", 
            &SpriteComponent::textureId, &SpriteComponent::setTextureId)
        .property("spriteCoordX", 
            &SpriteComponent::spriteCoordX, &SpriteComponent::setSpriteCoordX)
        .property("spriteCoordY", 
            &SpriteComponent::spriteCoordY, &SpriteComponent::setSpriteCoordY)
);

有没有办法(在 lua 端或 C++ 端)获取属性列表?如果我在结果表中列出这些对,我只会得到 name 和 __instance。

local o = SpriteComponent.new()
for key,value in pairs(o) do
    print("found member " .. key);
end

我什至尝试了一些these 台式打印机,但没有运气。

【问题讨论】:

  • 您能说明您是如何尝试构建您所指的列表的吗?
  • 我根据this 问题进行了尝试。我在帖子中添加了更多详细信息。
  • 你的意思是在那个循环中你有key 假设只有两个值:name 和__instance?更具体地说,在你的 Lua 循环中只输入 print(key, " --&gt; ", value) 并发布结果。
  • __instance --&gt; userdata: 0xa03e170 name --&gt; function: 0xa03cfe8.
  • 嗯。注释掉循环,试试这个并发布发生了什么:print("1:", o.name()); print("2:", o.textureId)

标签: c++ lua introspection


【解决方案1】:

如果您可以容忍必须在 Lua 代码中列出属性名称,这可能是一个解决方案:

local GetPropertyList
do -- to make `property_names` "private" to GetPropertyList
    property_names = {
        ["SpriteComponent"] = { "textureId", "spriteCoordX", "spriteCoordY" },
        -- property names for other components, e.g.
        ["AnotherComponentName"] = { "propName1", "propName2" },
    }
    function GetPropertyList( object )  --[[local]]
        local component_name = object:name()
        local prop_names = property_names[component_name]
        if not prop_names then
            error( "unsupported component" )
        end
        local res = {}
        for _, p_name in ipairs( prop_names ) do
            local p_val = object[p_name]
            res[ #res + 1 ] = p_val
            -- or use this if you want a key-value map:
            -- res[p_name] = p_val
        end
        return res
    end  -- function
end  -- do


for k, v in pairs( GetPropertyList(o) ) do
    print( k, v )
end

【讨论】:

  • 是的,我的想法是使用我提供给 lualite 的信息作为反射的原始形式 - 所以不幸的是,我不想重复属性名称。我会尝试调整 lualite 以在绑定时构造信息。
  • @fish 是的,但是我也为你公开了一些成员,所以你可以从C++ 端获取属性。
【解决方案2】:

我是lualite 的作者。我编写的库是极简且快速的,并且没有预见到反射的需要:) 无论如何,您要查找的内容可以作为 2 个静态成员找到:

static ::std::unordered_map<char const*, detail::map_member_info_type,
  detail::unordered_hash, detail::unordered_eq> getters_;
static ::std::unordered_map<char const*, detail::map_member_info_type,
  detail::unordered_hash, detail::unordered_eq> setters_;

char const* 是属性的名称,其值为map_member_info_type,本质上是两个指针,一个指向lualite 存根,另一个指向C++ 成员函数。

struct map_member_info_type
{
  lua_CFunction callback;

  member_func_type func;
};

如果你愿意,我可以将两个成员都公开。属性的工作方式如下:

默认的getter(通常)设置在包装类的实例表中:

lua_pushcclosure(L, default_getter<C>, 2);

rawsetfield(L, -2, "__index");

这指向默认的getter:

template <class C>
int default_getter(lua_State* const L)
{
  assert(2 == lua_gettop(L));
  auto const i(lualite::class_<C>::getters_.find(lua_tostring(L, 2)));

  return lualite::class_<C>::getters_.end() == i
    ? 0
    : (lua_pushlightuserdata(L, &i->second.func),
      lua_replace(L, lua_upvalueindex(2)),
      (i->second.callback)(L));
}

查找属性的名称(在堆栈上)。这实际上可以是任何东西,如果找不到名称,则返回 0,否则,它将调用转发到为成员函数创建的 lualite 存根,然后由它处理参数和返回值。

【讨论】:

  • 嗨,非常感谢您回答并编写了这么好的库:) 我实际上在此期间发现了这些。我还发现了一个错误(有点),我在哪里可以提交?
  • @fish 顺便说一句,如果你想要存储库写权限,我可以帮你解决。
  • 谢谢,我愿意。虽然我现在不能承诺任何事情,但我确实有一个更大的项目正在进行中,它使用了 lualite,所以它在未来可能是有益的。你看到我在这个问题上的完整电子邮件地址了吗?
  • @fish 我已经添加了你,希望这个库适合你。您可以将您的名字添加到头文件中。
  • 谢谢,你真好。如果我提交任何有用的东西,我也会这样做。
猜你喜欢
  • 2014-09-19
  • 1970-01-01
  • 1970-01-01
  • 2010-09-24
  • 2012-02-23
  • 2016-03-09
  • 1970-01-01
  • 1970-01-01
  • 2020-10-05
相关资源
最近更新 更多