简体   繁体   English

使用luabind和std :: shared_ptr继承

[英]Using luabind and std::shared_ptr with inheritance

I've got an API (a specific GUI library) that relies on std::shared_ptr a lot, ie they are often used as function parameters and stored within other objects. 我有一个API(一个特定的GUI库),它很多地依赖于std::shared_ptr ,即它们通常用作函数参数并存储在其他对象中。 For example, container widgets, such as splitters and boxes will store their child widgets in shared_ptr s. 例如,容器小部件(例如拆分器和框)将其子小部件存储在shared_ptr Now I would like to map this API to Lua via luabind. 现在我想通过luabind将此API映射到Lua。 In an ideal world, Luabind would create new objects in shared_ptrs and allow me to pass those directly to functions taking shared_ptr parameters. 在理想的世界中,Luabind将在shared_ptrs中创建新对象,并允许我将这些对象直接传递给采用shared_ptr参数的函数。 This seems to work for single classes, eg: 这似乎适用于单个类,例如:

luabind::class_<Button, std::shared_ptr<Button>>("Button")

While I declare it like that, I can expose and use functions like void foo(std::shared_ptr<Button> const&) . 虽然我声明它,我可以公开和使用像void foo(std::shared_ptr<Button> const&)

Now the luabind manual mentions that in order to use a hierarchy of classes, I'd have to use the same shared_ptr template-instance for all classes in the hierarchy, eg 现在,luabind手册提到为了使用类的层次结构,我必须对层次结构中的所有类使用相同的shared_ptr模板实例,例如

luabind::class_<BaseWidget, std::shared_ptr<BaseWidget>>("BaseWidget"),
luabind::class_<Button, BaseWidget, std::shared_ptr<BaseWidget>>("Button")

Now I can no longer call foo - it will fail to find the function from Lua. 现在我再也不能调用foo - 它将无法从Lua中找到函数。 Can I somehow get luabind to still support passing buttons in shared_ptr s? 我可以以某种方式让luabind继续支持shared_ptr的传递按钮吗? Also, I would like to know why luabind mandates that you use the same smart pointer for all classes in the hierarchy instead of them just being convertible to base class pointers. 此外,我想知道为什么luabind强制要求对层次结构中的所有类使用相同的智能指针,而不是它们只能转换为基类指针。

I think for that to work you have to bind your derived class like this: 我认为为了工作你必须绑定你的派生类,如下所示:

luabind::class_<Button, BaseWidget, std::shared_ptr<Button>> ("Button")

For example: 例如:

class BaseWidget
{
public:
    static void Bind2Lua(lua_State* l)
    {
        luabind::module(l)
        [
            luabind::class_<BaseWidget, std::shared_ptr<BaseWidget>> ("BaseWidget")
            .def(luabind::constructor<>())
        ];
    }

    virtual ~BaseWidget()
    {

    }
};

class Button : public BaseWidget
{
public:
    static void Bind2Lua(lua_State* l)
    {
        luabind::module(l)
        [
            luabind::class_<Button, BaseWidget, std::shared_ptr<Button>> ("Button")
            .def(luabind::constructor<>())
            .def("Click", &Button::Click)
        ];
    }

    void Click()
    {
        std::cout << "Button::Click" << std::endl;
    }
};

Now you can use it with shared_ptr: 现在您可以将它与shared_ptr一起使用:

class Action
{
public:
    void DoClick(const std::shared_ptr<Button>& b)
    {
        // perform click action
        b->Click();
    }

    static void Bind2Lua(lua_State* l)
    {
        luabind::module(l)
        [
            luabind::class_<Action> ("Action")
            .def(luabind::constructor<>())
            .def("DoClick", &Action::DoClick)
        ];
    }
};

In lua: 在卢阿:

b = Button()

a = Action()

a:DoClick(b)

The reason is that luabind uses type-id system with integers (more precisely std::size_t as defined in inheritance.hpp). 原因是luabind使用带有整数的type-id系统(更准确地说是在inheritance.hpp中定义的std :: size_t)。
You can obtain the type-id of any registered type with the function: 您可以使用以下函数获取任何已注册类型的type-id:

luabind::detail::static_class_id<T>(nullptr);

Where T is the registered class. 其中T是注册类。
In my demo program they are: 在我的演示程序中,它们是:

  • BaseWidget = 3 BaseWidget = 3
  • std::shared_ptr< BaseWidget > = 6 std :: shared_ptr <BaseWidget> = 6
  • Button = 4 按钮= 4
  • std::shared_ptr< Button > = 7 std :: shared_ptr <Button> = 7
  • Action = 5 行动= 5

So when you call DoClick from lua, it will call the get member of the template class pointer_holder in instance_holder.hpp: 因此,当您从lua调用DoClick时,它将在instance_holder.hpp中调用模板类pointer_holder的get成员:

std::pair<void*, int> get(class_id target) const
{
    if (target == registered_class<P>::id)
        return std::pair<void*, int>(&this->p, 0);

    void* naked_ptr = const_cast<void*>(static_cast<void const*>(
        weak ? weak : get_pointer(p)));

    if (!naked_ptr)
        return std::pair<void*, int>((void*)0, 0);

    return get_class()->casts().cast(
        naked_ptr
      , static_class_id(false ? get_pointer(p) : 0)
      , target
      , dynamic_id
      , dynamic_ptr
    );
}

As you can see, if the target class is not the same as the one registered, it will try to do a cast. 如您所见,如果目标类与注册的类不同,它将尝试进行强制转换。
This is where things get interesting. 这是事情变得有趣的地方。 If you declared the Button class as 如果您将Button类声明为

luabind::class_<Button, BaseWidget,std::shared_ptr<BaseWidget>>("Button")

then the instance will be held as a shared_ptr to BaseWidget, thus the cast function will try to cast from BaseWidget (3) to std::shared_ptr< Button > (7) and that fails. 那么实例将作为shared_ptr保存到BaseWidget,因此强制转换函数将尝试从BaseWidget(3)转换为std :: shared_ptr <Button>(7)并且失败。 It could work if luabind supported base-to-derived conversion, which it doesn't seem to. 如果luabind支持从基础到派生的转换,它可能会起作用,而这似乎并不适用。

If however you declared the Button class as 但是,如果您将Button类声明为

luabind::class_<Button, BaseWidget, std::shared_ptr<Button>> ("Button")

then the instance will be held as as a shared_ptr to Button and then the target id will match the registered type. 然后,实例将作为一个shared_ptr保持到Button,然后目标ID将匹配注册的类型。 The get function will branch on the first return, never to bother with the cast. get函数将在第一次返回时分支,从不打扰转换。

You can also find the self contained program I used here at pastebin . 你也可以在pastebin找到我在这里使用的自包含程序。

And here is a list of interesting break points you can set to see what's happening (luabind version 900): 这里有一个有趣的断点列表,你可以设置看看发生了什么(luabind版本900):

  • line 94 in instance_holder.hpp (first line of pointer_holder::get) instance_holder.hpp中的第94行(pointer_holder :: get的第一行)
  • line 143 in instance.cpp (first line of cast_graph::impl::cast) instance.cpp中的第143行(cast_graph :: impl :: cast的第一行)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM