2011-12-23 17 views
9

मैं एक विन्यास प्रबंधक वर्ग बनाने की कोशिश कर रहा हूं, जो std :: string द्वारा मनमानी वस्तुओं को स्टोर कर सकता है।किसी सार तत्व श्रेणी में टेम्पलेट फ़ंक्शन करने का कोई तरीका?

मेरी इंटरफेस (सार आधार वर्ग) के लिए मेरे प्रारंभिक विचार था इस (जाहिर है इस बुरी तरह अधूरा है)

class ConfigurationManager 
{ 
public: 
    static boost::shared_ptr<ConfigurationManager> create(); 

    template<typename T> 
    virtual T getOption(const std::string& name) = 0; 
}; 

लेकिन तब मेरी संकलक ने बताया कि टेम्पलेट की आभासी नहीं किया जा सकता (और फिर मुझे एहसास हुआ कि मैं वैसे भी निर्यात टेम्पलेट्स नहीं हो सकता है)।

आंतरिक रूप से मैं बूस्ट :: किसी भी (बहुत अधिक रनटाइम चेक * *) का उपयोग करने जा रहा हूं, लेकिन मैं अपने इंटरफ़ेस में किसी भी बूस्ट :: को बेनकाब नहीं करना चाहता हूं।

इस बारे में जाने का सबसे अच्छा तरीका क्या होगा?

+1

किस बारे में जाने के लिए, ठीक है? –

+0

@ ओली मैंने अपने प्रश्न में पोस्ट किए गए वाक्य रचनात्मक रूप से असंभव इंटरफ़ेस को अनुकरण करने के लिए। – Lalaland

+0

तो आप पॉलिमॉर्फिक फ़ंक्शन टेम्पलेट्स करना चाहते हैं, भले ही वे वास्तव में संभव न हों? –

उत्तर

7

boost::any पर एक संरक्षित वर्चुअल अमूर्त फ़ंक्शन लौटाएं, और एक गैर-वर्चुअल, गैर-सार, सार्वजनिक टेम्पलेट फ़ंक्शन को अपने इंटरफ़ेस के उपयोगकर्ताओं से छिपाने के लिए।

class ConfigurationManager { 
protected: 
    virtual boost::any getOptionProtected(const std::string& name) = 0; 
public: 
    static boost::shared_ptr<ConfigurationManager> create(); 
    template<typename T> T getOption(const std::string& name) { 
     return boost::any_cast<T>(getOptionProtected(name)); 
    } 
}; 
+0

यह 'boost :: any_cast (getOption संरक्षित (नाम)) होना चाहिए; ' – Xeo

+0

@Xeo सुधार के लिए धन्यवाद! (आप बता सकते हैं कि मैंने कभी भी उस लाइन से बढ़ावा नहीं दिया)। – dasblinkenlight

+0

लगभग बिल्कुल इस का उपयोग कर समाप्त हो गया। – Lalaland

4

एक वैकल्पिक दृष्टिकोण ConfigurationManager को व्युत्पन्न प्रकार का नाम पारित करने के लिए होगा:

template<typename Derived> 
class ConfigurationManager 
{ 
    public: 
    static boost::shared_ptr<ConfigurationManager> create(); 

    template<typename T> 
    T getOption(const std::string& name) 
    { 
    // call Derived::getOption 
    return static_cast<Derived*>(this)->getOption(name); 
    } 
}; 

व्युत्पन्न प्रकार Foo तो इस तरह परिभाषित किया जाएगा:

class Foo : public ConfigurationManager<Foo> 
{ 
    template<typename T> 
    T getOption(const std::string& name) 
    { 
    // do something Foo-specific here 
    } 
}; 

अंत परिणाम एक सार वर्चुअल फ़ंक्शन के समान कुछ है। इस मुहावरे को curiously recurring template pattern के रूप में जाना जाता है।

+1

मुझे पता है कि यह पुराना है, लेकिन सीआरटीपी के इस उपयोग में कॉन्फ़िगरेशन मैनेजर क्लास का क्या मतलब है? हम फू स्टोर करने के लिए उस प्रकार का उपयोग नहीं कर सकते हैं। – Constantin

1

पता नहीं क्या boost::any आप के लिए करता है, लेकिन एक तरफ से है कि आपके (केवल, मुझे लगता है) विकल्प हैं या तो 1) ConfigurationManager बनाओ एक टेम्पलेट वर्ग, या 2) बनाने ConfigurationManager::getOptionगैर आभासी लेकिन एक का उपयोग अलग गैर-टेम्पलेट वर्चुअल फ़ंक्शन (getOption के भीतर कहा जाता है) जो आपके व्युत्पन्न कक्षाओं में इच्छित कार्यक्षमता का प्रबंधन करता है। 2 पर वेरिएंट भी हैं), जैसे किसी ऑब्जेक्ट के पॉइंटर को शामिल करना जो (गैर-आभासी) getOption की इच्छित कार्यक्षमता निर्दिष्ट करता है। यह वस्तु एक वर्ग का एक उदाहरण होगा जो मूल रूप से एक विरासत पदानुक्रम का हिस्सा होगा - मूल रूप से रणनीति पैटर्न। यद्यपि अधिक जटिल लगता है। क्यों मुझे लगता है कि यह काफी तुम सब कर सकते हैं तो मूल रूप से मैं

class ConfigurationManager 
{ 
    public: 
     ... 
     template<typename T> 
     getOption(...); 
    private: 
     virtual getOptionSpecial(...) = 0; //Called within getOption 
}; 

शीर्ष जवाब का सुझाव दे रहा हूँ this SO thread को (आंशिक रूप से) है।