2011-12-21 37 views
9

Tôi đã cố gắng nghĩ ra một giải pháp sáng tạo cho vấn đề này (và tắt) trong một thời gian, nhưng tôi vẫn chưa thể. Gần đây tôi đã xem xét rằng nó có thể được giải quyết với lập trình meta mẫu, mặc dù tôi không chắc chắn do thiếu kinh nghiệm tương đối của tôi với kỹ thuật này.Đếm với Lập trình meta mẫu?

Có thể sử dụng lập trình meta mẫu (hoặc bất kỳ cơ chế nào khác với ngôn ngữ C++) để đếm số lớp được bắt nguồn từ một số lớp cơ sở sao cho mỗi lớp dẫn xuất được cấp một mã định danh lớp duy nhất?

Cảm ơn trước!

+0

là các id tĩnh là yêu cầu hoặc bạn đã đặt chúng ở đó vì bạn cho rằng chúng là một phần của giải pháp? một giải pháp lý tưởng cho vấn đề này có lẽ sẽ không cần những id này, và sẽ dựa vào hệ thống kiểu thay thế. nghĩa là, tên của các lớp sẽ là các số nhận dạng tĩnh duy nhất. – wilhelmtell

+0

Tôi đang cố gắng tránh RTTI và ở trong C++. –

+0

@ DanM.Katz: Có thể tôi đã thực hiện những gì bạn muốn. Đăng ở đây nếu bạn vẫn quan tâm. –

Trả lời

6

số này là một vấn đề mà đi lên trong thực tế khá nhiều, và như xa như tôi biết chỉ có hai giải pháp:

  1. thủ gán ID cho mỗi lớp dẫn xuất.
  2. Tạo ID một cách linh hoạt và lười biếng không xác định.

Cách bạn làm điều thứ hai là một cái gì đó như thế này:

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

này cung cấp cho bạn ID duy nhất cho mỗi lớp:

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

Tuy nhiên, những ID được giao một cách lười biếng, vì vậy thứ tự bạn gọi getId() ảnh hưởng đến ID được trả lại.

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

Điều này có phù hợp với ứng dụng của bạn hay không tùy thuộc vào nhu cầu cụ thể của bạn (ví dụ: sẽ không tốt cho việc tuần tự hóa).

+0

Vâng, tuần tự hóa là mục tiêu của tôi. Tôi cảm thấy như thế này nên có thể mặc dù ... –

0

Tôi đang đăng sự cố này với sự cố của mình. Nó sẽ được đăng bài dài. Tôi đang viết hệ thống sự kiện và tôi chỉ muốn đăng ký sự kiện ở một nơi.

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

Và không phải là công cụ thú vị ...

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

Do đây là rất nhiều mã, tôi sẽ cố gắng tóm tắt. Tôi có một lớp cơ sở EventBase có hai thành viên quan trọng: EVENT_IDEVENT_TYPE. Những gì tôi đang làm là để meta-soạn hai lớp: AllTankEvents mà khi instatiation khởi tạo EVENT_TYPE cho TankEvents, và AllEvents khởi tạo EVENT_ID. Những gì người dùng của crap này cần phải làm, là thêm một định nghĩa sự kiện xe tăng, và để thêm nó vào EVENTS_ALL__ typelist. Bạn có thể gửi các sự kiện có mã như if (event.EVENT_ID==EventTank1::EVENT_ID) v.v. Mã khác có thể xem ra cho EVENT_ID/EVENT_TYPE được khởi tạo với EVENT_ID_INITIAL/EVENT_TYPE_INITIALassert. Đừng sợ các macro tiền xử lý trước. Họ chỉ là một đường, vì vậy tôi có thể tự động hóa một số nhiệm vụ. Hãy xem, tôi phải đi ngay bây giờ.

2

Có thể sử dụng lập trình meta mẫu (hay bất kỳ cơ chế nào khác với ngôn ngữ C++) để đếm số lớp được bắt nguồn từ một số lớp cơ sở sao cho mỗi lớp dẫn xuất được cấp một mã định danh lớp duy nhất?

Không, không có cơ chế như vậy. Không có vấn đề gì bạn làm, bạn sẽ phải thêm "một cái gì đó" (rất có thể là một macro) cho mỗi lớp dẫn xuất thủ công để đạt được một cái gì đó như thế. Xem macro Qt 4 và Q_OBJECT. Bạn cũng có thể tạo một macro để tạo các lớp dẫn xuất, nhưng điều này không thể được thực hiện tự động.

Bạn có thể tuy nhiên, hãy viết công cụ phân tích/xử lý mã C++ của riêng bạn quét mã nguồn bạn cung cấp rồi chèn chỉ thị cần thiết vào nguồn.

Ngoài ra, RTTI cung cấp tên cho mọi lớp học. Vấn đề là tên này được thực hiện cụ thể, do đó, nó không phải là rất hữu ích.

Các vấn đề liên quan