5

को देखते हुए निम्नलिखित समारोह टेम्पलेट्स:संकलक निम्नलिखित उदाहरण में मेरे फ़ंक्शन-टेम्पलेट अधिभार का चयन क्यों नहीं कर रहा है?

#include <vector> 
#include <utility> 

struct Base { }; 
struct Derived : Base { }; 

// #1 
template <typename T1, typename T2> 
void f(const T1& a, const T2& b) 
{ 
}; 

// #2 
template <typename T1, typename T2> 
void f(const std::vector<std::pair<T1, T2> >& v, Base* p) 
{ 
}; 

क्यों है यह है कि निम्नलिखित कोड हमेशा अधिभार # 1 के बजाय # 2 अधिभार का आह्वान?

int main() 
{ 
    std::vector<std::pair<int, int> > v; 
    Derived derived; 

    f(100, 200); // clearly calls overload #1 
    f(v, &derived);   // always calls overload #1 

    return 0; 
} 

यह देखते हुए कि f का दूसरा पैरामीटर Base की एक व्युत्पन्न प्रकार है, मुझे उम्मीद थी कि संकलक अधिभार # 2 का चयन करेंगे के रूप में यह # 1 अधिभार में सामान्य प्रकार की तुलना में एक बेहतर मुकाबला नहीं है।

क्या ऐसी कोई तकनीक है जिसका उपयोग मैं इन कार्यों को फिर से लिखने के लिए कर सकता हूं ताकि उपयोगकर्ता main फ़ंक्शन (यानी, तर्क प्रकारों के संकलक-कटौती का लाभ उठाने) में प्रदर्शित कोड लिख सकें?

+0

हालांकि यह मुख्य प्रश्न से संबंधित नहीं है, फिर भी: 1. 'int main()', कृपया। 2. आपकी टेम्पलेट फ़ंक्शन परिभाषाओं के बाद खाली घोषणाएं ';' हैं। यह सी ++ में अवैध है। – AnT

उत्तर

12

आप या तो यह कर सकते हैं:

f(v, static_cast<Base*>(&derived)); 

या SFINAE का उपयोग पहले दूर करने के लिए चयन उम्मीदवार के रूप में कार्य करें:

// Install boost library and add these headers: 
#include <boost/utility/enable_if.hpp> 
#include <boost/type_traits.hpp> 

// #1 - change it to look like this (note the keyword void changed positions) 
template <typename T1, typename T2> 
typename boost::disable_if< 
    typename boost::is_convertible<T2, Base*>, void>::type 
f(const T1& a, const T2& b) 
{ 
}; 

// #2 - this one can stay the same 
template <typename T1, typename T2> 
void f(const std::vector<std::pair<T1, T2> >& v, Base* p) 
{ 
}; 
+0

बचाव के लिए बूस्ट! बहुत चालाक! –

+0

डांग मैं बस इसे जोड़ रहा था। :) – GManNickG

+0

एकमात्र दुखद नोट यह है कि यह बहुत कम पठनीय है ...वैसे भी +1, समझा जाना अच्छा है, समाधान का प्रस्ताव भी बेहतर है :) –

8

यह देखते हुए कि च का दूसरा पैरामीटर बेस

यह करने के लिए परिवर्तनीय है की एक व्युत्पन्न प्रकार है, लेकिन * यह एक ली गई है। पहले टेम्पलेट फ़ंक्शन को कोई रूपांतरण की आवश्यकता नहीं होती है, और दूसरे को एक की आवश्यकता होती है, इसलिए यह पहले को चुनता है।

यह दूसरा चुनता है:

f(v, static_cast<Base*>(&derived)); 

एक तरफ ध्यान दें पर, main रिटर्न एक int

+0

स्पष्टीकरण के लिए धन्यवाद। मैंने मुख्य रूप से वापसी मूल्य हटा दिया है क्योंकि यह उदाहरण में आवश्यक नहीं था। –

+0

खैर मुख्य में एक निहित 'वापसी 0 है;' तो आप वैसे भी int छोड़ सकते हैं :) और यह एक चरित्र छोटा है! : पी – GManNickG

+3

आवश्यक या नहीं, सी ++ भाषा _requires_ कि 'मुख्य' वापसी प्रकार 'int' के साथ घोषित किया जाता है। – AnT

1

Koenig Lookup के बारे में स्पष्ट विषयों के अलावा जो संकलक (विशेष रूप से पुराने लोग काफी समस्याग्रस्त हैं) द्वारा लागू किया गया है, template specialization के संबंध में कुछ नुकसान हैं।

विशेषज्ञता के लिए प्रकारों को बिल्कुल मिलान करने की आवश्यकता होती है (सुनिश्चित नहीं है कि std यह कैसे परिभाषित करता है, लेकिन मेरे अनुभव से [gcc, msvc] एक व्युत्पन्न वर्ग मिलान नहीं किया जाएगा)। आप बेस * करने के लिए एक बदसूरत डाली जोड़ते हैं, तो ऐसा लगता है जैसे आप का इरादा काम करना चाहिए, व्युत्पन्न के लिए वैकल्पिक रूप से एक और विशेषज्ञता जोड़ने ...