2011-12-21 5 views
9

私はしばらくの間、この問題に対する創造的な解決策を考えることを試みてきましたが、私はまだできていません。私は最近、テンプレートのメタプログラミングで解決できるかもしれないと考えましたが、私はこの技術の経験が比較的少ないために確信が持てません。テンプレートメタプログラミングによるカウント?

テンプレートメタプログラミング(またはC++言語の他のメカニズム)を使用して、いくつかの基本クラスから派生したクラスの数を数えて、各派生クラスに一意の静的クラス識別子が与えられるようにすることはできますか?

ありがとうございます!

+0

は静的IDですか、ソリューションの一部だと思ってそこに配置しましたか?この問題に対する理想的な解決法はおそらくこれらのIDを必要とせず、代わりに型システムに依存するでしょう。つまり、クラス名自体が一意の静的識別子として機能します。 – wilhelmtell

+0

私はRTTIを避け、C++内にとどまっています。 –

+0

@ DanM.Katz:多分私はあなたが望むものを作った。あなたがまだ興味があるなら、ここに投稿してください。 –

答えて

6

いいえ。これは実際にはかなり多くのことをアップします問題であり、私の知る限り承知しているとして2つしか解決策があります。

  1. は手動で各派生クラスにIDを割り当てます。
  2. IDを非決定論的に動的かつ遅延して生成します。そう、

    Derived1::getStaticId(); // 0 
    Derived2::getStaticId(); // 1 
    Derived3::getStaticId(); // 2 
    

    しかし、それらのIDを遅延割り当てられています。これはあなたのクラスごとに固有のIDを与える

    class Base 
    { 
        virtual int getId() const = 0; 
    }; 
    
    // Returns 0, 1, 2 etc. on each successive call. 
    static int makeUniqueId() 
    { 
        static int id = 0; 
        return id++; 
    } 
    
    template <typename Derived> 
    class BaseWithId : public Base 
    { 
        static int getStaticId() 
        { 
         static int id = makeUniqueId(); 
         return id; 
        } 
    
        int getId() const { return getStaticId(); } 
    }; 
    
    class Derived1 : public BaseWithId<Derived1> { ... }; 
    class Derived2 : public BaseWithId<Derived2> { ... }; 
    class Derived3 : public BaseWithId<Derived3> { ... }; 
    

2番目のいずれかを実行方法は、このようなものですあなたがgetId()と呼んでいる注文が返されたIDに影響します。

Derived3::getStaticId(); // 0 
Derived2::getStaticId(); // 1 
Derived1::getStaticId(); // 2 

アプリケーションに問題がないかどうかは、必要に応じて異なります(たとえば、シリアル化には適しません)。

+0

ええ、シリアル化は私の目標です。私はこれが可能でなければならないように感じる... –

0

私はこれを念頭に置いて掲示しています。それは長いポストになります。 私はイベントシステムを作成しています。イベントを1か所に登録したいのです。

----- ----- Event.h

typedef int EventAddress; 
typedef int EventId; 
typedef int EventType; 

static const EventAddress EVENT_FROM_ALL=-1; 
static const EventAddress EVENT_TO_ALL=-1; 

static const EventId EVENT_ID_INITIAL=-1; 
static const EventType EVENT_TYPE_INITIAL=-1; 

static const EventId EVENT_ID_ALL=0; 
static const EventType EVENT_TYPE_ALL=0; 

struct Event 
{ 
    public: 
     EventId eventId; 
     EventType eventType; 
     EventAddress from; 

     Event(const EventId eventId, const EventType eventType): 
      eventId(eventId), 
      eventType(eventType) 
     { 
     } 

     virtual ~Event() 
     { 
     } 

     virtual std::string asString()=0; 

    private: 
     Event(); 
}; 

template <class T> 
struct EventBase 
     :public Event 
{ 
    static int EVENT_ID; 
    static int EVENT_TYPE; 

    EventBase(): 
     Event(EVENT_ID,EVENT_TYPE) 
    { 
    } 
}; 
template <class T> 
int EventBase<T>::EVENT_ID=EVENT_ID_INITIAL; 

