2016-01-18 58 views
2

我在想如何創建一個從模板基類派生的所有類的列表。C++編譯一個類的子類的時間列表

首先,我想有一個模板的基類:

template <typename T> 
class Base 
{ 
public: 
    Base() {}; 
    virtual ~Base() {}; 
}; 

,並從基本模板類繼承的類:

class Foo : public Base<Foo > 
{ 
public: 
    Foo() {}; 
    virtual ~Foo() {}; 
}; 

可能有任意數量的其他子像Foo的。結果應該是這樣的:

std::vector<std::string> allTemplates = Base<Base>::getAllTemplateClasses(); 

我的問題是如果它可能在編譯時創建所有子類的列表?魔術應該發生在基礎課程中,或者在兒童課程中付出很少的努力。

以前我在想不同的方向。首先,我認爲可以使用constexpr。像每一個子類需要與簽名靜態函數:

constexpr static std::string name() { "Foo";} 

或者想也許這是可能的元編程和創造這樣的A Compile Time Data Structure Using,Template-Meta爲例編譯時間列表。這裏的問題是,我不知道模板創建的頭。

接下來我正在考慮使用宏並像這樣建立一個枚舉結構Enum structs expanding。所以我找不到任何解決這個問題的方法,我想問你是否有可能?

編輯:

爲了說清楚:我想有孩子的對象列表,而無需創建它們。

+0

好吧,我刪除了我的答案,因爲它不工作。缺少的部分是這裏描述的:http://stackoverflow.com/questions/5803953/static-constructor-in-c'// C++需要從外部定義靜態成員。 has_static_constructor ::構造函數has_static_constructor :: cons;'註冊器對象實際上並沒有在靜態初始化中構造,因爲當它出現在模板類中時,它只是一個聲明而不是一個定義。我仍然認爲這個靜態註冊的東西是要走的路,但是你需要用宏觀方法來做一些醜陋的事情。 –

+0

(宏的要點是,當你聲明一個類是這個基類的一個子類時,你還希望在類定義之外聲明一個靜態註冊器類型對象,它的構造函數註冊它的名字,宏應該幫助確保這兩件事情一起發生,但是,如果這是一個足夠好的解決方案,無論如何都值得寫出來。) –

+0

就像一個額外的評論 - 我會感興趣,如果有一個優雅的方式來做這,但現在我不敢打賭,真的有一個。 –

回答

3

有了這個不錯的文章static constructor和一個類似於這個的答案,我找到了一個解決方案。神奇的是靜態的構造函數。首先,我將不得不創建其持有的子類的容器,並添加子類:所以現在我們要創建一個靜態類添加字符串到

// base.cpp 

std::set<std::string> &get_objects() 
{ 
    static std::set<std::string> theSet; 
    return theSet; 
} 

void add_object(const char *name) 
{ 
    get_objects().emplace(name); 
} 

//base.h 
std::set<std::string> &get_objects(); 
void add_object(const char *name); 

而實現名單。它類似於後static constructor

//base.h 
class StaticClassType { 
public: 
    StaticClassType(const char *name) { 
     // Notify when the static member is created 
     add_object(name); 
    } 
}; 

的基類是一個模板類它創建「StaticClassType」的靜態對象。 C++保證在調用main()之前完成靜態初始化。

//base.h 
template<typename T> 
class Base { 
protected: 
    // Static member in a template class 
    static StaticClassType m; 
    Base() 
    { 
     (void)m; 
    } 
}; 

沒有下一行m犯規得到createad:

template<typename T> 
StaticClassType Base<T>::m = StaticClassType(typeid(T).name()); 

現在,我們可以創建兩個類和主:

class TestClass1 : public Base<TestClass1> { 
public: 
    TestClass1() :Base() {} 
}; 

class TestClass1 : public Base<TestClass1> { 
public: 
    TestClass1() :Base() {} 
}; 

int main() 
{ 
    std::set<std::string> &test = get_objects(); 
    for(auto str : test) 
     std::cout << str.c_str() << std::endl; 
    return 0; 
} 

輸出是沒有任何對象的任何建設:

class TestClass1 
class TestClass2 

有一個想法照顧。我們必須在某處使用m。否則,編譯器會優化代碼並刪除m。我強迫這種行爲通過書面方式構造函數調用:

TestClass1() :Base() {} 

希望你喜歡它,它是不是真的編譯時間,但我們有對象列表,而無需通過書面方式構造做任何事情,並使用基地父類。