2010-06-09 21 views
15

मैं टेम्पलेट तर्क के सदस्य टाइपपीफ का उपयोग करने वाले कोड को लिखने की कोशिश कर रहा हूं, लेकिन टेम्पलेट तर्क में टाइपफ़ीफ़ नहीं होने पर डिफ़ॉल्ट प्रकार की आपूर्ति करना चाहते हैं।डिफ़ॉल्ट प्रकार का उपयोग करने के लिए टेम्पलेट विशेषज्ञता यदि वर्ग सदस्य टाइपिफ़ाफ़ मौजूद नहीं है

struct DefaultType { DefaultType() { printf("Default "); } }; 
struct NonDefaultType { NonDefaultType() { printf("NonDefault "); } }; 

struct A {}; 
struct B { typedef NonDefaultType Type; }; 

template<typename T, typename Enable = void> struct Get_Type { 
    typedef DefaultType Type; 
}; 
template<typename T> struct Get_Type< T, typename T::Type > { 
    typedef typename T::Type Type; 
}; 

int main() 
{ 
    Get_Type<A>::Type test1; 
    Get_Type<B>::Type test2; 
} 

मैं इस मुद्रित करने के लिए "डिफ़ॉल्ट nondefault" उम्मीद करेंगे, लेकिन इसके बजाय यह प्रिंट "डिफ़ॉल्ट डिफ़ॉल्ट": एक सरल उदाहरण मैं कोशिश की है यह है। मेरी उम्मीद यह है कि मुख्य() में दूसरी पंक्ति Get_Type के विशेष संस्करण से मेल खाना चाहिए, क्योंकि बी :: प्रकार मौजूद है। हालांकि, ऐसा नहीं होता है।

क्या कोई यह बता सकता है कि यहां क्या हो रहा है और इसे कैसे ठीक किया जाए, या एक ही लक्ष्य को पूरा करने का दूसरा तरीका?

धन्यवाद।

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

जोर्ज एक वैकल्पिक तरीका दिया था, लेकिन मैं अभी भी क्यों यह काम नहीं करता उत्सुक हूँ। डॉक्स enable_if बढ़ावा अनुसार, एक तरह से विभिन्न प्रकार के लिए एक टेम्पलेट विशेषज्ञ तो की तरह है:

template <class T, class Enable = void> 
class A { ... }; 

template <class T> 
class A<T, typename enable_if<is_integral<T> >::type> { ... }; 

template <class T> 
class A<T, typename enable_if<is_float<T> >::type> { ... }; 

यह काम करता है क्योंकि enable_if < सच> एक typedef के रूप में टाइप किया है, लेकिन enable_if < झूठी> नहीं करता है।

मुझे समझ में नहीं आता कि यह मेरे संस्करण से अलग कैसे है, जहां enable_if का उपयोग करने के बजाय मैं केवल टी :: प्रकार का उपयोग कर रहा हूं। यदि टी :: टाइप मौजूद है, तो यह सक्षम नहीं होगा सक्षम_if < सत्य> :: उपरोक्त उदाहरण में टाइप करें और विशेषज्ञता का चयन क्यों करें? और यदि टी :: प्रकार मौजूद नहीं है, तो यह enable_if < झूठी> :: प्रकार मौजूद नहीं है और उपरोक्त उदाहरण में डिफ़ॉल्ट संस्करण को चुना जा सकता है?

template<class T> struct has_type { 
    template<class U> static char (&test(typename U::Type const*))[1]; 
    template<class U> static char (&test(...))[2]; 
    static const bool value = (sizeof(test<T>(0)) == 1); 
}; 

template<class T, bool has = has_type<T>::value> struct Get_Type { 
    typedef DefaultType Type; 
}; 

template<class T> struct Get_Type<T, true> { 
    typedef typename T::Type Type; 
}; 
+0

उह के बजाय always .. क्या लक्ष्य का उपयोग कर सकते हैं? –

+0

