2012-06-24 35 views
5

我正試圖編寫一個應用程序,在運行時動態加載其擴展。我使用Boost預處理器庫來編寫一個預處理器函數,給定一個名稱列表,爲每個名稱聲明一個類(並將它們的所有子類作爲AbstractPlugin類的子類),然後聲明包含該類的Boost MPL序列。然後,我寫了一個類,該類嘗試指向AbstractPlugin的指針,如果它可以轉換爲該MPL序列中的任何類型。 這裏的問題是我的預處理器函數需要我想要創建和加載的所有擴展的完整列表。是否有一些技術可以讓我在一個單獨的文件中註冊每個擴展?註冊一個C++類,以便以後一個函數可以遍歷所有註冊的類

更新:

我相信,我的情況的解釋過於含糊,所以我決定把它更加明確。

我想定義一個擴展類型的集合。對於每種擴展類型,可以有任意數量的擴展。在運行期間,程序加載外部庫,解析入口點函數,調用它,結果得到一個指針。然後它試圖將該指針轉換爲所有已註冊的擴展類型(使用dynamic_cast,所以擴展類型的類都從一些多態基類繼承)。如果對某種擴展類型強制轉換成功,則轉換指針將用於對該擴展類型的特殊處理程序的調用。

擴展類型的數量在編譯時是已知的(顯然,擴展的數量是無限的)。使用我的aproach加載器類使用這些知識來檢查是否存在每個擴展類型的處理程序(如果沒有,程序不會編譯)。另外,我的意見並不強制類的擴展類型知道任何關於加載器(所以很容易修改加載器)。但是如果每個擴展類型都註冊了,它會更方便。

+0

正在生成一個頭可接受的解決方案? – Arpegius

回答

0

事實證明,我想要的是不可能的。其原因是在這個上下文中的「註冊」意味着「在類型序列中放置一個類型」,並且類型序列是不可變的,因爲它們本身就是類型。所以人們應該手動創建這種類型的序列,或者一些人建議將「註冊」移動到運行時。

8

你可以讓所有的類在某種集合中自行註冊。這裏有一個骨架的方法:

Base.hpp:

#include <memory> 
#include <unordered_map> 
#include <string> 

struct Base 
{ 
    virtual ~Base() = default; 

    using create_f = std::unique_ptr<Base>(); 

    static void registrate(std::string const & name, create_f * fp) 
    { 
     registry()[name] = fp; 
    } 

    static std::unique_ptr<Base> instantiate(std::string const & name) 
    { 
     auto it = registry().find(name); 
     return it == registry().end() ? nullptr : (it->second)(); 
    } 

    template <typename D> 
    struct Registrar 
    { 
     explicit Registrar(std::string const & name) 
     { 
      Base::registrate(name, &D::create); 
     } 
     // make non-copyable, etc. 
    }; 

private: 
    static std::unordered_map<std::string, create_f *> & registry(); 
}; 

Base.cpp:

#include "Base.hpp" 

std::unordered_map<std::string, Base::create_f *> & Base::registry() 
{ 
    static std::unordered_map<std::string, Base::create_f *> impl; 
    return impl; 
} 

我們在客戶端使用:

派生。 hpp:

#include "Base.hpp" 

struct Derived : Base 
{ 
    static std::unique_ptr<Base> create() { return std::make_unique<Derived>(); } 
    // ... 
}; 

Derived.cpp:

#include "Derived.hpp" 

namespace 
{ 
    Base::Registrar<Derived> registrar("MyClass"); 
} 

Base::Registrar<Derived>的構造函數的名稱"MyClass"下注冊類Derived的照顧。您可以通過動態創建的Derived實例:

std::unique_ptr<Base> p = Base::instantiate("MyClass"); 

的代碼可以/應該通過檢測重複註冊,打印的可用類的列表等。注意我們如何避免我做實際的任何靜態初始化順序的問題得到改善註冊表映射對象是一個塊靜態對象,它保證在第一次使用之前被初始化,並且僅在其最後一次使用之後才被銷燬。

+0

我認爲是這樣的,但我更關心編譯時間的問題。我不確定是否存在一個,但是,C++模板的土地卻充滿了奇蹟。 – grisumbras

+0

沒有靜態的。你不能讓類自己註冊,因爲每個實現文件都有它自己的編譯單元,並且每個文件都可以放在不同的庫中。這個解決方案的強大之處在於,當你加載一個動態庫時,擴展類變成了自動可用的。這是衆所周知的非常有用的模式。 – Arpegius

+0

這是一個非常好的實現。我唯一不理解的是靜態create()函數上的= 0。據我所知,這是無效的C++,因爲靜態函數永遠不會是虛擬的。那部分應該如何工作? – Shenjoku

相關問題