template <class T> 
int EventBase<T>::EVENT_TYPE=EVENT_TYPE_INITIAL; 

/// Events All 
struct EventAll: 
     public Event 
{ 
    static int EVENT_ID; 
    static int EVENT_TYPE; 

    EventAll(): 
     Event(EVENT_ID,EVENT_TYPE) 
    { 
    } 

    virtual std::string asString() 
    { 
     return __PRETTY_FUNCTION__; 
    } 
}; 

----- ----- Event.cpp

#include "Event.h" 

int EventAll::EVENT_ID=EVENT_ID_ALL; 
int EventAll::EVENT_TYPE=EVENT_TYPE_ALL; 

------ EventGenerator.h ------

struct EventIdGenerator 
{ 
    int generator; 
    EventIdGenerator(): 
     generator(0) 
    { 

    } 
}; 

template <class T, class Base> 
struct UnitId: 
     virtual public Base, 
     public T 
{ 
    UnitId() 
    { 
     ++Base::generator; 
     T::EVENT_ID=Base::generator; 
    } 
}; 

struct EventTypeGenerator 
{ 
    static int generator; 
}; 

template <class T, class Base> 
struct UnitType: 
     virtual public Base, 
     public T 
{ 
    UnitType() 
    { 
     T::EVENT_TYPE=Base::generator; 
    } 
}; 

----- ----- EventGenerator.cpp

#include "EventGenerator.h" 

int EventTypeGenerator::generator=0; 

ではなく、楽しいもの...

----- ----- EventsTank.h

#include <loki/Typelist.h> 
#include <loki/HierarchyGenerators.h> 

#include "Event.h" 
#include "EventGenerator.h" 

#define EVENT_CONTEXT__ Tank 

#define EVENT_NAME__ EventTank1 
struct EVENT_NAME__: 
     public EventBase<EVENT_NAME__> 
{ 
    std::string s; 
    double b; 
    void f() 
    { 
    } 

    virtual std::string asString() 
    { 
     return __PRETTY_FUNCTION__; 
    } 
}; 
#undef EVENT_NAME__ 



#define EVENT_NAME__ EventTank2 
struct EVENT_NAME__: 
     public EventBase<EVENT_NAME__> 
{ 
    std::string s; 
    double b; 
    void f() 
    { 
    } 

    virtual std::string asString() 
    { 
     return __PRETTY_FUNCTION__; 
    } 
}; 
#undef EVENT_NAME__ 



#define EVENT_NAME__ EventTank3 
struct EVENT_NAME__: 
     public EventBase<EVENT_NAME__> 
{ 
    std::string s; 
    double b; 
    void f() 
    { 
    } 

    virtual std::string asString() 
    { 
     return __PRETTY_FUNCTION__; 
    } 
}; 
#undef EVENT_NAME__ 

#define TOKENPASTE(x, y, z) x ## y ## z 
#define TOKENPASTE2(x, y, z) TOKENPASTE(x, y, z) 

#define EVENTS_ALL__ TOKENPASTE2(Events,EVENT_CONTEXT__,All) 


template <typename...Ts> 
struct TYPELIST; 

template <> 
struct TYPELIST<> 
{ 
    typedef Loki::NullType Result; 
}; 

template <typename HEAD, typename...Ts> 
struct TYPELIST<HEAD,Ts...> 
{ 
    typedef Loki::Typelist<HEAD, typename TYPELIST<Ts...>::Result> Result; 
}; 

typedef TYPELIST< 
     EventTank1, 
     EventTank2, 
     EventTank3 
    >::Result EVENTS_ALL__; 

/// Do not change below--------------------------------------------------------------------- 

#define EVENT_CONTEXT_ALL__ TOKENPASTE2(Event,EVENT_CONTEXT__,All) 
struct EVENT_CONTEXT_ALL__: 
     public EventBase<EVENT_CONTEXT_ALL__> 
{ 
    virtual std::string asString() 
    { 
     return __PRETTY_FUNCTION__; 
    } 
}; 