लक्ष्य यह है कि Get_Type :: टाइप टी होगा :: टाइप होने पर टाइप करें, या डिफ़ॉल्ट टाइप अगर यह मौजूद नहीं है। – Frank

उत्तर

8

आपके अतिरिक्त उत्तर देने के लिए - आपका विशेषज्ञता तर्क सदस्य टाइपिफ़ को पास करता है और उम्मीद करता है कि यह void प्रकार के रूप में उपज करे। इसके बारे में जादू कुछ भी नहीं है - यह सिर्फ एक डिफ़ॉल्ट तर्क का उपयोग करता है। चलो देखते हैं कि यह कैसे काम करता है। यदि आप Get_Type<Foo>::type कहते हैं, तो संकलक Enable का डिफ़ॉल्ट तर्क उपयोग करता है, जो void है, और प्रकार का नाम Get_Type<Foo, void>::type बन जाता है। अब, कंपाइलर जांचता है कि कोई आंशिक विशेषज्ञता मेल खाता है या नहीं।

आपकी आंशिक विशेषज्ञता की तर्क सूची <T, typename T::Type> मूल तर्क सूची <Foo, void> से ली गई है। यह T से Foo को घटाएगा और इसके बाद विशेषज्ञता के दूसरे तर्क में Foo को प्रतिस्थापित करेगा, जिससे आपके आंशिक विशेषज्ञता के लिए <Foo, NonDefaultType> का अंतिम परिणाम प्राप्त होगा। हालांकि, मूल तर्क सूची <Foo, void> से मेल नहीं खाती है!

आप void प्रकार की उपज के लिए निम्नलिखित में के रूप में एक तरह से की जरूरत है:

template<typename T> 
struct tovoid { typedef void type; }; 

template<typename T, typename Enable = void> struct Get_Type { 
    typedef DefaultType Type; 
}; 
template<typename T> 
struct Get_Type< T, typename tovoid<typename T::Type>::type > { 
    typedef typename T::Type Type; 
}; 

अब इस तरह आप उम्मीद कर काम करेंगे। एमपीएल का उपयोग करके आप tovoid

typename apply< always<void>, typename T::type >::type 
+0

धन्यवाद जोहान्स। मुझे एहसास नहीं हुआ कि इस प्रकार का मिलान मैच के लिए शून्य होना था, लेकिन यह सही समझ में आता है। – Frank

7

आपको लगता है कि SFINAE का उपयोग करके कर सकते हैं।


BOOST_MPL_HAS_XXX_DEF(Type) 

template < typename T > 
struct get_type { typedef typename T::Type type; }; 

template < typename T > 
struct calculate_type : boost::mpl::if_ 
< 
    has_Type<T> 
, get_type<T> 
, boost::mpl::identity<default_type> 
>::type {} 

typedef calculate_type<A>::type whatever; 

यदि आप "प्रकार" अपने metafunctions आप फ़ेचर "get_type" की आवश्यकता नहीं होगी यह कन्वर्ट करने के लिए और सिर्फ इतना है कि मामले में टी लौट सकते में के बजाय "प्रकार" का इस्तेमाल किया।

+0

धन्यवाद जॉर्ज, यह काम करता है। मैंने अपने प्रश्न को एक और सवाल के साथ संपादित किया कि मेरा कार्यान्वयन क्यों काम नहीं करता है, क्योंकि ऐसा लगता है कि enable_if स्वयं ही आधारित है। enable_if में टाइपिफ़ है, लेकिन enable_if नहीं है। मुझे समझ में नहीं आता कि यह ऐसा क्यों नहीं है कि टी :: प्रकार मौजूद है या नहीं। – Frank

+0

@ फ्रैंक: जोहान्स ने पहले से ही किसी अन्य जवाब में उत्तर दिया है। –

4

प्रथम चरण: "प्रकार" का उपयोग कर बंद करो और एमपीएल मानक "प्रकार" का उपयोग

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