2010-05-17 10 views
11

जब एक MessageFactory वर्ग को लागू करने के लिए संदेश वस्तुओं मैं की तरह कुछ इस्तेमाल किया instatiate के संकलन समय पर एक AbstractFactory में निर्माता तरीकों रजिस्टर एक नया XXX_MSG जोड़ने और स्विच स्टेटमेंट को संशोधित करने के लिए।गतिशील रूप से सी ++ का उपयोग कर टेम्पलेट्स

कुछ शोध के बाद मुझे संकलन समय पर संदेशफैक्टरी को गतिशील रूप से अपडेट करने का एक तरीका मिला, इसलिए मैं संदेश संदेशों को संशोधित करने के बिना जितना चाहूं उतने संदेश जोड़ सकता हूं।

#include <stdio.h>                                           
#include <stdlib.h>                                           
#include <string.h>                                           
#include <inttypes.h>                                           

class Message                                             
{                                                
    protected:                                             
     inline Message() {};                                         

    public:                                             
     inline virtual ~Message() { }                                       
     inline int getMessageType() const { return m_type; }                                 
     virtual void say() = 0;                                         

    protected:                                             
     uint16_t m_type;                                          
};                                               

template<int TYPE, typename IMPL>                                        
class MessageTmpl: public Message                                        
{                                                
    enum { _MESSAGE_ID = TYPE };                                        
    public:                                             
     static Message* Create() { return new IMPL(); }                                   
     static const uint16_t MESSAGE_ID; // for registration                                 

    protected:                                             
     MessageTmpl() { m_type = MESSAGE_ID; } //use parameter to instanciate template                           
};                                               

typedef Message* (*t_pfFactory)();                                       
class MessageFactory⋅                                           
{                                                
    public:                                             
    static uint16_t Register(uint16_t msgid, t_pfFactory factoryMethod)                              
    {                                              
     printf("Registering constructor for msg id %d\n", msgid);                                
     m_List[msgid] = factoryMethod;                                       
     return msgid;                                           
    }                                              

    static Message *Create(uint16_t msgid)                                     
    {                                              
     return m_List[msgid]();                                        
    }                                              
    static t_pfFactory m_List[65536];                                      
}; 

template <int TYPE, typename IMPL>                                       
const uint16_t MessageTmpl<TYPE, IMPL >::MESSAGE_ID = MessageFactory::Register(                            
    MessageTmpl<TYPE, IMPL >::_MESSAGE_ID, &MessageTmpl<TYPE, IMPL >::Create);                            

class PingMessage: public MessageTmpl < 10, PingMessage >                                  
{⋅                                               
    public:                                              
    PingMessage() {}                                           
    virtual void say() { printf("Ping\n"); }                                     
};                                               

class PongMessage: public MessageTmpl < 11, PongMessage >                                  
{⋅                                               
    public:                                              
    PongMessage() {}                                           
    virtual void say() { printf("Pong\n"); }                                     
};                                               

t_pfFactory MessageFactory::m_List[65536];                                     

int main(int argc, char **argv)                                        
{                                                
    Message *msg1;                                            
    Message *msg2;                                            

    msg1 = MessageFactory::Create(10);                                       
    msg1->say();                                            

    msg2 = MessageFactory::Create(11);                                       
    msg2->say();                                            

    delete msg1;                                            
    delete msg2;                                            

    return 0;                                             
} 

यहाँ टेम्पलेट करता MessageFactory वर्ग में पंजीकरण से जादू, सभी नए संदेश कक्षाएं: यह क्लीनर और आसान कोड बनाए रखने के लिए के लिए के रूप में मैं जोड़ने के लिए तीन अलग-अलग स्थानों को संशोधित करने की जरूरत नहीं है/संदेश वर्गों को हटाने की अनुमति देता है (उदाहरण के लिए पिंगमेसेज और पोंगमेसेज) जो संदेश टीएमपीएल से उप-वर्ग है।

