2010-12-23 6 views
17

क्या यह टेम्पलेट फ़ंक्शन में पारित प्रकार की जांच करने के लिए सी ++ में संभव है? यह वह जगह है,टेम्पलेट से पारित प्रकार स्विच करें

template <typename T> 
void Foo() { } 

template <> 
void Foo<SomeClass>() { } 

template <> 
void Foo<SomeClass2>() { } 

// etc. 

(आप नहीं वास्तव में, हालांकि विशेषज्ञ समारोह टेम्पलेट हैं: उदाहरण के लिए:

template <typename T> 
void Foo() 
{ 
    if (typeof(SomeClass) == T) 
     ...; 
    else if (typeof(SomeClass2) == T) 
     ...; 
} 

उत्तर

27

हां, यह है ... लेकिन शायद यह आपके द्वारा अपेक्षित तरीके से काम नहीं करेगा।

template < typename T > 
void foo() 
{ 
    if (is_same<T,SomeClass>::value) ...; 
    else if (is_same<T,SomeClass2>::value) ...; 
} 

आप अपनी इच्छा/संकलक पर निर्भर करता है std:: या boost:: से is_same मिल सकती है। पूर्व केवल सी ++ 0x में है।

समस्या ... में क्या है के साथ आता है। यदि आप foo के भीतर उन प्रकारों के लिए विशिष्ट कुछ फ़ंक्शन कॉल करने में सक्षम होने की उम्मीद करते हैं, तो आप दुखी हैं। एक कंपाइलर त्रुटि तब भी परिणाम देगी जब कोड का वह अनुभाग कभी नहीं चलाया जाता है जब आप किसी ऐसे इंटरफ़ेस का पालन नहीं करते हैं जो उस अपेक्षित इंटरफ़ेस का पालन नहीं करता है।

उस समस्या को हल करने के लिए आपको कुछ अलग करने की आवश्यकता है। मैं टैग भेजने की सलाह देते हैं:

struct v1_tag {}; 
struct v2_tag {}; 

template < typename T > struct someclass_version_tag; 
template < > struct someclass_version_tag<SomeClass> { typedef v1_tag type; }; 
template < > struct someclass_version_tag<SomeClass2> { typedef v2_tag type; }; 

void foo(v1_tag) { ... } 
void foo(v2_tag) { ... } 
template < typename T > void foo() 
{ 
    typedef typename someclass_version_tag<T>::type tag; 
    foo(tag()); 
} 

ध्यान दें कि आप किसी भी क्रम-बहुरूपता भूमि के ऊपर यहाँ पीड़ित नहीं किया जाएगा और अनुकूलन के साथ यह चालू ही या यहाँ तक कि छोटे कोड आकार और गति में (हालांकि आप shouldn 'परिणाम चाहिए इस बारे में चिंता न करें जब तक कि आप एक प्रोफाइलर नहीं चलाते)।

+0

क्या संस्करण_टैग के आधार पर विभिन्न प्रकारों को वापस करना संभव है? – Boying

+0

निश्चित रूप से। यदि आप सी ++ 03 में फंस गए हैं, या सी ++ 11 और ऊपर में ऑटो का उपयोग करते हैं, तो आपको जानकारी पूछने के लिए कुछ तरीके से आने की आवश्यकता है। जब तक आप एक ही तत्कालता के भीतर विभिन्न प्रकारों को वापस करने की कोशिश नहीं करते हैं, तब तक आपको कोई समस्या नहीं होगी। –

+0

अब सी ++ 17 के साथ, यदि आप इसे छोटे से करने के लिए कथन करते हैं तो आप constexpr का उपयोग कर सकते हैं – xaxxon

10

आप कुछ विशिष्ट प्रकार के आधार पर करना चाहते हैं, टेम्पलेट विशेषज्ञ केवल प्रदर्शनी के लिए। यदि आप कर सकते हैं, तो आप टेम्प्लेट को अधिभारित करना चाहते हैं, या एक विशेष श्रेणी टेम्पलेट में प्रतिनिधि होना चाहते हैं। फ़ंक्शन टेम्पलेट्स को विशेषज्ञता देने से क्यों और कैसे बचें, हर्ब सटर के Why Not Specialize Function Templates?)

2

हां। आपको type traits का उपयोग करना होगा। उदाहरण के लिए:

#include <boost/type_traits/is_same.hpp> 

template <typename T> 
void Foo() 
{ 
    if ((boost::is_same<T, SomeClass>::value)) 
     ...; 
    else if ((boost::is_same<T, SomeClass2>::value)) 
     ...; 
} 

आप क्या हासिल करने की कोशिश कर रहे हैं पर निर्भर करता है, template specialization का उपयोग कर ज्यादा बेहतर विकल्प हो सकता है।

इसके अलावा, आप कुछ कार्यों/विधियों को सशर्त रूप से सक्षम/अक्षम करने के लिए enable_if/disable_if का उपयोग कर सकते हैं। टाइप ट्राइट्स के साथ इसे संयोजित करने के लिए, उदाहरण के लिए, एक प्रकार के एक प्रकार के लिए एक फ़ंक्शन का उपयोग करना और अन्य प्रकार के प्रकार के लिए अन्य फ़ंक्शन का उपयोग करना होगा।

template<typename T> 
struct Bar { static void foo(); }; 
template<typename T> 
template<> inline void Bar<T>::foo() { 
//generic 
} 
template<> inline void Bar<int>::foo() { 
//stuff for int 
} 
template<> inline void Bar<QString>::foo() { 
//QString 
} 

संपादित हाँ प्रकार लक्षण के साथ, लेकिन यह वास्तव में जरूरत नहीं है:

+0

आपका कोड संकलित नहीं होगा। आपको या तो एक चर के रूप में is_same त्वरण को तुरंत चालू करने की आवश्यकता है, या आपको इसकी आंतरिक 'मान' परिभाषा तक पहुंचने की आवश्यकता है। –

+0

@ नोहाः ठीक है। यह एक त्वरित और गंदा संकेत था :-) मैंने इसे संशोधित किया है। –

+0

क्या यह मानों के सेट के लिए ऐसा करना संभव है? प्रत्येक.gum मूल्य के लिए कुछ और करें? – paulm

2

नहीं है, लेकिन आप आंशिक विशेषज्ञता का उपयोग कर सकते हैं। टाइप_ट्रेट्स उदाहरण संपादित करें।

#include <type_traits> 
template<typename T> void foo() { 
    using std::is_same; 
    if<is_same<T, T2>::value || is_same<T, T1>::value) { 
     /* stuff */ 
    } 
} 
+0

क्या होगा यदि मैं कुछ ऐसा करना चाहते हैं 'अगर (is_same || is_same )'? –

+0

तो फिर तुम प्रकार लक्षण उपयोग करने के लिए ' और एसटीडी is_same :: मान' # शामिल :: अपने संकलक C++ 0x (VS2010/किसी भी हाल ही में जीसीसी) या सिर्फ पुराने संकलक संगतता के लिए बढ़ावा का उपयोग का समर्थन करता है। – OneOfOne

+3

यह आंशिक विशेषज्ञता नहीं है, यह पूर्ण विशेषज्ञता है। एक बहुत महत्वपूर्ण अंतर है। शायद सबसे महत्वपूर्ण यह है कि आंशिक विशेषज्ञता करना असंभव होगा क्योंकि इस तरह से किसी भी प्रकार के कार्यों के साथ इसकी अनुमति नहीं है। –

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