c++ 파이썬 템플릿 메타 프로그래밍으로 계산 하시겠습니까?



파이썬 메타프로그래밍 (3)

나는 한동안이 문제에 대한 창조적 인 해결책을 생각하려고 노력해 왔지만 아직까지는 할 수 없었습니다. 나는 최근에이 기술에 대한 나의 경험이 부족하기 때문에 확신 할 수는 없지만 그것이 템플릿 메타 프로그래밍으로 풀릴 수 있다고 생각했다.

템플릿 메타 프로그래밍 (또는 C ++ 언어의 다른 메커니즘)을 사용하여 일부 기본 클래스에서 파생 된 클래스의 수를 계산하여 각 파생 클래스에 고유 한 정적 클래스 식별자가 부여되도록 할 수 있습니까?

미리 감사드립니다!


템플릿 메타 프로그래밍 (또는 C ++ 언어의 다른 메커니즘)을 사용하여 일부 기본 클래스에서 파생 된 클래스의 수를 계산하여 각 파생 클래스에 고유 한 정적 클래스 식별자가 부여되도록 할 수 있습니까?

아니요, 그런 메커니즘은 없습니다. 당신이 무엇을 하든지 상관없이, 파생 된 모든 클래스에 "무언가"(대개 매크로)를 추가 해야 합니다. Qt 4 및 Q_OBJECT 매크로를 참조하십시오. 파생 클래스를 만들기위한 매크로를 만들 수도 있지만 자동으로 수행 할 수는 없습니다.

그러나 제공 한 소스 코드를 스캔 한 다음 필요한 지시문을 소스에 삽입하는 자체 C ++ 코드 전 처리기 / 분석 도구를 작성할 수 있습니다.

또한 RTTI는 모든 클래스의 이름을 제공합니다. 문제는이 이름이 구현에 따라 다르기 때문에 매우 유용하지 않다는 것입니다.


아니요. 이것은 실제로 많이 발생하는 문제입니다. 알고있는 한 두 가지 해결책 만 있습니다.

  1. 파생 된 각 클래스에 ID를 수동으로 할당합니다.
  2. 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> { ... };

이렇게하면 각 클래스에 고유 한 ID가 부여됩니다.

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

그러나 이러한 ID는 lazily로 할당되므로 getId() 를 호출하는 순서는 반환 된 ID에 영향을줍니다.

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

이것이 당신의 어플리케이션에 적합한 지 여부는 당신의 특별한 요구에 달려있다. (예를 들어 직렬화에 좋지는 않다).


내 문제를 염두에두고 게시하고 있습니다. 긴 게시물 일 것입니다. 나는 사건 체계를 쓰고 있는데, 한 곳에서만 사건을 등록하고 싶다.

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

이것은 많은 코드이므로, 요약하려고 노력할 것입니다. EVENT_IDEVENT_TYPE 이라는 두 가지 중요한 멤버가있는 기본 클래스 EventBase 가 있습니다. 내가하고있는 일은 두 클래스를 메타 - 컴파일하는 것이다. AllTankEvents는 instatiation시 TankEvents에 대해 EVENT_TYPE을 초기화하고 AllEvents는 EVENT_ID를 초기화한다. 이 쓰레기 중 어떤 사용자는 다른 탱크 이벤트 정의를 추가하고이를 EVENTS_ALL__ 에 추가해야합니다. if (event.EVENT_ID==EventTank1::EVENT_ID) 등의 코드로 이벤트를 디스패치 할 수 있습니다. 다른 코드는 EVENT_ID/EVENT_TYPE 초기화되고 assert 하는 EVENT_ID_INITIAL/EVENT_TYPE_INITIAL 있습니다. C 프리 프로세서 매크로를 두려워하지 마십시오. 그들은 단지 설탕이므로 일부 작업을 자동화 할 수 있습니다. 보세요, 이제 가야 해요.





template-meta-programming