यह महान काम करता है और कोड रखरखाव सरल करता है लेकिन मैं अभी भी इस तकनीक के बारे में कुछ सवाल हैं:

  1. यह एक ज्ञात तकनीक/पैटर्न है? क्या नाम है? मैं इसके बारे में अधिक जानकारी खोजना चाहता हूं।

  2. मैं नए कंस्ट्रक्टर्स MessageFactory :: m_List [65536] एक std :: नक्शा भंडारण लेकिन करने के लिए सरणी बनाना चाहते तो कारण बनता कार्यक्रम भी मुख्य तक पहुँचने से पहले SEGFAULT लिए()। 65536 तत्वों की एक सरणी बनाना ओवरकिल है लेकिन मुझे पर कोई डायनामिक कंटेनर नहीं मिला है।

  3. संदेश संदेश के उप-वर्ग वाले सभी संदेश वर्गों के लिए मुझे निर्माता को कार्यान्वित करना होगा। यदि नहीं, तो यह संदेश फैक्टरी में पंजीकृत नहीं होगा।

    उदाहरण के लिए

    PongMessage के निर्माता टिप्पणी:

    class PongMessage: public MessageTmpl < 11, PongMessage >  
    {                                               
        public:                                              
        //PongMessage() {} /* HERE */                                           
        virtual void say() { printf("Pong\n"); }     
    }; 
    

    PongMessage वर्ग नहीं MessageFactory द्वारा पंजीकृत किया जा रहा में परिणाम होगा और कार्यक्रम MessageFactory :: बनाएं (11) लाइन में SEGFAULT हैं । प्रश्न
    कक्षा क्यों पंजीकृत नहीं होगी? मुझे 100+ संदेशों के खाली कार्यान्वयन को जोड़ने के लिए मुझे अक्षम और अनावश्यक लगता है।

+0

# 1 CRTP (की तरह) http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern है – Anycorn

+0

# 3 क्योंकि MessageTmpl के निर्माता सुरक्षित है (हो सकता है) – Anycorn

+0

वैसे, अपने कोड सूची की जाँच करें। यह भटक गया है; तथा । वर्ण। मैंने इसे संकलित किया, हालांकि मुझे इसे सेगमेंटेशन गलती मिल रही है। क्लास टेम्पलेट स्थिर सदस्य प्रारंभिकरण के वास्तव में कूल उपयोग के लिए – Anycorn

उत्तर

7

उत्तर एक

इस तरह एक वर्ग पाने के सामान्य तकनीक है Curiously Recurring Template Pattern (CRTP):

class PingMessage: public MessageTmpl < 10, PingMessage > 

उपवर्गों रजिस्टर करने के लिए की है कि वर्ग है एक टेम्पलेट वर्ग के स्थिर सदस्य आरंभीकरण का उपयोग करने का आपका विशिष्ट तकनीक (आईएमओ) बस शानदार है, और मैंने इसे पहले कभी नहीं देखा है। यूनिट टेस्ट फ्रेमवर्क जैसे UnitTest++ और Google Test द्वारा उपयोग किए जाने वाले एक और आम दृष्टिकोण, उन वर्गों को प्रदान करना है जो कक्षा को शुरू करने वाले वर्ग और एक अलग स्थिर चर दोनों घोषित करते हैं।

जवाब दो

स्थैतिक चर सूचीबद्ध क्रम में प्रारंभ कर रहे हैं। यदि आप अपने संदेशफैक्टरी :: कॉल पंजीकृत करने से पहले अपनी एम_लिस्ट घोषणा को स्थानांतरित करते हैं, तो आपको सुरक्षित होना चाहिए। यह भी ध्यान रखें कि यदि आप एक से अधिक फाइलों में संदेश सबक्लास को घोषित करना शुरू करते हैं, तो आपको C++ static initialization order fiasco के कारण, प्रत्येक उपयोग से पहले m_List को एक सिंगलटन के रूप में लपेटना होगा और जांच लेंगे।

उत्तर तीन

