2013-02-10 20 views
14

मैं इस सरल कोड है में व्युत्पन्न वर्ग: के साथ कॉल करने के लिएखाका विशेषज्ञता और सी ++

specialization 
template 
template 

क्या यह संभव है: जब मैं यह (VS2010) चलाने

class A{}; 
class B : public A{}; 
class C : public B{}; 

class Test 
{ 
    public: 
     template<typename T> 
     void f(T&){printf("template\n");} 
     void f(A&){printf("specialization\n");} 
}; 

int main() 
{ 
    A a; 
    B b; 
    C c; 

    Test test; 
    test.f(a); 
    test.f(b); 
    test.f(c); 
} 

मैं इस उत्पादन विशेषज्ञता का उपयोग करने के लिए A-derived कक्षाएं?

+0

आपका क्या मतलब है? सवाल पूरी तरह से संदिग्ध –

+2

@ डिस्कोटर का मतलब है कि वह ए से प्राप्त कुछ भी चाहता है और साथ ही साथ उदाहरणों को जेनेरिक टेम्पलेट विस्तार के बजाय ए-रेफरेंस में ओवरराइड का उपयोग करने के लिए खुद को एक उदाहरण देता है। 'बी' और 'सी' उदाहरणों के साथ 'foo() 'का उपयोग करने के लिए उनकी कॉल सामान्य, न कि ओवरराइड का उपयोग कर रहे हैं। – WhozCraig

+0

@WhozCraig धन्यवाद! यह वही है जो मैं चाहता हूं। ए-व्युत्पन्न कक्षाओं में एक ऐसा कार्य होता है जिसे मुझे कॉल करने की आवश्यकता होती है। अन्य प्रकारों में यह फ़ंक्शन नहीं है और मुझे इसके बजाय लक्षणों का उपयोग करने की आवश्यकता है। – Felics

उत्तर

20

हां, यह संभव है, लेकिन आपको अपना कोड थोड़ा सा बदलना होगा।

सबसे पहले, तकनीकी हो सकता है, दूसरा समारोह f()नहीं टेम्पलेट समारोह के एक विशेषज्ञता है, लेकिन एक अधिभार। अधिभार को हल करते समय, टेम्पलेट संस्करण उन सभी तर्कों के लिए चुना जाता है जिनका प्रकार A नहीं है, क्योंकि यह एक आदर्श मिलान है: T तर्क के प्रकार के बराबर होने के लिए घटाया जाता है, इसलिए f(b) पर कॉल करते समय, उदाहरण के लिए, कटौती के प्रकार के बाद, कंपाइलर को निम्नलिखित दो अधिभारों के बीच चयन करना होगा:

void f(B&){printf("template\n");} 
void f(A&){printf("specialization\n");} 

बेशक, पहला एक बेहतर मैच है।

अब अगर आप चाहते हैं जब समारोह एक तर्क जो A का एक उपवर्ग है के साथ शुरू हो जाती है दूसरे संस्करण का चयन किया जाना है, तो आप जब प्रकार T है कुछ SFINAE तकनीक का उपयोग करने के लिए से सही ढंग से किया जा रहा instantiated समारोह टेम्पलेट को रोकने के लिए है A का उप-वर्ग बनने के लिए प्रेरित किया गया।

आप std::enable_if का उपयोग std::is_base_of प्रकार के गुणों के साथ संयोजन में कर सकते हैं।

// This will get instantiated only for those T which are not derived from A 
template<typename T, 
    typename enable_if< 
     !is_base_of<A, T>::value 
     >::type* = nullptr 
    > 
void f(T&) { cout << "template" << endl; } 

यहाँ कैसे आप एक पूरा कार्यक्रम में इसका इस्तेमाल होता है:

#include <type_traits> 
#include <iostream> 

using namespace std; 

class A{}; 
class B : public A{}; 
class C : public B{}; 
class D {}; 

class Test 
{ 
    public: 

     template<typename T, 
      typename enable_if<!is_base_of<A, T>::value>::type* = nullptr 
      > 
     void f(T&) { cout << ("template\n"); } 

     void f(A&){ cout << ("non-template\n");} 

}; 

int main() 
{ 
    A a; 
    B b; 
    C c; 
    D d; 
    float f; 

    Test test; 
    test.f(a); // Will print "non-template" 
    test.f(b); // Will print "non-template" 
    test.f(c); // Will print "non-template" 
    test.f(d); // Will print "template" 
    test.f(f); // Will print "template" 
} 

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

आप एक संकलक जो सी के साथ पूरी तरह से शिकायत नहीं है के साथ काम कर रहे हैं, तो ++ 11 (और इसलिए फ़ंक्शन टेम्पलेट्स पर डिफ़ॉल्ट टेम्पलेट तर्कों का समर्थन नहीं करता है), आप f() के अपने टेम्पलेट अधिभार की परिभाषा को निम्नानुसार बदलना चाहेंगे:

template<typename T> 
typename enable_if<!is_base_of<A, T>::value, void>::type 
f(T&) { cout << ("template\n"); } 

कार्यक्रम का व्यवहार समान होगा। ध्यान दें कि अगर f() का रिटर्न प्रकार void है, तो आप दूसरे तर्क को enable_if क्लास टेम्पलेट पर छोड़ सकते हैं।

+0

आपको एंडी +1। मैं इस बारे में SFINAE उत्तर लिखना शुरू कर रहा था, मुझे keystrokes को बचाने के लिए धन्यवाद =) – WhozCraig

+0

@WhozCraig: धन्यवाद :-) –

+0

नोट: 'पी' नाम टेम्पलेट पैरामीटर सूची में वैकल्पिक है। –

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