2012-05-22 89 views
2

使用CRTP(好奇地重复出现的模板模式),您可以提供基类,并具有从中派生的类的知识。这并不是说很难创建存储各从基类派生的类的实例的阵列(见实施例)C++派生类的类型列表

class Base{ 
    public: 
     static std::vector<Base *> m_derivedInstances; 
}; 

template <class Derived> 
class CRTPBase : public Base { 
    public: 
     static bool m_temp; 
     static bool addInstance() 
     { 
      m_derivedInstances.push_back(new Derived); 
      return true; 
     } 
}; 
template <class Derived> 
CRTPBase<Derived>::m_temp = CRTPBase<Derived>::addInstance(); 

我想知道是否有可能创建类型串(见http://www.research.ibm.com/designpatterns/pubs/ph-jun00.pdf)所有的派生类的类型。问题是每次编译器看到一个派生自Base的新类时,它都需要在列表中追加一个新类型,但是类型列表是不可变的(可以创建一个新列表,并附加新类型,但是添加元素的列表是不可能的,因为据我所知,最后,我想有这样的事情:

struct DerivedClassHolder { 
    typedef Loki::TL::MakeTypeList</*list all derived classes here*/>::Result DerivedTypes; 
}; 

的最终目标是要能够通过遍历所有从Base派生的类

+2

什么是“迭代所有类”*是指*? –

+0

如果你一直在谈论“The Base”,那么你可能在错误的心理轨道上。你*没有*基类。你有一个* template *,每个新的派生类从中获得它自己的个人基类型。 –

+0

另外,如何确保在全局范围内调用'addInstance'时已经初始化了'm_derivedInstances'? – Griwes

回答

3

可以使用伪类型映射来完成。这里是一些使用boost :: mpl的示例代码。 “Implem”的明确定义可以用每个相应的实现头中的宏来完成。

#include <iostream> 
#include <boost/mpl/vector.hpp> 
#include <boost/mpl/eval_if.hpp> 
#include <boost/mpl/identity.hpp> 
#include <boost/mpl/for_each.hpp> 
#include <boost/mpl/push_front.hpp> 
#include <boost/mpl/empty_sequence.hpp> 
#include <boost/type_traits/is_same.hpp> 

using namespace boost::mpl; 
using namespace boost; 


// A type map. Implem #N of type Key is type (default: void) 

template <typename Key, int N> 
struct Implem 
{ 
    public: 
    typedef void type; 
}; 


// Type vector building functions 
// void, the default type, is used to stop the recursion 

template <typename Key, int N = 1> 
struct ImplemToList; 

template <typename Key, typename Item, int N> 
struct ImplemListItem 
{ 
    public: 
    typedef typename push_front<typename ImplemToList<Key, N + 1>::type, Item>::type type; 
}; 

template <typename Key, int N> 
struct ImplemToList 
{ 
    public: 
    typedef typename Implem<Key, N>::type item; 
    typedef typename eval_if<is_same<item, void>, 
          identity<vector<> >, 
          ImplemListItem<Key, item, N> >::type type; 
}; 


// Example code: an interface with two implems 

class Interface 
{ 
    public: 
    virtual const char* name() const = 0; 
}; 

class Implem1 : public Interface 
{ 
    public: 
    virtual const char* name() const { return "implem_1"; } 
}; 

class Implem2 : public Interface 
{ 
    public: 
    virtual const char* name() const { return "implem_2"; } 
}; 

template <> 
struct Implem<Interface, 1> 
{ 
    public: 
    typedef Implem1 type; 
}; 

template <> 
struct Implem<Interface, 2> 
{ 
    public: 
    typedef Implem2 type; 
}; 


void print(Interface const& i) 
{ 
    std::cout << i.name() << std::endl; 
} 

int main() 
{ 
    typedef ImplemToList<Interface>::type IList; 
    for_each<IList>(&print); 
} 
+0

谢谢,辉煌! –

2

您的类型列表只能用手工创建。您提到的问题,不可变性,是不可逾越的。

+0

可以说我想创建类型列表,但我希望能够更新列表而不必更改Base或DerivedClassHolder的定义。为列表创建别名的排序,但实际列表可以从外部更改。 –

+0

@BenjyKessler - 你不能改变列表。期。你当然可以随时编译一个新的列表,并使用THAT列表,但是你不能替换已经存在的列表,所以你只需要知道列表中哪些列表包含了它应该包含的所有值。 –

+0

好的,谢谢我会试着去想一些其他的做事方式。 –