सी ++ compilers केवल टेम्पलेट सदस्यों को बताया कि वास्तव में उपयोग किया जाता है का दृष्टांत होगा। टेम्पलेट कक्षाओं के स्टेटिक सदस्य सी ++ का एक क्षेत्र नहीं है जिसका मैंने बहुत उपयोग किया है, इसलिए मैं यहां गलत हो सकता हूं, लेकिन ऐसा लगता है कि कन्स्ट्रक्टर को यह उपलब्ध कराने के लिए पर्याप्त है कि संकलक को लगता है कि MESSAGE_ID का उपयोग किया जाता है (इस प्रकार संदेशफैक्टरी :: रजिस्टर कहा जाता है)।

यह मेरे लिए बहुत ही अनजान लगता है, इसलिए यह एक कंपाइलर बग हो सकता है। (मैं जी ++ 4.3.2 में यह परीक्षण किया गया था, मैं उत्सुक हूँ पता है कि कैसे Comeau सी ++, उदाहरण के लिए, यह संभालती है।)

स्पष्ट रूप instantiating message_id भी पर्याप्त होता, कम से कम छ में ++ 4.3.2:

template const uint16_t PingMessage::MESSAGE_ID; 

लेकिन यह एक खाली डिफ़ॉल्ट कन्स्ट्रक्टर प्रदान करने से भी अधिक अनावश्यक काम है।

मैं आपके वर्तमान दृष्टिकोण का उपयोग करके एक अच्छा समाधान नहीं सोच सकता; मैं व्यक्तिगत रूप से एक तकनीक (जैसे मैक्रोज़ या अपनी स्रोत फ़ाइलों का हिस्सा उत्पन्न करने के लिए एक स्क्रिप्ट का उपयोग करने) के लिए स्विच करने का लुत्फ उठाता हूं जो उन्नत सी ++ पर कम निर्भर करता है। अपनी टिप्पणी के लिए (एक स्क्रिप्ट MESSAGE_IDs के रखरखाव में ढील का एक अतिरिक्त लाभ होगा।)

जवाब में:

Singletons आम तौर पर से परहेज किया क्योंकि वे अक्सर overused के रूप में खराब प्रच्छन्न वैश्विक चर रहे हैं । कुछ बार हैं, हालांकि, जब आपको वास्तव में वैश्विक चर की आवश्यकता होती है, और उपलब्ध संदेश सबक्लास की वैश्विक रजिस्ट्री उन समयों में से एक है।

हां, आपके द्वारा प्रदान किया गया कोड MESSAGE_ID प्रारंभ कर रहा है, लेकिन मैं explicitly instantiating प्रत्येक सबक्लास के MESSAGE_ID के उदाहरण के बारे में बात कर रहा था। स्पष्टीकरण तत्काल का मतलब है कि संकलक को टेम्पलेट को तत्काल करने के लिए निर्देश देना, भले ही यह सोचता है कि उस टेम्पलेट इंस्टेंस का अन्यथा उपयोग नहीं किया जाएगा।

मुझे संदेह है कि अस्थिर असाइनमेंट के साथ स्थिर कार्य MESSAGE_ID असाइनमेंट उत्पन्न करने में संकलक को मजबूर करने या मजबूर करने के लिए है (डैश-टॉम-बैंग की समस्याओं को हल करने के लिए और मैंने कंपाइलर या लिंकर ड्रॉपिंग के साथ इंगित किया है या असाइनमेंट को तत्काल नहीं)।

+0

ओपी को यह भी ध्यान में रखना चाहिए कि कई लिंकर्स अनियंत्रित ऑब्जेक्ट्स को स्वचालित रूप से स्ट्रिप करते हैं, भले ही वे दिलचस्प काम करते हैं (यानी, स्थिर सदस्यों के प्रारंभिकरण को मास्टर सूची में पंजीकरण शुरू करना)। उदाहरण के लिए, विजुअल स्टूडियो लाइब्रेरी में स्थिर सदस्य प्रारंभिक रूप से फेंक देगा (यानी, कोड जो आपके "निष्पादन योग्य" प्रोजेक्ट का हिस्सा नहीं है) यदि निष्पादन योग्य किसी स्थिर तरीके से उस स्थैतिक वस्तु को स्पष्ट रूप से संदर्भित नहीं करता है। आप वीएस में "अंतर्निहित संदर्भित वस्तुओं" की सूची में प्रत्येक को जोड़ सकते हैं, लेकिन यह एक परेशानी आईएमओ से भी अधिक है। –

