2010-10-13 16 views
22

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

उदाहरण:

template <typename T> struct MyClassTemplate { 
    // ... 
}; 

template <typename T> struct MyClassTemplate<T*> { 
    // Do not use MyClassTemplate with a pointer type! 
    typedef typename T::intentional_error err; 
}; 

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

क्या टेम्पलेट इंस्टॉलेशन को अस्वीकार करने के लिए बेहतर सरल तरीके हैं?

मुझे पता है कि सी ++ 0x में, टेम्पलेट अवधारणाओं और हटाए गए फ़ंक्शन घोषणाएं इस तरह की चीज़ पर अधिक बेहतर नियंत्रण प्रदान करती हैं, लेकिन मैं उन उत्तरों की तलाश कर रहा हूं जो वैध C++ 03 हैं।

उत्तर

25

तुम बस यह परिभाषित करने को छोड़ सकता है।

template <typename T> struct MyClassTemplate<T*>; 

तुम भी एक गैर परिभाषित विशेषज्ञता से निकाले जाते हैं सकता है

template <typename T> struct invalid; 
template <typename T> struct MyClassTemplate<T*> : invalid<T> { }; 

ध्यान दें कि स्पष्ट विशेषज्ञताओं है कि वर्ग या कार्यों की घोषणा टेम्प्लेट पैरामीटर पर निर्भर करते हैं कभी नहीं होगा। तो, इस तरह की चीजें जो टेम्पलेट पैरामीटर पर निर्भर करती हैं वैसे भी काम नहीं कर सकती हैं। उस मामले में, एक गैर परिभाषित स्पष्ट विशेषज्ञता घोषित करने के लिए पर्याप्त

template<> struct MyClassTemplate<int*>; 
+0

इनमें से कुछ संकलन समय के बजाय लिंक समय पर त्रुटियां देने जा रहे हैं, है ना? – zwol

+0

@Zack सभी संकलन समय पर त्रुटियां देंगे। –

+0

ओह, ठीक है, क्योंकि एक वर्ग टेम्पलेट का दृष्टांत को एक एक पूर्ण वर्ग घोषणा होना आवश्यक है। मैं फ़ंक्शन टेम्पलेट्स के बारे में सोच रहा था। – zwol

1

अवधारणाओं को 0x से हटा दिया गया था। आप लाइब्रेरी का उपयोग कर सकते हैं, जैसे Boost Concept Check

1

आप किसी लाइब्रेरी का उपयोग नहीं करना चाहते हैं, तो हो सकता है, इस संरचना बहुत विश्वसनीय है (यह मोटे तौर पर क्या बूस्ट आंतरिक रूप से करता है):

template <typename T> 
void must_be_specialized(T const&) 
{ 
    enum dummy { d = (sizeof(struct must_be_specialized_for_this_type) 
        == sizeof(T)) }; 
} 

आप उस प्रकार के साथ टेम्पलेट के तत्कालता को अस्वीकार करने के लिए विशेषज्ञता में कुछ समानता डाल सकते हैं। मैं व्यक्तिगत रूप से, must_be_specialized_for_this_type पर कहीं से परिभाषा प्राप्त करने की चिंता नहीं करता, लेकिन यदि आप वास्तव में चाहते थे तो आप इसे निजी नामस्थान में गिलहरी करने के लिए आगे की घोषणा का उपयोग कर सकते हैं।

+0

मुझे यह नहीं मिला, अगर दो प्रकार के समान आकार हैं तो क्या होगा? Enum के साथ हिस्सा क्या करता है? –

+0

'struct must_be_specialized_for_this_type' कहीं भी परिभाषित नहीं किया जाता है, ताकि क्या त्रुटि से चलाता है। एक अभिव्यक्ति में इसका उपयोग करना जिसमें 'टी' शामिल है, त्रुटि समय के बजाय टेम्पलेट तत्काल समय पर त्रुटि उत्पन्न होती है, और' enum dummy' भाग निरंतर अभिव्यक्ति के साथ करने के लिए एक सुविधाजनक बात है, इसलिए इसे फेंक दिया नहीं जाएगा पूरी तरह से पार्स समय पर दूर। – zwol

+0

