2011-06-19 11 views
12

क्या किसी को व्युत्पन्न कक्षाएं बनाने के तरीके को स्वचालित रूप से टेम्पलेट प्रकार के साथ एक स्थिर चर को तुरंत चालू करने के बारे में पता है (या तो व्युत्पन्न वर्ग के लेखक से कुछ भी आवश्यकता नहीं है, या उसे इस स्थिर को कॉल करने के लिए मजबूर करना पड़ता है व्युत्पन्न कक्षा परिभाषा वैध बनाने के लिए विधि)।व्युत्पन्न प्रकारों का स्वत: स्थैतिक आमंत्रण

यह समझना असंभव है, मैं इसे बेहतर तरीके से परिभाषित करने और परिभाषित करने की कोशिश करूंगा।

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

तो मैं इस है:

class Factory 
{ 
    template <typename EntityType> 
    registerEntityType(); 
}; 

void someInitFunction() 
{ 
    /// All of these are derived from Entity 
    gFactory.registerEntityType<EntityType1>(); 
    gFactory.registerEntityType<EntityType2>(); 
    gFactory.registerEntityType<EntityType3>(); 
    /// and so on 
} 

जबकि मैं नहीं बल्कि इस लिए होता है:

class Factory 
{ 
    template <typename EntityType> 
    registerEntityType(); 
}; 

class Entity // Abstract 
{ 
    /// This function should be called automatically with the derived 
    /// type as a parameter 
    SomeStaticConstructor<MDerivedType>() 
    { 
     gFactory.registerEntityType<MDerivedType>(); 
    } 
}; 

संपादित करें:

यह: यह स्थिर आवर्ती टेम्पलेट कोड है कि काम नहीं कर रहा है मेरी बेस क्लास है, और स्वचालित रूप से सामान पंजीकृत करने के लिए कक्षा

template <typename DerivedType> 
class Registrar 
{ 
    public: 
     Registrar(); 
     void check(); 
}; 
template <typename Product, typename DerivedType> 
class AbstractFactory: public AbstractFactoryBase<Product> 
{ 
    public: 
     AbstractFactory(); 
     ~AbstractFactory(); 
    private: 
     static Registrar<DerivedType> registrar; 
}; 

रजिस्ट्रार के निर्माता

template <typename DerivedType> 
Registrar<DerivedType>::Registrar() 
{ 
    std::cout << DerivedType::name() << " initialisation" << std::endl; 
    g_AbstractFactories.registerFactoryType<DerivedType>(DerivedType::name()); 
} 

और एक व्युत्पन्न प्रकार

class CrateFactory : public AbstractFactory<Entity, CrateFactory> 
{ 
    public: 
     CrateFactory(FactoryLoader* loader); 
     virtual ~CrateFactory(); 
     Entity* useFactory(FactoryParameters* parameters); 
     static std::string name() 
     { 
      return "CrateFactory"; 
     } 
+0

पहले पथ मैं नीचे चलने चाहते हैं, 'बनाने Entity' एक टेम्पलेट वर्ग है तो यह व्युत्पन्न प्रकार जानता है । व्युत्पन्न प्रकारों की समस्या या तो स्वयं टेम्पलेट्स (और इस प्रकार सार हो) होनी चाहिए, या बेस क्लास के रूप में कभी भी उपयोग नहीं किया जाना चाहिए। मैंने Win32 रैपर पुस्तकालयों में इसके लिए मैक्रोज़ भी उपयोग किए हैं। और, यह प्रश्न कुछ हद तक संबंधित है - http://stackoverflow.com/questions/138600/initializing-a-static-stdmapint-int-in-c –

+0

एनएम, ऐसा लगता है कि इसे सीआरटीपी कहा जाता है, और जवाबों ने कब्जा कर लिया जो मैं था हो रहा है :) –

उत्तर

2

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

template <typename DerivedType> 
class Registrar 
{ 
    public: 
     Registrar(); 
     void check(){} 
}; 

मेरी कक्षा मैं फोन करने के लिए

मेरे रजिस्ट्री वर्ग अपनी खाली समारोह के साथ, पंजीकृत होना चाहते हैं।

template <typename Product, typename DerivedType> 
class AbstractFactory: public AbstractFactoryBase<Product> 
{ 
    public: 
     AbstractFactory(); 
     ~AbstractFactory(); 
    private: 
     static Registrar<DerivedType> registrar; 
}; 

रजिस्ट्रार के निर्माता

template <typename DerivedType> 
Registrar<DerivedType>::Registrar() 
{ 
    std::cout << DerivedType::name() << " initialisation" << std::endl; 
    g_AbstractFactories.registerFactoryType<DerivedType>(DerivedType::name()); 
} 

और मेरे वर्गों निर्माता

template <typename Product, typename DerivedType> 
AbstractFactory::AbstractFactory() 
{ 
    registrar.check(); 
} 
7

आप क्या आप एक मिश्रण में और CRTP का उपयोग कर चाहते प्राप्त करने में सक्षम हो सकता है।