+0

आपके उत्तरों के लिए धन्यवाद। मैंने उनसे बहुत कुछ सीखा। मैं इस कोड से कोई क्रेडिट नहीं लेता क्योंकि मैंने इसे नौ नेटवर्क नामक जापानी नेटवर्किंग लाइब्रेरी से कॉपी किया था। अब मैं सिंगलटन चीज में देख रहा हूं लेकिन मुझे लगता है कि इन्हें टालना है। हालांकि मैं कन्स्ट्रक्टर पंजीकृत करने वाला टेम्पलेट भी स्पष्ट रूप से MESSAGE_ID को प्रारंभ कर रहा हूं? आप वहां एक बराबर चिह्न देख सकते हैं। अंत में मूल कार्यान्वयन में यह कोड MessageTmpl टेम्पलेट में है: स्थैतिक शून्य सक्षम() {volatile uint16_t x = MESSAGE_ID; } लेकिन मुझे नहीं पता कि इसका उपयोग कन्स्ट्रक्टर पंजीकरण को सक्षम करने के लिए कैसे किया जाता है। – Horacio

+1

स्थिर शून्य सक्षम() {volatile uint16_t x = MESSAGE_ID; } ऐसा लगता है कि यह ऑब्जेक्ट को अलग करने से लिंकर अनुकूलन को रोकने के लिए है। एक्स को अस्थिर होने के कारण असाइनमेंट को अनुकूलित नहीं किया जा सकता है। –

0

2: यदि आप एक गतिशील कंटेनर इस्तेमाल कर सकते हैं, लेकिन फिर आप भी कैसे पंजीकरण आदि उदाहरण के लिए, आप कुंजी के रूप में एक पूर्णांक और तत्व के रूप में एक समारोह सूचक के साथ एक नक्शा इस्तेमाल कर सकते हैं बदलना पड़ा चाहते हैं:

typedef Message* (*NewMessageFun)(); 

template< class tMessage > 
Message* NewMessage() 
{ 
    return new tMessage(); 
}; 

class PingMessage : public MessageImpl 
{ 
public: 
    enum{ _MESSAGE_ID = 10 }; 
}; 

class PongMessage 
{ 
public: 
    enum{ _MESSAGE_ID = 11 }; 
} 

//factory 
std::map< int, NewMessageFun > mymap; 
bool Register(const int type, NewMessageFun fun) 
{ 
    if(mymap.contains(type)) 
    return false; //already registered! 
    mymap[ type ] = fun; 
    return true; 
} 

template< class tMessage > 
bool RegisterAny() //shortcut 
{ 
    return Register(tMessage::_MESSAGE_ID, NewMessage<tMessage>); 
} 
// 

//main 
factory.RegisterAny<PingMessage>(); 
factory.RegisterAny<PongMessage>(); 
// 

अथवा, अपने वर्तमान कोड में, बस एक समझदार आवंटन आकार का उपयोग करें और क्रम सीमा बहुत ज्यादा पंजीकरण देखते हैं देखने के लिए जाँच की है। और शायद एक 'पंजीकरण रद्द करें' विधि की आपूर्ति करें।

+0

हां मैंने एक मानचित्र की कोशिश की लेकिन यह segfaulted ... लेकिन जोश केली और नोहा रॉबर्ट्स के जवाब के जवाब में मुझे समस्या (स्थैतिक प्रारंभिक आदेश) मिला। मान लीजिए मुझे सिंगलटन जाना होगा, लेकिन मैंने सुना है कि ये बुरा हैं। – Horacio

+1

