2012-05-22 7 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(); 
Typelist을 만들 수 있다면 궁금

은 (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

"베이스"에 대해 계속 이야기를 나누면 정신 착란이 될 수 있습니다. * 기본 클래스가 없습니다. 각각의 새 파생 클래스가 고유 한 개인 기본 유형을 가져 오는 템플릿 *이 있습니다. –

+0

또한 글로벌 범위에서'addInstance'를 호출 할 때'm_derivedInstances'가 이미 초기화되었다고 보장하기를 원합니까? – Griwes

답변

3

의사 유형 맵을 사용하여 수행 할 수 있습니다. 다음은 boost :: mpl을 사용한 몇 가지 예제 코드입니다. "Implem"의 명시 적 정의는 각 해당 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

그래, 내가 다른 방법으로 생각하려고 노력할 것이다. –