2012-12-20 44 views
12

मिनिमल कार्यक्रम:समान हस्ताक्षर के साथ टेम्पलेट फ़ंक्शन ओवरलोडिंग, यह क्यों काम करता है?

#include <stdio.h> 

#include <type_traits> 

template<typename S, typename T> 
int foo(typename T::type s) { 
    return 1; 
} 

template<typename S, typename T> 
int foo(S s) { 
    return 2; 
} 

int main(int argc, char* argv[]) { 
    int x = 3; 
    printf("%d\n", foo<int, std::enable_if<true, int>>(x)); 

    return 0; 
} 

उत्पादन:

1 

क्यों इस एक संकलन त्रुटि नहीं करता है? जब टेम्पलेट कोड उत्पन्न होता है, तो क्या कार्य int foo(typename T::type search) और int foo(S& search) समान हस्ताक्षर नहीं होंगे?

आप बदलना टेम्पलेट समारोह एक छोटा सा, यह अभी भी काम करता है (जैसा कि मैंने ऊपर के उदाहरण दिए गए अपेक्षा करेंगे) हस्ताक्षर हैं: फिर भी

template<typename S, typename T> 
void foo(typename T::type s) { 
    printf("a\n"); 
} 

template<typename S, typename T> 
void foo(S s) { 
    printf("b\n"); 
} 

यह नहीं और अभी तक सिर्फ इतना फर्क है एक है कि करता है एक int हस्ताक्षर और दूसरा पहले टेम्पलेट पैरामीटर द्वारा परिभाषित किया गया है।

template<typename S, typename T> 
void foo(typename T::type s) { 
    printf("a\n"); 
} 

template<typename S, typename T> 
void foo(int s) { 
    printf("b\n"); 
} 

संकलक त्रुटि (बजना):