सिंगलेट हमेशा बुरा नहीं होते हैं। यदि आपको लगता है कि, आपके मामले के लिए, एक सिंगलटन सबसे अच्छा तरीका है, तो यह है। – stijn

2

मुझे लगता है कि आप अनिर्दिष्ट व्यवहार में भाग रहे हैं क्योंकि आपके पंजीकरण उस ऑब्जेक्ट से पहले हो सकते हैं, जिसे आप उन्हें चिपकाना चाहते हैं। आपको ठीक परिणाम मिल रहे हैं क्योंकि सरणी की जगह प्रोग्राम के मुख्य ढेर में बनाई गई है। कौन जानता है ...

मेरे द्वारा उपयोग किए जाने वाले फ़िक्स को पंजीकरण कार्य को बाहरी या सदस्य कार्य को स्थैतिक के बजाय बनाना है। फिर एक मेयर्स सिंगलटन का उपयोग करें:


MessageFactory * MessageFactory::instance() 
{ 
    static MessageFactory fact; 
    return &fact; 
} 

इस तरह अपने संदेश कारखाने और कुछ से पहुँच पर बनाया जाएगा और जब आप इसे उपयोग करने के लिए (पहली बार यह बनाता है इसका इस्तेमाल करने की कोशिश कर रहा है क्योंकि कोशिश उपलब्ध होने की गारंटी दी जाएगी)।

0

यहाँ थोड़ा नक्शा

#include <map> 
#include <iostream> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <inttypes.h> 

//typedef Message *; 
class MessageFactory { 
public: 
    struct register_base { 
     virtual int id() const = 0; 
     virtual Message* new_() = 0; 
    }; 
    template<class C> 
    struct register_ : register_base { 
     static const int ID; 
     register_() : id_(ID) {} // force ID initialization 
     int id() const { return C::factory_key; } 
     Message* new_() { return new C(); } 
    private: 
     const int id_; 
    }; 
    static uint16_t Register(register_base* message) { 
     printf("Registering constructor for msg id %d\n", message->id()); 
     m_List[message->id()] = message; 
     return message->id(); 
    } 
    static Message *Create(uint16_t msgid) { 
     return m_List[msgid]->new_(); 
    } 
    static std::map<int,register_base*> m_List; 
}; 
std::map<int, MessageFactory::register_base*> MessageFactory::m_List; 

template<class C> 
const int MessageFactory::register_<C>::ID = 
    MessageFactory::Register(new MessageFactory::register_<C>()); 


class Message { 
public: 
    virtual ~Message() {} 
    int getMessageType() const { 
     return m_type; 
    } 
    virtual void say() = 0; 
protected: 
    uint16_t m_type; 
}; 

class PingMessage: public Message, private MessageFactory::register_<PingMessage> { 
public: 
    static const int factory_key = 10; 
    PingMessage() { } // must call explicitly to register 
    virtual void say() { 
     printf("Ping\n"); 
    } 
}; 

class PongMessage:public Message, private MessageFactory::register_<PongMessage> { 
public: 
    static const int factory_key = 11; 
    PongMessage() { } 
    void say() { 
     printf("Pong\n"); 
     std::cout << this->id() << std::endl; 
    } 
}; 



int main(int argc, char **argv) 
{ 
    Message *msg1; 
    Message *msg2; 

    msg1 = MessageFactory::Create(10); 
    msg1->say(); 

    msg2 = MessageFactory::Create(11); 
    msg2->say(); 

    delete msg1; 
} 
+0

धन्यवाद, मैंने जोश केली द्वारा उल्लिखित संदेश टीएमएल पंजीकरण कोड से पहले std :: मानचित्र घोषणा को स्थानांतरित करके इस समस्या को ठीक किया है। अब मैं एक निश्चित सरणी के बजाय std :: map का उपयोग कर सकता हूं। फिर भी मुझे समस्या संख्या से बचने के लिए इसे सिंगलटन बनाने की आवश्यकता है क्योंकि संदेश संख्या बढ़ जाती है। – Horacio

3