#define EVENT_ALL_REVERSED__ TOKENPASTE2(Event,EVENT_CONTEXT__,AllReversed) 
typedef Loki::TL::Reverse<EVENTS_ALL__>::Result EVENT_ALL_REVERSED__; 

#define EVENT_ALL_REVERSED_FIRST__ TOKENPASTE2(Event,EVENT_CONTEXT__,AllReversedFirst) 
typedef Loki::TL::TypeAt<EVENTS_ALL__,0>::Result EVENT_ALL_REVERSED_FIRST__; 

template <class Base> 
struct UnitType<EVENT_ALL_REVERSED_FIRST__,Base>: 
     virtual public Base, 
     public EVENT_ALL_REVERSED_FIRST__ 
{ 
    typedef EVENT_ALL_REVERSED_FIRST__ T; 
    UnitType() 
    { 
     std::cout << __PRETTY_FUNCTION__ << std::endl; 
     ++Base::generator; 
     T::EVENT_TYPE=Base::generator; 
     EVENT_CONTEXT_ALL__::EVENT_ID=EVENT_ID_ALL; 
     EVENT_CONTEXT_ALL__::EVENT_TYPE=Base::generator; 
    } 
}; 

#define ALL_CONTEXT_EVENTS__ TOKENPASTE2(All,EVENT_CONTEXT__,Events) 
typedef Loki::GenLinearHierarchy<EVENT_ALL_REVERSED__,UnitType,EventTypeGenerator> ALL_CONTEXT_EVENTS__; 

#undef ALL_CONTEXT_EVENTS__ 
#undef EVENT_ALL_REVERSED__ 
#undef EVENT_ALL_REVERSED_FIRST__ 
#undef EVENT_NAME_ALL__ 
#undef EVENTS_ALL__ 

----- ----- EventsTank.cpp

#include "EventsTank.h" 

AllTankEvents allTankEvents; 

----- ----- EventRegisterer.cpp

#include <loki/Typelist.h> 
#include <loki/HierarchyGenerators.h> 

#include "../core/Event.h" 

#include "EventsTank.h" 

typedef Loki::GenLinearHierarchy<Loki::TL::Reverse<EventsTankAll>::Result,UnitId,EventIdGenerator> AllEvents; 
AllEvents allEvents; 

これはコードがたくさんあるので、私は要約しようとします。 私は基本クラスEventBaseを持っています。このクラスは2人の重要なメンバー: EVENT_IDEVENT_TYPEを持っています。私がやっていることは、2つのクラスをメタ作成することです:AllTankEventsは、instatiationでTankEventsのEVENT_TYPEを初期化し、AllEventsはEVENT_IDを初期化します。 このような邪魔者は、別のタンクイベント定義を追加し、それをタイプリストEVENTS_ALL__に追加する必要があります。 if (event.EVENT_ID==EventTank1::EVENT_ID)などのコードでイベントを送出することができます。 他のコードは、EVENT_ID/EVENT_TYPEについては、EVENT_ID_INITIAL/EVENT_TYPE_INITIALassertで初期化されています。 Cプリプロセッサマクロを恐れてはいけません。彼らはただの砂糖なので、私はいくつかのタスクを自動化することができます。 見て、私は今行く必要があります。

2

テンプレートメタプログラミング(またはC++言語の他のメカニズム)を使用して、いくつかの基本クラスから派生したクラスの数をカウントして、各派生クラスに一意の静的クラス識別子が与えられるようにすることはできますか?

いいえ、そのようなメカニズムはありません。あなたが何をしていても、派生クラスすべてに「何か」(おそらくマクロ)を追加する必要があります。これを実現するにはQt 4とQ_OBJECTマクロを参照してください。派生クラスを作成するためのマクロを作成することもできますが、これは自動的には実行できません。

ただし、提供したソースコードをスキャンしてソースに必要なディレクティブを挿入する独自のC++コードプリプロセッサ/解析ツールを作成してください。

また、RTTIはすべてのクラスの名前を提供します。問題は、この名前は実装固有であるため、それほど有用ではないということです。

関連する問題