2008-09-23 13 views
49

सी # में हम एक सामान्य प्रकार को परिभाषित कर सकते हैं जो कि सामान्य पैरामीटर के रूप में उपयोग किए जा सकने वाले प्रकारों पर बाधा लगाता है।टेम्पलेट प्रतिबंध सी ++

interface IFoo 
{ 
} 


class Foo<T> where T : IFoo 
{ 
} 

class Bar : IFoo 
{ 
} 

class Simpson 
{ 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Foo<Bar> a = new Foo<Bar>(); 
     Foo<Simpson> b = new Foo<Simpson>(); // error CS0309 
    } 
} 

वहाँ एक तरह से हम सी में टेम्पलेट मापदंडों के लिए बाधाओं को लागू कर सकते हैं ++ है: निम्न उदाहरण सामान्य कमी के उपयोग को दिखाता है।


सी ++ 0x के लिए मूल समर्थन है लेकिन मैं वर्तमान मानक सी ++ के बारे में बात कर रहा हूं।

+0

के रूप में Nemanja कहा, बूस्ट एक पुस्तकालय है कि कुछ इसी तरह लागू करता है। यह एक उचित भाषा सुविधा होने की तुलना में थोड़ा अधिक वर्बोज़ है, लेकिन यह काम करता है, और यह आपको अधिकतर बाधाओं को व्यक्त करने की अनुमति देता है। – jalf

उत्तर

31

जैसा कि किसी और ने उल्लेख किया है, सी ++ 0x इसे भाषा में बना रहा है। तब तक, मैं Bjarne Stroustrup के suggestions for template constraints की अनुशंसा करता हूं।

संपादित करें: Boost में alternative of its own भी है।

संपादित 2: concepts have been removed from C++0x जैसा लगता है।

+2