का उपयोग कर यह एक संशोधित संस्करण एक MessageFactory सिंगलटन और एक std :: दुकान कंस्ट्रक्टर्स के लिए नक्शे का उपयोग करता है सूची संशोधित किया गया है। यह अब तक बहुत अच्छा काम करता है लेकिन टिप्पणियों का स्वागत है।

मैं अभी भी प्रत्येक संदेश वर्ग के लिए रचनाकार बनाने से बचने के लिए एक रास्ता खोजने की कोशिश कर रहा हूं। मुझे पता है कि संभव है क्योंकि मूल पुस्तकालय इसे कर सकता है। दुर्भाग्य से मेरे पास केवल हेडर फाइलें हैं, इसलिए कार्यान्वयन विवरणों पर कोई विचार नहीं है।

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <inttypes.h> 
#include <map> 

class Message 
{ 
    protected: 
     Message() {}; 

    public: 
     virtual ~Message() { } 
     int getMessageType() const { return m_type; } 
     virtual void say() = 0; 

    protected: 
     uint16_t m_type; 
}; 

template<int TYPE, typename IMPL> 
class MessageTmpl: public Message 
{ 
    enum { _MESSAGE_ID = TYPE }; 
    public: 
    static Message* Create() { return new IMPL(); } 
    static const uint16_t MESSAGE_ID; // for registration 
    static void Enable() { volatile uint16_t x = MESSAGE_ID; } 
    protected: 
     MessageTmpl() { m_type = MESSAGE_ID; } //use parameter to instanciate template 
}; 

class MessageFactory 
{ 
    public: 
    typedef Message* (*t_pfFactory)(); 

    static MessageFactory *getInstance() 
    { 
     static MessageFactory fact; 
     return &fact; 
    } 

    uint16_t Register(uint16_t msgid, t_pfFactory factoryMethod) 
    { 
     printf("Registering constructor for msg id %d\n", msgid); 
     m_List[msgid] = factoryMethod; 
     return msgid; 
    } 

    Message *Create(uint16_t msgid) 
    { 
     return m_List[msgid](); 
    } 

    std::map<uint16_t, t_pfFactory> m_List; 

    private: 
    MessageFactory() {}; 
    MessageFactory(MessageFactory const&) {}; 
    MessageFactory& operator=(MessageFactory const&); 
    ~MessageFactory() {}; 
}; 

//std::map<uint16_t, t_pfFactory> MessageFactory::m_List; 

template <int TYPE, typename IMPL> 
const uint16_t MessageTmpl<TYPE, IMPL>::MESSAGE_ID = MessageFactory::getInstance()->Register(
    MessageTmpl<TYPE, IMPL >::_MESSAGE_ID, &MessageTmpl<TYPE, IMPL >::Create); 


class PingMessage: public MessageTmpl < 10, PingMessage > 
{ 
    public: 
    PingMessage() {} 
    virtual void say() { printf("Ping\n"); } 
}; 

class PongMessage: public MessageTmpl < 11, PongMessage > 
{ 
    public: 
    PongMessage() {} 
    virtual void say() { printf("Pong\n"); } 
}; 

int main(int argc, char **argv) 
{ 
    Message *msg1; 
    Message *msg2; 

    msg1 = MessageFactory::getInstance()->Create(10); 
    msg1->say(); 

    msg2 = MessageFactory::getInstance()->Create(11); 
    msg2->say(); 

    delete msg1; 
    delete msg2; 

    return 0; 
} 
0

सभी संदेश कक्षाएं कि MessageTmpl की उपवर्गों मैं निर्माता को लागू करना हैं । यदि नहीं, तो यह संदेश फैक्टरी में पंजीकृत नहीं होगा।

मैं इस विचार के साथ प्रयोग कर रहा था और व्युत्पन्न वर्ग में कुछ भी किए बिना पंजीकरण चर के तत्कालता को मजबूर करने के लिए एक तरीका आया। टेम्पलेट में वर्चुअल फ़ंक्शन बनाएं जो पंजीकरण चर का उपयोग करता है। यह फ़ंक्शन को तत्काल करने के लिए मजबूर करता है क्योंकि वर्चुअल फ़ंक्शन वहां होना चाहिए या नहीं, इसे कभी भी कहा जाता है।