मैं या तो यह वास्तव में पता नहीं था, लेकिन वह वास्तव में struct 'must_be_specialized' की एक स्थानीय struct के आगे घोषणा है। तो यह वास्तव में बाहर से परिभाषा प्राप्त नहीं कर सकता है। हालांकि, ध्यान दें कि कंपाइलर तुरंत बिना किसी त्रुटि के त्रुटि के लिए स्वतंत्र हैं (वास्तव में आते हैं, और डिकर ने मुझे बताया कि मुझे क्लैंग के खिलाफ एक पीआर भेजना चाहिए ताकि वे अन्य बग तय करने के बाद भी ऐसा कर सकें), क्योंकि कभी भी वैध विशेषज्ञता नहीं हो सकती नमूना। इसे वैध बनाने की चाल नाम को निर्भर करने के लिए होगी, जैसे 'sizeof (typename depedent :: type) '। –

12

मेरे लिए यह C++ 0x या BOOST_STATIC_ASSERT से static_assert के लिए एक सामान्य मामले की तरह लगता है। static_assert कार्यक्षमता का लाभ यह है कि आप एक कस्टम त्रुटि संदेश पारित कर सकते हैं ताकि त्रुटि का कारण अधिक स्पष्ट हो।

दोनों तरीके आपको कुछ कस्टम परिभाषित संकलन समय स्थिति के तहत संकलन प्रक्रिया को समय-समय पर समाप्त करने का अवसर दे रहे हैं।

static_assert साथ

:

template <typename T> struct MyClassTemplate<T*> { 
    static_assert(always_false<T>::value, "Do not use MyClassTemplate with a pointer type!"); 
}; 
BOOST_STATIC_ASSERT साथ

template <typename T> struct MyClassTemplate<T*> { 
    // Do not use MyClassTemplate with a pointer type! 
    BOOST_STATIC_ASSERT(always_false<T>::value); 
}; 

हमेशा झूठे कुछ इस तरह दिखेगा:

template< typename T > 
struct always_false { 
    enum { value = false }; 
}; 

HTH

संपादित करें: परीक्षा फिक्स्ड उन्हें वास्तव में काम करने के लिए ples ;-) जीएमएन के लिए धन्यवाद!

+4

वे हर समय बिना शर्त शर्त देंगे। (यानी, कंपाइलर को 'झूठा' दिखाई देगा, पता है कि यह स्थैतिक जोर विफल हो जाता है, इसलिए निदान को ट्रिगर करें।) यदि आप तत्काल होने पर इसे केवल ट्रिगर करना चाहते हैं, तो आपको इसे टेम्पलेट पैरामीटर पर निर्भर करना होगा: 'static_assert (आकार (टी) == 0, "ब्लाह"); '। – GManNickG

+0

डांग, मैं पूरी तरह से भूल गया-.- 'मुझे याद दिलाने के लिए धन्यवाद – Vinzenz

+2

तो मैंने उदाहरण को ठीक किया कि यह वास्तव में काम करता है :-) – Vinzenz

1

"क्या टेम्पलेट तत्काल अस्वीकार करने के लिए बेहतर सरल तरीके हैं?" जो आपने पहले से पहचाना है उससे कहीं ज्यादा बेहतर नहीं है। मुझे यकीन है कि दुर्घटना से बचाने के लिए सी ++ सुरक्षा तंत्र आप दुर्भाग्य से नहीं हैं। और कोई व्यक्ति आपके इच्छित उपयोग को तोड़ने के लिए विशेषज्ञता या कक्षा को परिभाषित करता है, तो मैं दुर्भावनापूर्ण मानता हूं। शायद जब भी वे इसे करते हैं तो आप सिर के पीछे व्यक्ति को मार सकते हैं।

मैं व्यक्तिगत रूप से जांच को टेम्पलेट्स में रखना पसंद करता हूं जो केवल चेक का वर्णन करने के लिए मौजूद हैं। यह विरासत और टेम्पलेट्स के दिलचस्प संयोजन की अनुमति देता है।

template <class T> 
class not_with_pointer_t { }; 

template <class T> 
class not_with_pointer_t<T*>; 

template <class T> 
class some_class_t : public not_with_pointer_t<T> { }; 

template <class T, template <class U> class base_t> 
class another_class_t : public base_t<T> { }; 

typedef some_class_t<int> a_t; // ok 
typedef some_class_t<void*> b_t; // error if instantiated 
typedef another_class_t<void*, not_with_pointer_t> c_t; // error if instantiated 

template <class T> class unrestricted_t { }; 
typedef another_class_t<void*, unrestricted_t> d_t; // ok 
संबंधित मुद्दे