2013-02-02 45 views
7

मैं एन-टन बेस क्लास टेम्पलेट पर काम कर रहा हूं। मैं आलस्य के बारे में चिंता नहीं है अभी तक, इसलिए आशय है:औद्योगिक-शक्ति एन-टन बेस क्लास टेम्पलेट

सुनिश्चित करें एक वर्ग केवल n उदाहरण हैं, और उन्हें करने के लिए उपयोग की एक वैश्विक बिंदु प्रदान करते हैं। यहाँ

template<typename Derived, size_t n = 1> 
class n_ton_base     // Singletons are the default 
{ 
    static Derived instances[n + (n == 0)]; 
           // Zerotons are supported, too 
protected: 

    // Prevent n_ton_base to be used outside of inheritance hierarchies 
    n_ton_base() {} 

    // Prevent n_ton_base (and Derived classes) from being copied 
    n_ton_base(const n_ton_base&) = delete; 

public: 
        // Get first element by default, useful for Singletons 
    template<size_t i = 0> 
    static Derived& get_instance() 
    { 
     static_assert(i < n, "Time to increase n it seems!"); 
     return instances[i]; 
    } 
}; 

और कैसे एक के लिए इसका इस्तेमाल होता है:

यहाँ मेरी कोड अब तक है

class SingletonExample : public n_ton_base<SingletonExample> 
{ 
public: 
    void method() 
    { 
     std::cout << "Singletons are overused.\n"; 
    }  
}; 

class DoubletonExample : public n_ton_base<DoubletonExample, 2> 
{ 
public: 
    void method() 
    { 
     std::cout << "Doubleton " << this << " says hello.\n"; 
    }  
}; 

int main() 
{ 
    SingletonExample::get_instance().method(); 
    DoubletonExample::get_instance().method(); 
    DoubletonExample::get_instance<0>().method(); 
    DoubletonExample::get_instance<1>().method(); 
} 

दुर्भाग्य से, कोड अभी तक संकलन नहीं करता है:

/tmp/ccsFtliS.o: In function `SingletonExample& n_ton_base<SingletonExample, 1ul>::get_instance<0ul>()': 
nton.cpp:(.text._ZN10n_ton_baseI16SingletonExampleLm1EE12get_instanceILm0EEERS0_v[SingletonExample& n_ton_base<SingletonExample, 1ul>::get_instance<0ul>()]+0x5): undefined reference to `n_ton_base<SingletonExample, 1ul>::instances' 
/tmp/ccsFtliS.o: In function `DoubletonExample& n_ton_base<DoubletonExample, 2ul>::get_instance<0ul>()': 
nton.cpp:(.text._ZN10n_ton_baseI16DoubletonExampleLm2EE12get_instanceILm0EEERS0_v[DoubletonExample& n_ton_base<DoubletonExample, 2ul>::get_instance<0ul>()]+0x5): undefined reference to `n_ton_base<DoubletonExample, 2ul>::instances' 
/tmp/ccsFtliS.o: In function `DoubletonExample& n_ton_base<DoubletonExample, 2ul>::get_instance<1ul>()': 
nton.cpp:(.text._ZN10n_ton_baseI16DoubletonExampleLm2EE12get_instanceILm1EEERS0_v[DoubletonExample& n_ton_base<DoubletonExample, 2ul>::get_instance<1ul>()]+0x5): undefined reference to `n_ton_base<DoubletonExample, 2ul>::instances' 
collect2: ld gab 1 als Ende-Status zurück 

मैंने क्या गलत किया?

+0

n_ton_base :: उदाहरण स्थैतिक हैं, इसलिए आपको इसे कहीं परिभाषित करना चाहिए। फिलहाल आप इसे केवल –

+0

घोषित कर रहे हैं आपने स्थिर सरणी के लिए परिभाषा नहीं जोड़ा है? –

+11

मैं इस साल के दहेज डिजाइन पैटर्न के रूप में वोट देता हूं। –

उत्तर

9

Etienne Cordonnier pointed out रूप में, यह एक वर्ग स्थिर के बजाय एक स्थानीय स्थिर उपयोग करने के लिए बहुत आसान है: प्रत्येक instantiated सदस्य समारोह अपनी ही स्थानीय स्थिर है, इसलिए कोई सरणी की जरूरत है होगा

template<typename Derived, size_t n = 1> 
class n_ton_base     // Singletons are the default 
{ 
protected: 

    // Prevent n_ton_base to be used outside of inheritance hierarchies 
    n_ton_base() {} 

    // Prevent n_ton_base (and Derived classes) from being copied 
    n_ton_base(const n_ton_base&) = delete; 

public: 
        // Get first element by default, useful for Singletons 
    template<size_t i = 0> 
    static Derived& get_instance() 
    { 
     static_assert(i < n, "Time to increase n it seems!"); 

     static Derived instance; 
     return instance; 
    } 
}; 

ध्यान दें कि।

यह मुझे इसके बारे में कुछ भी करने के बिना thread-safe lazy initialization प्राप्त करता है। अच्छा!

8

वैश्विक क्षेत्र में इस जोड़ें:

template<typename Derived, size_t n> 
Derived n_ton_base<Derived, n>::instances[n + (n == 0)]; 

Btw, std::array<> शून्य आकार सरणियों की अनुमति देता है, ताकि आप इसे विचार करना चाह सकते।

+0

दिलचस्प है कि आपने '= 1' भाग को संपादित किया है, यह प्रासंगिक कैसे है? – fredoverflow

+0

@FredOverflow डिफ़ॉल्ट तर्क केवल घोषणा या प्रारंभिक परिभाषा में ही अनुमत हैं। – 0x499602D2

+0

@FredOverflow: मैंने इसे हटा दिया क्योंकि परिभाषा में डिफ़ॉल्ट तर्कों को ओवरराइड नहीं किया जा सकता है (और यह एक परिभाषा है)। यह डिफ़ॉल्ट तर्कों के साथ कार्यों के समान काम करता है: आप उन्हें घोषणा और किसी फ़ंक्शन की परिभाषा में जोड़ नहीं सकते हैं, भले ही वे लगातार निर्दिष्ट हों। प्रारंभ में मैंने टेम्पलेट तर्क सूची चिपकाया और इसे हटाने के लिए भूल गए। –

1

आप here स्थिर वर्ग के सदस्यों के बारे में एक व्याख्या पा सकते हैं:

स्टेटिक डेटा सदस्यों (सी ++ केवल):

एक वर्ग के सदस्य सूची में एक स्थिर डेटा सदस्य की घोषणा एक नहीं है परिभाषा। आपको नेमस्पेस स्कोप में कक्षा घोषणा के बाहर स्थिर सदस्य को परिभाषित करना होगा। उदाहरण के लिए:

class X { 
public: 
    static int i; 
}; 

int X::i = 0; // definition outside class declaration 

इसलिए आप अपने वर्ग के n_ton::instances बाहर परिभाषित करने के लिए किया है।