9

私はしばらくの間、この問題 (オンとオフ) に対する創造的な解決策を考え出そうと試みてきましたが、まだできていません。私は最近、テンプレートのメタプログラミングで解決できるかもしれないと考えましたが、テクニックの経験が比較的少ないため確信が持てません.

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

前もって感謝します!

4

3 に答える 3

6

いいえ。これは実際に非常に多く発生する問題であり、私が知る限り、解決策は2つしかありません。

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

2番目の方法は次のようになります。

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> { ... };

これにより、クラスごとに一意のIDが得られます。

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

ただし、これらのIDは遅延して割り当てられるため、呼び出す順序がgetId()IDの返送に影響します。

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

これがアプリケーションに適しているかどうかは、特定のニーズによって異なります(たとえば、シリアル化には適していません)。

于 2011-12-21T21:47:14.820 に答える
2

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

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

ただし、提供したソース コードをスキャンし、必要なディレクティブをソースに挿入する独自の C++ コード プリプロセッサ/分析ツールを作成することもできます。

また、RTTI はすべてのクラスに名前を付けます。問題は、この名前が実装固有であるため、あまり役に立たないことです。

于 2012-03-29T15:52:00.770 に答える
0

私の問題を念頭に置いてこれを投稿しています。ロングポストになります。イベントシステムを書いていて、イベントを一箇所だけ登録したい。

-----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__

-----EventTank.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_IDありEVENT_TYPEます。私がやっていることは、2 つのクラスをメタ構成することです: 開始時に TankEvents の EVENT_TYPE を初期化する AllTankEvents と、EVENT_ID を初期化する AllEvents です。このがらくたのユーザーが行う必要があるのは、別の Tank Event 定義を追加し、それをEVENTS_ALL__typelist に追加することです。などのコードでイベントをディスパッチできますif (event.EVENT_ID==EventTank1::EVENT_ID)。他のコードは、およびでEVENT_ID/EVENT_TYPE初期化されることに注意することができます。C プリプロセッサ マクロを恐れないでください。それらは単なる砂糖なので、いくつかのタスクを自動化できます。見てください、私は今行かなければなりません。EVENT_ID_INITIAL/EVENT_TYPE_INITIALassert

于 2012-03-29T15:01:32.573 に答える