10

कुलपति ++ 2010 का उपयोग करना, निम्नलिखित दिया:इस टेम्पलेट को ओवरलोड किए गए गैर-टेम्पलेट फ़ंक्शन पर चुनने वाला संकलक क्यों है?

class Base { }; 
class Derived : public Base { }; 

template<class T> void foo(T& t); // A 
void foo(Base& base);    // B 

Derived d; 
foo(d);       // calls A 
foo(static_cast<Base&>(d));  // calls B 

मैं 'बी' चाहते हैं इसके बाद के संस्करण कहा जाता है। मैं इसे Base पर एक कलाकार के साथ प्राप्त कर सकता हूं, लेकिन यह आवश्यक क्यों है?

मैं चाहता हूँ टेम्पलेट समारोह सभी प्रकार Base से प्राप्त नहीं करने के लिए कहा जा करने के लिए (में निर्मित प्रकार, आदि), लेकिन मैं चाहता हूँ गैर टेम्पलेट अधिभार Base से प्राप्त प्रकार के लिए कहा जाता था, ग्राहक की आवश्यकता के बिना स्पष्ट रूप से कास्ट करने के लिए। मैंने ओवरलोड को टेम्पलेट की विशेषज्ञता बनाने की भी कोशिश की, लेकिन उसी मामले में वही व्यवहार होता है। जो मैं ढूंढ रहा हूं उसे प्राप्त करने का बेवकूफ तरीका क्या है?

उत्तर

12

सभी चीजें बराबर होती हैं, फ़ंक्शन टेम्पलेट्स पर नॉनटेम्प्लेट फ़ंक्शंस को प्राथमिकता दी जाती है। हालांकि, आपके परिदृश्य में, सभी चीजें बराबर नहीं हैं: (ए) T = Derived के साथ एक सटीक मिलान है, लेकिन (बी) तर्क के व्युत्पन्न-से-बेस रूपांतरण की आवश्यकता है।

#include <type_traits> 
#include <utility> 

template <typename T> 
typename std::enable_if< 
    !std::is_base_of<Base, T>::value 
>::type foo(T& x) 
{ 
} 

void foo(Base& x) 
{ 
} 
:

आप SFINAE का उपयोग करके विशिष्ट मामलों (यह एक तरह) के लिए इस के आसपास काम कर सकते हैं एक प्रकार Base से ली गई है उस के साथ instantiated जा रहा से (ए) को रोकने के लिए (प्रतिस्थापन विफलता कोई त्रुटि नहीं है)

+0

क्या यह एक सी ++ 11 चीज है या यह पुराने कोड में भी काम करता है - बस पूछ रहा है क्योंकि यह अच्छा है :)? –

+1

@ w00te: 'is_base_of' और 'enable_if' बूस्ट, सी ++ टीआर 1, और सी ++ 11 में शामिल हैं। उनके लिए कोई सी ++ 11 कार्यक्षमता आवश्यक नहीं है; आप केवल सी ++ 03 भाषा सुविधाओं का उपयोग करके इन्हें परिभाषित कर सकते हैं। –

+0

@ w00te: आप इसे C++ 03 में कर सकते हैं, लेकिन आपको बूस्ट से 'enable_if' और 'is_base_of' को पकड़ना होगा (या अपना खुद का रोल करें, यह आपको सी ++ के बारे में कुछ बातें सिखाएगा)। –

2

टेम्पलेट संस्करण का चयन किया जा रहा है क्योंकि अधिभारित संस्करण की तुलना में Derived के तर्क के साथ बुलाया जाने वाला यह एक बेहतर मिलान है। आप टेम्पलेट संस्करण को ओवरलोड रिज़ॉल्यूशन से ड्रॉप करने के लिए SFINAE का उपयोग कर सकते हैं ताकि Base या Derived के तर्कों के साथ कॉल करते समय अन्य संस्करण का चयन किया जा सके।

#include <type_traits> 
#include <iostream> 

class Base { }; 
class Derived : public Base { }; 

template<class T> 
typename std::enable_if< 
    std::is_base_of<Base, T>::value == false 
>::type 
foo(T&) 
{ 
    std::cout << "template foo" << std::endl; 
} 


void foo(Base&) 
{ 
    std::cout << "non-template foo" << std::endl; 
} 


int main() 
{ 
    Derived d; 
    Base b; 

    foo(d); 
    foo(b); 
} 
+0

'is_same' यह अनावश्यक है। – Pubby

+0

@ पब्बी धन्यवाद, मैं इसे ठीक कर दूंगा – Praetorian