2016-01-18 31 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() {} 

希望你喜欢它,它是不是真的编译时间,但我们有对象列表,而无需通过书面方式构造做任何事情,并使用基地父类。