2011-12-21 10 views
9

मैं कुछ समय के लिए इस समस्या (चालू और बंद) के लिए एक रचनात्मक समाधान सोचने की कोशिश कर रहा हूं, लेकिन मैं अभी तक सक्षम नहीं हूं। मैंने हाल ही में माना है कि यह टेम्पलेट मेटाप्रोग्रामिंग के साथ हल करने योग्य हो सकता है, हालांकि मुझे यकीन नहीं है कि तकनीक के साथ अनुभव की मेरी सापेक्ष कमी के कारण।टेम्पलेट मेटाप्रोग्रामिंग के साथ गिनती?

क्या कुछ बेस क्लास से प्राप्त कक्षाओं की संख्या को गिनने के लिए टेम्पलेट मेटाप्रोग्रामिंग (या सी ++ भाषा के साथ कोई अन्य तंत्र) का उपयोग करना संभव है, जैसे कि प्रत्येक व्युत्पन्न वर्ग को अद्वितीय, स्थैतिक वर्ग पहचानकर्ता दिया जाता है?

अग्रिम धन्यवाद!

+0

स्थैतिक आईडी एक आवश्यकता है या आपने उन्हें वहां रखा है क्योंकि आपको लगता है कि वे समाधान का हिस्सा हैं? इस समस्या का एक आदर्श समाधान शायद इन आईडी की आवश्यकता नहीं होगी, और इसके बजाय टाइप सिस्टम पर निर्भर करेगा। यानी, वर्ग के नाम स्वयं अद्वितीय स्थिर पहचानकर्ता के रूप में कार्य करेंगे। – wilhelmtell

+0

मैं आरटीटीआई से बचने और सी ++ के भीतर रहने की कोशिश कर रहा हूं। –

+0

@ DanM.Katz: शायद मैंने जो भी आप चाहते हैं बनाया है। यदि आप अभी भी रुचि रखते हैं तो यहां पोस्ट करें। –

उत्तर

6

नहीं। यह एक समस्या यह है कि व्यवहार में काफी एक बहुत ऊपर आता है, और जहाँ तक मुझे पता है हूँ केवल दो समाधान हैं:

  1. मैन्युअल प्रत्येक व्युत्पन्न वर्ग को आईडी निर्दिष्ट।
  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> { ... }; 

यह आपको प्रत्येक वर्ग के लिए अद्वितीय आईडी देता है:

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

हालांकि, उन आईडी lazily आवंटित कर रहे हैं, इसलिए जिस आदेश को आप getId() पर कॉल करते हैं, वह आईडी की वापसी को प्रभावित करता है।

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

या नहीं, यह आपके आवेदन के लिए ठीक है अपने विशेष जरूरतों पर निर्भर करता है (उदाहरण के लिए क्रमांकन के लिए अच्छा नहीं होगा)।

+0

हाँ, serialization मेरा लक्ष्य है। मुझे लगता है कि यह संभव होना चाहिए हालांकि ... –

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__ 

----- 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 है जिसमें दो महत्वपूर्ण सदस्य हैं: EVENT_ID और EVENT_TYPE। मैं जो कर रहा हूं वह मेटा-दो वर्गों को लिखना है: AllTankEvents जो इंस्टाटेशन पर टैंकवेन्ट्स के लिए EVENT_TYPE प्रारंभ करते हैं, और AllEvents EVENT_ID प्रारंभ करते हैं। बकवास के इस टुकड़े के उपयोगकर्ता को क्या करना है, एक और टैंक इवेंट परिभाषा जोड़ना है, और इसे EVENTS_ALL__ टाइपलिस्ट में जोड़ना है। आप if (event.EVENT_ID==EventTank1::EVENT_ID) जैसे कोड के साथ ईवेंट प्रेषित कर सकते हैं और इसी तरह। अन्य कोड EVENT_ID/EVENT_TYPE के लिए EVENT_ID_INITIAL/EVENT_TYPE_INITIAL और assert के साथ प्रारंभ किया जा सकता है। सी प्री-प्रोसेसर मैक्रोज़ से डरो मत। वे सिर्फ चीनी हैं, इसलिए मैं कुछ कार्यों को स्वचालित कर सकता हूं। एक नज़र डालें, मुझे अभी जाना है।

2

यह टेम्पलेट metaprogramming (या सी ++ भाषा के साथ किसी अन्य तंत्र) का उपयोग करने के इस तरह के प्रत्येक व्युत्पन्न वर्ग एक अद्वितीय, स्थिर वर्ग पहचानकर्ता दिया जाता है कि जो कुछ आधार वर्ग से प्राप्त कर रहे वर्गों की संख्या की गणना करना संभव है?

नहीं, ऐसी कोई व्यवस्था नहीं है। कोई फर्क नहीं पड़ता कि आप क्या करते हैं, आपको कुछ व्युत्पन्न कक्षा मैन्युअल रूप से पर कुछ ऐसा करने के लिए "कुछ" (संभवतः एक मैक्रो) जोड़ना होगा। क्यूटी 4 और Q_OBJECT मैक्रो देखें। आप व्युत्पन्न कक्षाएं बनाने के लिए मैक्रोज़ भी बना सकते हैं, लेकिन यह स्वचालित रूप से नहीं किया जा सकता है।

आप हालांकि अपने स्वयं के सी ++ कोड प्रीप्रोसेसर/विश्लेषण उपकरण लिख सकते हैं जो आपके द्वारा प्रदत्त स्रोत कोड स्कैन करता है और फिर स्रोत में आवश्यक निर्देशों को सम्मिलित करता है।

इसके अलावा, आरटीटीआई प्रत्येक वर्ग के लिए नाम प्रदान करता है। समस्या यह है कि यह नाम कार्यान्वयन-विशिष्ट है, इसलिए यह बहुत उपयोगी नहीं है।

संबंधित मुद्दे