#include <boost/array.hpp> 
#include <iostream> 

struct thingy 
{ 
    virtual ~thingy() {} 
    virtual void print_msg() const = 0; 
    virtual size_t id() const = 0; 

    bool registered_already() const { return registered; } 
protected: 
    bool registered; 
}; 

struct holder 
{ 
    enum index { 
    ID_OPEN 
    , ID_SAVE 
    , ID_SAVEAS 
    , COUNT 
    }; 

    static holder& instance() 
    { 
    static holder inst; 
    return inst; 
    } 

    thingy& operator[] (size_t i) 
    { 
    assert(thingys[i] && "Not registered."); 
    return *thingys[i]; 
    } 

    bool registered(size_t i) const { return thingys[i] != 0; } 

    ~holder() { std::for_each(thingys.begin(), thingys.end(), [](thingy* t) { delete t; }); } 

    index reg(thingy* t, index i) 
    { 
    assert(!thingys[i] && "Thingy registered at this ID already"); 
    thingys[i] = t; 
    return i; 
    } 

private: 

    holder() : thingys() {} 

    boost::array< thingy*, COUNT > thingys; 
}; 

template < typename Derived, holder::index i > 
struct registered_thingy : thingy 
{ 
    size_t id() const { return registration; } 
private: 
    static holder::index registration; 
}; 

template < typename T, holder::index i > 
holder::index registered_thingy<T,i>::registration = holder::instance().reg(new T, i); 

struct thingy1 : registered_thingy<thingy1,holder::ID_OPEN> 
{ 
    void print_msg() const { std::cout << "thingy1\n"; } 
}; 

struct thingy2 : registered_thingy<thingy2, holder::ID_SAVE> 
{ 
    void print_msg() const { std::cout << "thingy2\n"; } 
}; 

struct thingy3 : registered_thingy<thingy3, holder::ID_SAVEAS> 
{ 
    void print_msg() const { std::cout << "thingy3\n"; } 
}; 



int main() 
{ 
    holder::instance()[holder::ID_OPEN].print_msg(); 

    std::cin.get(); 
} 
+0

कहने के लिए खेद है कि मैं यह कोड काम नहीं कर सकता। मुझे पंजीकृत दावा नहीं मिलता है जिसका मतलब है कि चीज़ों को पंजीकृत नहीं किया जा रहा है। फिर अगर मैं चीज़ों के रचनाकार प्रदान करता हूं तो कोड ठीक काम करता है। – Horacio

+0

आप किस कंपाइलर का उपयोग कर रहे हैं? यह मेरे लिए काम करता है और जहां तक ​​मैं इसे बता सकता हूं। मेरा मानना ​​है कि संकलक आईडी() को तुरंत चालू करने के लिए मजबूर है, जो चर का उपयोग करता है ... –

+0

डॉन। 14.7.1/9: "... यह अनिर्दिष्ट है कि कार्यान्वयन एक वर्ग टेम्पलेट के वर्चुअल सदस्य फ़ंक्शन को तत्काल रूप से तत्काल करता है या नहीं, यदि वर्चुअल सदस्य फ़ंक्शन अन्यथा तत्काल नहीं किया जाएगा।" –

1

मैं व्युत्पन्न वर्ग में कंस्ट्रक्टर्स का उपयोग किए बिना काम कर होरासियो कोड बनाने के लिए कर रहा था:

यहाँ मेरी खरोंच कोड है। मैंने व्युत्पन्न कक्षाओं के कहानियों के अंदर सक्षम फ़ंक्शन को बुलाया।

class PingMessage: public MessageTmpl < 10, PingMessage > 
{ 
    public: 
    //PingMessage() {} 
    virtual void say() 
    { 
    enable(); // virtual (not static) function of the template class 
    printf ("Ping\n"); 
    } 
}; 
संबंधित मुद्दे