2012-05-03 57 views
9

的shared_ptr我有一個API(特定的GUI庫)依賴於std::shared_ptr很多,即,它們經常被用來作爲函數的參數和存儲的其他對象中。例如,容器小部件(如拆分器和框)將在shared_ptrs中存儲其子部件。現在我想通過luabind將這個API映射到Lua。在理想的世界中,Luabind會在shared_ptrs中創建新的對象,並允許我直接將這些對象傳遞給採用shared_ptr參數的函數。這似乎爲單班工作,例如:使用luabind和std ::與繼承

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

雖然我宣佈會這樣,我可以公開和使用功能,如void foo(std::shared_ptr<Button> const&)

現在luabind手冊中提到,爲了使用的類層次,我必須在層次結構中,例如使用相同的shared_ptr模板實例的所有類

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

現在我不能再打電話foo - 它將無法從Lua中找到該函數。我能以某種方式獲得luabind以支持shared_ptr s中的傳遞按鈕嗎?另外,我想知道爲什麼Luabind要求您爲層次結構中的所有類使用相同的智能指針,而不是將它們轉換爲基類指針。

+0

難道不應該二線使用'的std :: shared_ptr的''不是的std :: shared_ptr的

+0

是的 - 謝謝!只是一個類型壽! – ltjax

回答

7

我覺得這工作,你有你的派生類綁定是這樣的:

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

例如:

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) 
     ]; 
    } 
}; 

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; 
    } 
}; 

現在你可以用shared_ptr的使用

在Lua:

b = Button() 

a = Action() 

a:DoClick(b) 

其原因是,使用luabind型-ID系統與整數(更精確的std ::的size_t如inheritance.hpp定義)。
您可以獲取任何註冊類型的類型ID與功能:

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

其中T是註冊類。
以我演示程序,他們是:

  • BaseWidget = 3
  • 的std :: shared_ptr的< BaseWidget> = 6
  • 按鈕= 4
  • 的std :: shared_ptr的<鈕釦> = 7
  • Action = 5

因此,當您從lua調用DoClick時,它將調用t的get成員他模板類pointer_holder在instance_holder.hpp:

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 
    ); 
} 

正如你所看到的,如果目標類是不一樣註冊一個,它會嘗試做一個演員。
這是事情變得有趣的地方。 如果你聲明的Button類爲

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

那麼實例將舉行一個shared_ptr來BaseWidget,因此投功能將嘗試從BaseWidget投(3)到std :: shared_ptr的<按鈕>(7 )並且失敗。它可以工作,如果luabind支持基於衍生的轉換,它似乎並不如此。

然而,如果你聲明的Button類爲

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

那麼實例將持有作爲一個shared_ptr到按鈕,然後目標ID將在註冊類型相匹配。 get函數將在第一次返回時分支,從不打擾演員。

您還可以找到我使用的自包含程序here at pastebin

這裏是有趣的破發點的列表,您可以設置,看看發生了什麼(luabind版本900):在instance_holder.hpp

  • 線94(pointer_holder的第一行::獲得)
  • 在instance.cpp(cast_graph :: IMPL ::鑄造的第一行)線143
+0

我實際上爲get_pointer添加了那些重載。它確實通過了smart_pointer(我可以說,因爲如果我多次調用這些函數,引用計數是正確的) – ltjax

+0

另外,傳遞原始指針更加笨拙,因爲我想存儲指針,而不僅僅是對它們執行函數。對於那項工作,我不得不修改GUI對象層次結構以從enable_shared_from_this派生。 – ltjax

+0

但是,對於您當前的解決方案,您忽略了luabind手冊強制要求使用基類shared_ptr類型:請參見http://www.rasterbar.com/products/luabind/docs.html#smart-pointers,最後一段。如果這個「正常工作」,我想知道爲什麼... – ltjax