2015-02-09 10 views
19
#include <iostream> 

struct A {}; 
struct B : public A {}; 

template<typename T> 
void foo(const T &x) { std::cout << "Called template" << std::endl; } 

void foo(const A &a) { std::cout << "Called A" << std::endl; } 

int main() 
{ 
    foo(A()); 
    foo(B()); 
    return 0; 
} 

यह प्रिंट:अधिभार संकल्प, टेम्पलेट्स और विरासत

Called A 
Called template 

मैं धारणा है कि एक उपयुक्त गैर टेम्पलेट समारोह हमेशा एक टेम्पलेट समारोह की चुना जाना होगा तहत किया गया। क्या कोई मुझे संकल्प चरणों की व्याख्या कर सकता है जो इस आश्चर्यजनक परिणाम का कारण बनता है?

+0

ठीक है, यहाँ एक अनुमान है: 'b' को' A' से विरासत है, लेकिन यह * नहीं * 'A' है। इसलिए, जब संकलक एक ओवरलोड रिज़ॉल्यूशन करता है, तो यह पहले 'बी' में ले जाने वाले फ़ंक्शन की तलाश करता है, और 'शून्य फू (कॉन्स ए और ए) 'इस मानदंड में फिट नहीं होता है। हालांकि, टेम्पलेट फ़ंक्शन * फिट * करता है, क्योंकि 'टी' * * बी * हो सकता है। तो, 'शून्य फू (कॉन्स टी एंड एक्स)' को प्राथमिकता दी जाती है। वैसे भी, यह पूरी तरह से 'अधिभार-रिज़ॉल्यूशन' टैग विवरण से मेल खाता है: * "... अनुभवी उपयोगकर्ताओं के लिए भी इसके नियम जटिल और अक्सर आश्चर्यजनक हैं।" * तो, इतना सच =) – Mints97

+0

http: //en.cppreference का संदर्भ लें विस्तार के लिए .com/w/cpp/भाषा/sfinae। – oyjh

उत्तर

16

मैं धारणा है कि एक उपयुक्त गैर टेम्पलेट समारोह हमेशा एक टेम्पलेट समारोह की चुना जाना होगा तहत किया गया।

यह केवल धारण करता है, तो टेम्पलेट और गैर टेम्पलेट समान रूप से अच्छे उम्मीदवार हैं। यही कारण है कि गैर-टेम्पलेट foo(A()) के लिए चुना गया है।

हालांकि, foo(B()) के मामले में, गैर-टेम्पलेट का उपयोग करके व्युत्पन्न-टू-बेस रूपांतरण की आवश्यकता होती है। तो फ़ंक्शन टेम्पलेट सख्ती से बेहतर है, और इसलिए इसे चुना गया है।

foo टेम्पलेट void foo(const B&) में तत्काल होता है। क्या यह टेम्पलेट्स के बिना कैसा दिखेगा पर विचार करें:

void foo(const B &x) { std::cout << "Called template" << std::endl; } 

void foo(const A &a) { std::cout << "Called A" << std::endl; } 

मेरा मानना ​​है कि आप foo(B()) बुला स्पष्ट रूप से पहले कोई एक चुनना चाहिए सहमत हूँ। यही कारण है कि टेम्पलेट चुना गया है।

+0

मैं क्या जानना चाहता हूं कि उपर्युक्त टेम्पलेट अधिभार की तरह अधिभार लिखने का कोई तरीका है जो केवल अंतिम अंतिम पुनरारंभ के रूप में चुना जाता है, फ़ॉलबैक। –

+0

@EmilEriksson यह कुछ शोध के लायक है और फिर एक अलग सवाल है। मेरे सिर के ऊपर से, केवल एक चीज जो मैं सोच सकता हूं वह इन पंक्तियों के साथ नाजुक SFINAE है: 'foo (const t &, sfinae_if <टी ए और टी से नहीं लिया गया है ....>) '। – Angew

+0

मैं सहमत हूं, मुझे लगता है कि मैं ऐसा प्रश्न बनाने जा रहा हूं। दुर्भाग्यवश, आपका सुझाव एक्सटेंशन के लिए खुला नहीं है। –

5

n3376 13.3.3.1/6

पैरामीटर एक वर्ग प्रकार है और तर्क अभिव्यक्ति एक व्युत्पन्न वर्ग प्रकार होता है, अंतर्निहित रूपांतरण अनुक्रम व्युत्पन्न से एक व्युत्पन्न-टू-बेस रूपांतरण है कक्षा वर्ग के लिए कक्षा।

n3376 13.3.3.1/8

बिना किसी रूपांतरण एक पैरामीटर प्रकार के एक तर्क से मेल करने के लिए आवश्यक हैं, तो अंतर्निहित रूपांतरण अनुक्रम मानक रूपांतरण अनुक्रम पहचान रूपांतरण से मिलकर (13.3 है .3.1.1)।

पहचान रूपांतरण में 13.3.3.1.1/तालिका 12 में सटीक मिलान रैंक देय तालिका है, लेकिन पहचान से तुलना में व्युत्पन्न-टू-बेस खराब है।

तो, संकलक सिर्फ पहला मामला

// template after resolving 
void foo(const A&) 

// non-template 
void foo(const A&) 

दोनों में उम्मीदवारों है पहचान रैंक है, लेकिन पहले से ही समारोह-टेम्पलेट है, दूसरा चुना जाएगा। और दूसरे मामले में

// template after resolving 
void foo(const B&) 

// non-template 
void foo(const A&) 