लेकिन सबसे पहले, आपको "प्रारंभिकरण के क्रम" समस्या का ख्याल रखना होगा। "मिश्रण-में" इस प्रकार दिखाई देगा

class Factory { 
public: 
    static Factory &getFactory() { static Factory f; return f; } 
    template <typename EntityType> 
    void registerEntityType { ... } 
}; 

तब:

सुनिश्चित करने के लिए gFactory मौजूद है इससे पहले कि आप इसका इस्तेमाल करने की कोशिश करते हैं, क्या तुम सच में यह एक उचित "सिंगलटन" वर्ग बनाने के लिए, की जरूरत है इस तरह
template <typename T> 
class EntityMixin { 
private: 
    struct RegisterMe { 
     RegisterMe() { Factory::getFactory().registerEntityType<T>(); } 
    }; 
    EntityMixin() { 
     static RegisterMe r; 
    } 
}; 

और आप की तरह इस के लिए इसका इस्तेमाल होगा:

class EntityType1 : public Entity, EntityMixin<EntityType1> { ... }; 
class EntityType2 : public Entity, EntityMixin<EntityType2> { ... }; 
class EntityType3 : public Entity, EntityMixin<EntityType3> { ... }; 

[अपडेट]

तुम भी tak कर सकते हैं EntityBase बनाने का ज़ीओ/मेरलीन विचार, EntityMixinEntity का नाम बदलें, और दो स्थानों से प्राप्त करने की आवश्यकता से बचें। मुझे लगता है कि मेरा मूल प्रस्ताव अधिक स्पष्ट है; आप mixin FactoryMixin भी कॉल कर सकते हैं और इसे किसी भी कक्षा में ले जा सकते हैं जिसे आप रजिस्टर करना चाहते हैं।

लेकिन Xeo/Merlyn संस्करण तो ऐसा दिखाई देगा:

class Factory { 
    public: 
    static Factory &getFactory() { static Factory f; return f; } 
    template <typename EntityType> 
    void registerEntityType { ... } 
}; 

class EntityBase { ... } ; 

template <typename T> 
class Entity : public EntityBase { 
private: 
    struct RegisterMe { 
     RegisterMe() { Factory::getFactory().registerEntityType<T>(); } 
    }; 
    Entity() { 
     static RegisterMe r; 
    } 
}; 

class EntityType1 : public Entity<Entitytype1> { ... }; 
class EntityType2 : public Entity<Entitytype2> { ... }; 
class EntityType3 : public Entity<Entitytype3> { ... }; 

किसी भी समाधान के लिए कुंजी CRTP और स्थिर स्थानीय चर से सावधान उपयोग क्रम के- प्रारंभ समस्या से बचने के लिए कर रहे हैं।

+0

यदि संभव हो, तो मैं मिश्रण-और इकाई वर्ग को संयोजित करने का सुझाव दूंगा। –

+0

तो मैं सिर्फ semantics के लिए मिश्रण और इकाई वर्ग को अलग कर रहा हूँ? (क्योंकि एक वर्ग में दोनों होने के बदसूरत और विरोधाभासी है) या क्या कोई अन्य कारण है? – deek0146

+0

मिश्रण एक टेम्पलेट वर्ग है। आम आधार इकाई वर्ग नहीं है (कम से कम, मुझे लगता है कि आप यही चाहते हैं ...)। इसलिए वे वही नहीं हो सकते हैं। – Nemo

10

मैं एक CTRP समर्थित दृष्टिकोण की सलाह देते हैं:

// Entity.h 
class EntityBase 
{ // abstract 
}; 

template<class Derived> 
class Entity 
    : public EntityBase 
{ // also abstract thanks to the base 
    static char _enforce_registration; // will be instantiated upon program start 
}; 

// your actual types in other headers 
class EntityType1 
    : public Entity<EntityType1> 
{ // automatic registration thanks to the _enforce_registration of the base 
    // ... 
}; 

// Entity.cpp 
#include "Entity.h" 

template<class T> 
char RegisterType(){ 
    GetGlobalFactory().registerEntityType<T>(); 
    return 0; // doesn't matter, never used. 
} 

template<class Derived> 
char Entity<Derived>::_enforce_registration = RegisterType<Derived>(); 

हालांकि, के रूप में देखा, अब आप एक GetGlobalFactory समारोह है, जो आलसी कारखाने initializes सुनिश्चित करने के लिए कि यह शुरू कर दिया गया के माध्यम से अपना कारखाना प्राप्त करने की आवश्यकता लागू पंजीकरण होने से पहले:

Factory& GetGlobalFactory(){ 
    static Factory _factory; 
    return _factory; 
} 
+0

@Merlyn: ठीक है, मुझे पता था कि मैं उससे लिंक करना चाहता था, लेकिन किसी भी तरह से इसे भूल गया। – Xeo

+0

+1। यही वह है जिसे मैं ओपी पर अपनी टिप्पणी में शामिल करने की कोशिश कर रहा था, लेकिन मैं भूल गया कि यह एक पूर्ण उड़ा हुआ मुहावरे था। इन दिनों बहुत सी ++ नहीं कर रहा :) –

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