test.cpp:26:2: error: call to 'foo' is ambiguous 
foo<std::enable_if<true, int>>(3); 
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
test.cpp:16:6: note: candidate function [with T = std::__1::enable_if<true, int>] 
void foo(typename T::type s) { 
     ^
test.cpp:21:6: note: candidate function [with T = std::__1::enable_if<true, int>] 
void foo(int s) { 
     ^
1 error generated. 

मैं एक परियोजना मैं पर काम कर रहा हूँ के लिए इस के समान कोड का उपयोग कर रहा है और मैं आसानी से भाषा डर वहाँ एक बात यह है कि कर रहा हूँ कि मैं मैं समझ नहीं पा रहा हूं कि कुछ मामलों में कुछ अपरिभाषित व्यवहार का कारण बन जाएगा। मुझे यह भी उल्लेख करना चाहिए कि यह क्लैंग और वीएस 11 दोनों में संकलित करता है, इसलिए मुझे नहीं लगता कि यह सिर्फ एक कंपाइलर बग है।


संपादित करें: दूसरा दूसरा मामला (टाइपो); क्लैंग से जोड़ा गया त्रुटि संदेश।

संपादित करें # 2: आप में से उन लोगों के लिए जो टी :: प्रकार का मतलब है।

http://en.cppreference.com/w/cpp/types/enable_if से

:

टेम्पलेट < bool बी, वर्ग टी = शून्य> struct enable_if;

यदि बी सत्य है, तो std :: enable_if में एक सार्वजनिक सदस्य टाइपपीफ प्रकार है, बराबर टी के लिए; अन्यथा, कोई सदस्य टाइपिफ़ नहीं है।

enable_if एक संरचना है। असल में, अगर enable_if के पहले टेम्पलेट पैरामीटर में मूल्यांकन की गई अभिव्यक्ति सत्य है (और ऊपर दिए गए मेरे उदाहरणों के मामले में), तो उसके बाद एक सार्वजनिक सदस्य type होगा जो दूसरे टेम्पलेट पैरामीटर के समान प्रकार होगा।

enable_if<true, int> के मामले में, enable_if :: प्रकार में int का एक प्रकार है।

+1

यह आश्चर्य की बात नहीं है कि आपका अंतिम मामला संकलित नहीं होता है। जब आप फ़ंक्शन (ओं) को केवल एक प्राप्त करते हैं तो आप दो टेम्पलेट तर्कों का उपयोग कर रहे हैं। –

+0

धन्यवाद, मुझे लगता है कि मैंने वहां गलत मामला कॉपी किया है। फिक्स्ड। – vmrob

+0

मैं एक सी ++ नोब हूं इसलिए मुझे कठोर मत करो ... क्या पहला उदाहरण काम नहीं करता क्योंकि आप पहली विधि को ओवरराइड कर रहे हैं? मुझे इसका जवाब जानने में दिलचस्पी है। मैं अगले वर्ष सी ++ सीखने की योजना बना रहा हूं। –

उत्तर

7

पहला कार्य पहले की तुलना में अधिक विशिष्ट माना जाता है।

समारोह

int foo(typename T::type) 

पैरामीटर S के लिए मूल्य के रूप में टी :: प्रकार का उपयोग करके

template <typename S,typename T> int foo(S s) 

मेल खा सकते हैं, लेकिन

int foo(S s) 

template <typename S,typename T> int foo(typename T::type) 
से मेल नहीं खाएगी

क्योंकि टी को कम नहीं किया जा सकता है।

तर्क 14.5.5.2 में सी ++ 03 मानक में और धारा 14.5.6.2 में सी ++ 11 मानक में तर्क दिया गया है।

यहां विचार है: यह देखने के लिए कि कोई फ़ंक्शन किसी अन्य से अधिक विशिष्ट है या नहीं, तो आप पहले फ़ंक्शन के लिए प्रत्येक टेम्पलेट पैरामीटर के मानों का आविष्कार करते हैं, और फिर देखें कि दूसरा फ़ंक्शन परिणामस्वरूप हस्ताक्षर से मेल खाता है या नहीं। आप दूसरे फ़ंक्शन के टेम्पलेट पैरामीटर के लिए भी मूल्यों का आविष्कार करते हैं, और देखें कि पहला फ़ंक्शन परिणामस्वरूप हस्ताक्षर से मेल खाता है या नहीं। यदि दूसरा फ़ंक्शन पहले से मेल खाता है, तो दूसरा फ़ंक्शन पहले से अधिक विशिष्ट नहीं हो सकता है। यदि, इसके अलावा, पहला फ़ंक्शन दूसरे से मेल नहीं खाता है, तो पहले दूसरे की तुलना में अधिक विशिष्ट होना चाहिए। यही वह मामला है जो आपके पास है।

2

यहाँ घटना का एक भी आगे सरलीकरण है:

#include <stdio.h> 

template<typename T> 
void foo(int arg) { 
    printf("a\n"); 
} 

template<typename T> 
void foo(T arg) { 
    printf("b\n"); 
} 

int main(int argc, char* argv[]) { 
    foo<int>(3); // prints "a" 
    foo(3);  // prints "b" 

    return 0; 
} 

खाका मानकों या तो explictly कोणीय कोष्ठक के माध्यम से पारित किया जा सकता है या वे कटौती के माध्यम से हल किया जा सकता। यदि पैरामीटर स्पष्ट रूप से निर्दिष्ट नहीं किया गया है, तो इसे फ़ंक्शन के तर्कों का उपयोग करके deducible होना चाहिए।

तो foo(3) के मामले में, टेम्पलेट 'ए' काम नहीं करेगा, क्योंकि पैरामीटर टी स्पष्ट रूप से निर्दिष्ट नहीं है और इसे घटाया नहीं जा सकता है। foo<int>(3) के मामले में, दोनों टेम्पलेट काम कर सकते हैं। वास्तव में, यदि आप टेम्पलेट 'ए' पर टिप्पणी करते हैं, तो foo<int>(3) पर कॉल "बी" प्रिंट करेगा। तो सवाल यह है कि टेम्पलेट 'ए' क्यों पसंद किया जाता है? यहाँ मुख्य "आंशिक आदेश" है:

http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fpartial_ordering_funct_templ.htm

मैं अब देखते हैं कि किसी और पहले से ही उत्तर है (मैं जल्दी से सवालों का जवाब दे पर बुरा हूँ), तो मैं सिर्फ इस लपेट के लिए अब जा रहा हूँ और कहें कि टेम्पलेट 'ए' वॉन ने कहा जैसे अधिक विशिष्ट है।

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

  • कोई संबंधित समस्या नहीं^_^