केवल पहली पहचान रैंक है और चुना जाएगा।

2

क्या कोई मुझे संकल्प चरणों की व्याख्या कर सकता है जो इस आश्चर्यजनक परिणाम का कारण बनता है?

आप cppreference.com पर अधिभार संकल्प पर लग सकता है: विशेष रूप से http://en.cppreference.com/w/cpp/language/overload_resolution

देख अंतर्निहित रूपांतरण दृश्यों

जवाब का विस्तार की धारा रैंकिंग:

मैंने एक अंश के साथ और स्पष्टीकरण प्रदान करने की कोशिश की उपर्युक्त लिंक से जानकारी:

स्वयं द्वारा एक फ़ंक्शन टेम्पलेट एक प्रकार, या कोई फ़ंक्शन या कोई अन्य इकाई नहीं है। किसी स्रोत फ़ाइल से कोई कोड उत्पन्न नहीं होता है जिसमें केवल टेम्पलेट परिभाषाएं होती हैं। किसी भी कोड को प्रकट होने के लिए, एक टेम्पलेट को तत्काल किया जाना चाहिए: टेम्पलेट तर्कों को निर्धारित किया जाना चाहिए ताकि संकलक वास्तविक कार्य (या क्लास टेम्पलेट से कक्षा) उत्पन्न कर सके।

  • समारोह टेम्पलेट का नाम देखने
  • टेम्पलेट तर्क कटौती

यहाँ करने के लिए नीचे, संकलक उम्मीदवार समारोह के एक जोड़े हैं:

कि के लिए, संकलक माध्यम से चला जाता परिभाषाएं जो विशिष्ट फ़ंक्शन कॉल को संभाल सकती हैं। ये उम्मीदवार टेम्पलेट फ़ंक्शन के साथ-साथ प्रासंगिक गैर-टेम्पलेट फ़ंक्शन परिभाषाओं के instannces हैं।

लेकिन आपके सवाल का जवाब यहाँ तथ्य में निहित है:

खाका तर्क कटौती समारोह टेम्पलेट का नाम देखने (जो तर्क पर निर्भर देखने शामिल हो सकता है) और से पहले अधिभार संकल्प के बाद जगह लेता है।

तथ्य यह है कि फ़ंक्शन ओवरलोड रिज़ॉल्यूशन टेम्पलेट फ़ंक्शन इंस्टेंटेशन के बाद आपके कोड के आउटपुट का कारण बनता है।

अधिभार संकल्प:

अब आप अपने विशेष मामले के रूप में निम्नलिखित अधिभार संकल्प के माध्यम से चला जाता है

[पिछले] कदम एक से अधिक उम्मीदवार समारोह का उत्पादन करते हैं, तो ओवरलोड समाधान करने के लिए किया जाता है उस फ़ंक्शन का चयन करें जिसे वास्तव में बुलाया जाएगा। आम तौर पर, अभ्यर्थी कार्य करते हैं जिनके मानदंड तर्कों से मेल खाते हैं, जिन्हें सबसे अधिक निकटता कहा जाता है। । । ।

...
एफ 1 एफ 2 की तुलना में बेहतर कार्य करने के लिए निर्धारित किया गया है यदि एफ 1 के सभी तर्कों के लिए निहित रूपांतरण एफ 2, और
के सभी तर्कों के लिए अंतर्निहित रूपांतरण से भी बदतर नहीं हैं 1) एफ 1 का कम से कम एक तर्क है जिसका निहित रूपांतरण है F2
के उस तर्क के लिए संबंधित अंतर्निहित रूपांतरण से बेहतर ... ।


अंतर्निहित रूपांतरण दृश्यों के रैंकिंग:

मानक रूपांतरण अनुक्रम के प्रत्येक प्रकार के तीन पंक्तियां एक असाइन किया गया है:
1) सटीक मिलान: कोई रूपांतरण की आवश्यकता है, lvalue करने वाली rvalue रूपांतरण, योग्यता रूपांतरण, उपयोगकर्ता एक ही कक्षा के वर्ग प्रकार के निर्धारित रूपांतरण
2) संवर्धन: अभिन्न पदोन्नति, फ्लोटिंग प्वाइंट पदोन्नति
3) रूपांतरण: अभिन्न रूपांतरण, फ्लोटिंग प्वाइंट रूपांतरण, चल अभिन्न रूपांतरण, सूचक रूपांतरण, सूचक करने वाली सदस्य रूपांतरण , बूलियन रूपांतरण, व्युत्पन्न वर्ग के उपयोगकर्ता द्वारा परिभाषित रूपांतरण को इसके आधार पर ई

मानक रूपांतरण अनुक्रम के पद मानक रूपांतरण यह मानती है की श्रेणी का सबसे बुरा तर्क अभिव्यक्ति के लिए सीधे एक संदर्भ पैरामीटर के बाइंडिंग या तो है

(वहाँ तीन रूपांतरण हो सकता है) है पहचान या एक व्युत्पन्न-टू-बेस रूपांतरण:

struct Base {}; 
struct Derived : Base {} d; 
int f(Base&); // overload #1 
int f(Derived&); // overload #2 
int i = f(d); // d -> Derived& has rank Exact Match 
       // d -> Base& has rank Conversion 
       // calls f(Derived&) 
+7

यह एक लिंक-केवल उत्तर है, इसमें लिंक को छोड़कर कोई जानकारी नहीं है। इसे एक वैध SO उत्तर बनाने के लिए, कृपया लिंक किए गए पृष्ठ से प्रासंगिक जानकारी जोड़ें। – Angew

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