... और संभवतः [सी ++ 1y] में वापस जोड़ा गया (http://stackoverflow.com/questions/15669592/what-are-the-differences-between-concepts-and-template-constraints) – Yakk

1

केवल निस्संदेह।
किसी विधि में आप जिस विधि का उपयोग करते हैं उसे वास्तव में कहा जाता है जिसे टेम्पलेट पैरामीटर पर लगाया जाता है।

8

चेक बाहर Boost

बूस्ट संकल्पना लाइब्रेरी (बीसीसीएल) की जाँच करें

संकल्पना चेक पुस्तकालय एक स्पष्ट बयान और proposed C++ language extension की शैली में concepts की जाँच को जोड़ने के लिए अनुमति देता है।

2

क्रमबद्ध करें। यदि आप IFoo * पर static_cast करते हैं, तो टेम्पलेट को तत्काल करना असंभव होगा जब तक कि कॉलर एक वर्ग को पास न करे जिसे IFoo * को असाइन किया जा सके।

31

"लागू" सही उत्तर है। टेम्पलेट्स प्रभावी ढंग से "बतख टाइपिंग" परिदृश्य बनाते हैं, जिस तरीके से वे संकलित होते हैं। आप टेम्पलेट-टाइप किए गए मान पर इच्छित किसी भी फ़ंक्शन को कॉल कर सकते हैं, और केवल उन्हीं तात्कालिकताओं को स्वीकार किया जाएगा जिनके लिए विधि को परिभाषित किया गया है। उदाहरण के लिए:

template <class T> 
int compute_length(T *value) 
{ 
    return value->length(); 
} 

हम किसी भी प्रकार है जो एक int वापस जाने के लिए length() विधि वाणी के लिए सूचक पर इस विधि कॉल कर सकते हैं। Thusly:

string s = "test"; 
vector<int> vec; 
int i = 0; 

compute_length(&s); 
compute_length(&vec); 

... लेकिन नहीं एक प्रकार है जो करता है करने के लिए एक सूचक पर नहीं घोषित length():

compute_length(&i); 

यह तीसरा उदाहरण संकलन नहीं होंगे।

यह काम करता है क्योंकि सी ++ प्रत्येक तत्कालता के लिए templatized फ़ंक्शन (या कक्षा) का एक नया संस्करण संकलित करता है। चूंकि यह संकलन करता है, यह टाइप-चेकिंग से पहले कोड में टेम्पलेट तत्कालता का प्रत्यक्ष, लगभग मैक्रो-जैसे प्रतिस्थापन बनाता है। यदि सब कुछ अभी भी उस टेम्पलेट के साथ काम करता है, तो संकलन आय और हम अंततः परिणाम पर पहुंचते हैं। अगर कुछ विफल रहता है (जैसे int*length() घोषित नहीं करता है), तो हमें डरावनी छः पेज टेम्पलेट संकलन-समय त्रुटि मिलती है।

+1

मुझे लगता है कि आप 'यह कहकर एक टिप्पणी में लिखना पर्याप्त है? '// टी को बेसए से उत्तराधिकारी होना चाहिए, अन्यथा संकलन विफल हो जाएगा ' – bobobobo

+0

' तो हमें डरावनी छः पेज टेम्पलेट संकलन-समय त्रुटि '(एलओएल) मिलती है क्योंकि हम सभी पवित्र" अवधारणा "अवधारणा की प्रतीक्षा कर रहे हैं। – TechNyquist

14

आपको लगता है कि कुछ नहीं करता है IFoo पर एक गार्ड प्रकार डाल सकते हैं, यकीन है कि यह फू में टी पर वहाँ बनाने:

class IFoo 
{ 
public: 
    typedef int IsDerivedFromIFoo; 
}; 

template <typename T> 
class Foo<T> 
{ 
    typedef typename T::IsDerivedFromIFoo IFooGuard; 
} 
0

तुम कर सकते हो। आधार टेम्पलेट बनाएँ। इसे केवल निजी निर्माता बनाओ। फिर प्रत्येक मामले के लिए विशेषज्ञता बनाएं जो आप अनुमति देना चाहते हैं (या यदि विपरीत सूची सूची की अनुमति से बहुत छोटी है तो विपरीत बना दें)।

संकलक आपको उन टेम्पलेट्स को तुरंत चालू करने की अनुमति नहीं देगा जो निजी रचनाकारों के साथ संस्करण का उपयोग करते हैं।

यह उदाहरण केवल int और float के साथ तत्कालता की अनुमति देता है।

template<class t> class FOO { private: FOO(){}}; 

template<> class FOO<int>{public: FOO(){}}; 

template<> class FOO<float>{public: FOO(){}}; 

यह करने का एक छोटा और सुरुचिपूर्ण तरीका नहीं है, लेकिन यह संभव है।

-1

सीआरटीपी पैटर्न (उत्सुकता से रिकर्सिव टेम्पलेट पैटर्न) देखें। यह स्थिर विरासत का समर्थन करने में मदद के लिए बनाया गया है।

+0

सीआरटीपी वास्तव में किसी विशेष चीज़ के लिए डिज़ाइन नहीं किया गया है ... मुझे लगता है कि यह डिज़ाइन किए गए बजाय _discovered_ था (["इस मुहावरे का नाम जिम कोप्लिएन द्वारा बनाया गया था, जिसने इसे शुरुआती सी ++ टेम्पलेट कोड में देखा था।" ] (http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)), हालांकि टेम्पलेट पैरामीटर पर बाधा डालने का निश्चित रूप से उपयोग होता है, यह बहुत अच्छा होता है। – leftaroundabout

30

यदि आप सी ++ 11 का उपयोग करते हैं, तो आप static_assertstd::is_base_of के साथ इस उद्देश्य के लिए उपयोग कर सकते हैं।

उदाहरण के लिए,

#include <type_traits> 

template<typename T> 
class YourClass { 

    YourClass() { 
     // Compile-time check 
     static_assert(std::is_base_of<BaseClass, T>::value, "type parameter of this class must derive from BaseClass"); 

     // ... 
    } 
} 
+2

बिल्कुल सही! * और मुझे और अक्षर चाहिए ... * –

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