2009-07-24 12 views
10

नीचे दिए गए कोड को देखते हुए, foo(T*) फ़ंक्शन का चयन क्यों किया गया है?ओवरलोडेड टेम्पलेट फ़ंक्शंस से चुनने के नियम क्या हैं?

अगर मैं यह (foo(T*)) कोड अभी भी संकलित करता है तथा सही ढंग से काम करता है, लेकिन जी ++ v4.4.0 (और साथ ही शायद अन्य compilers) दो foo() कार्यों उत्पन्न होगा निकालें: चार के लिए एक [4] और चार के लिए एक [ 7]।

#include <iostream> 
using namespace std; 

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

template< typename T > 
void foo(T*) 
{ 
    cout << "foo(T*)" << endl; 
} 

int main() 
{ 
    foo("bar"); 
    foo("foobar"); 
    return 0; 
} 
+1

मजेदार, एमएसवीसी 9 डीबग प्रतीकों में "foo " फ़ंक्शन का नाम है, लेकिन जाहिर है क्योंकि यह कार्यान्वयन को पहचानता है समान है - दोनों कॉल के लिए समान कार्यान्वयन का उपयोग करता है। - दिलचस्प सवाल, वैसे भी। – peterchen

+0

AFAIK VC टेम्पलेट उदाहरणों को फोल्ड करता है जिसके परिणामस्वरूप समान कोड होता है। – sbi

+1

जीसीसी (4.2.4) दोनों foo और foo को ओओ 3 तक कुछ भी करने में तत्कालता बनाता है, जहां यह इन्हें पूरी तरह से इन कार्यान्वयन के लिए पूरी तरह से बढ़ाता है और इसे इनलाइन बनाता है। –

उत्तर

6

औपचारिक रूप से, रूपांतरण अनुक्रमों की तुलना करते समय, लैवलू परिवर्तनों को अनदेखा कर दिया जाता है। , lvalue परिवर्तन (int[N] ->int*, void() ->void(*)()), और अन्य - रूपांतरण की तरह योग्यता समायोजन (>T const*T*), कई श्रेणियों में बांटा जाता है।

आपके दो उम्मीदवारों के बीच एकमात्र अंतर एक अंतराल परिवर्तन है। स्ट्रिंग अक्षर वे सरणी हैं जो पॉइंटर्स में परिवर्तित होते हैं। पहला उम्मीदवार संदर्भ के अनुसार सरणी स्वीकार करता है, और इस प्रकार एक अंतराल परिवर्तन की आवश्यकता नहीं होगी। दूसरे उम्मीदवार को एक लालू परिवर्तन की आवश्यकता है।

तो, यदि दो उम्मीदवार हैं कि दोनों टेम्पलेट विशेषज्ञताएं केवल रूपांतरणों को देखकर समान रूप से व्यवहार्य हैं, तो नियम यह है कि दोनों का आंशिक क्रम करके अधिक विशिष्ट व्यक्ति चुना जाता है।

हम पहले पैरामीटर सूची के लिए कुछ अद्वितीय प्रकार Q चुनते हैं, तो अपने समारोह पैरामीटर सूची

void(T const&); 
void(T*); 

के अपने हस्ताक्षर को देखकर दोनों के बीच तुलना और दूसरा पैरामीटर सूची के खिलाफ मैच के लिए कोशिश करते हैं, हम मिलान कर रहे हैं के खिलाफ Q। यह असफल हो जाएगा, क्योंकि Q एक सूचक नहीं है। इस प्रकार, दूसरा कम से कम पहले के रूप में विशिष्ट है।

यदि हम दूसरी तरफ करते हैं, तो हम Q* से T const& के विरुद्ध मेल खाते हैं। संदर्भ गिरा दिया गया है और अपरिवर्तनीय क्वालीफायरों को अनदेखा किया जाता है, और शेष TQ* बन जाता है। यह आंशिक क्रम के उद्देश्य के लिए एक सटीक मैच है, और इस प्रकार पहले उम्मीदवार के खिलाफ दूसरी की रूपांतरित पैरामीटर सूची की कटौती सफल होती है। चूंकि दूसरी दिशा (दूसरे के खिलाफ) सफल नहीं हुई, दूसरा उम्मीदवार अधिक पहले से विशिष्ट है - और इसके परिणामस्वरूप, ओवरलोड रिज़ॉल्यूशन दूसरी पसंद करेगा, अगर अन्यथा अस्पष्टता होगी।

13.3.3.2/3 में:

स्टैंडर्ड रूपांतरण अनुक्रम एस 1 मानक रूपांतरण अनुक्रम S2 अगर [तुलना में एक बेहतर रूपांतरण अनुक्रम है ...पहचान रूपांतरण अनुक्रम किसी भी गैर की किसी परिणाम को माना जाता है;]

  • एस 1 (S2 का एक उचित परिणाम को विहित प्रपत्र 13.3.3.1.1 द्वारा परिभाषित किया गया, किसी भी lvalue परिवर्तन को छोड़कर में रूपांतरण दृश्यों की तुलना है -identity रूपांतरण अनुक्रम) या, यदि नहीं है कि [...]
फिर

13.3.3/1

  • आईसीएसआई (एफ) को अंतर्निहित रूपांतरण अनुक्रम को इंगित करने देता है जो सूची में i-th तर्क को व्यवहार्य फ़ंक्शन के i-th पैरामीटर के प्रकार में परिवर्तित करता है F.3.3.3.1 निहित रूपांतरण अनुक्रमों को परिभाषित करता है और 13.3.3.2 परिभाषित करता है कि यह क्या परिभाषित करता है एक अंतर्निहित रूपांतरण अनुक्रम के लिए एक बेहतर रूपांतरण अनुक्रम या किसी अन्य से बदतर रूपांतरण अनुक्रम होने का मतलब है।

इन परिभाषाओं को देखते हुए, एक व्यवहार्य समारोह एफ 1 फिर अगर सभी तर्कों के लिए मैं, आईसीएसआई (एफ 1) नहीं आईसीएसआई (F2) से भी बदतर एक रूपांतरण अनुक्रम है एक व्यवहार्य समारोह F2 तुलना में एक बेहतर कार्य माना परिभाषित किया गया है, और [...]

  • F1 और F2 समारोह टेम्पलेट विशेषज्ञताओं हैं, और F1 के लिए समारोह टेम्पलेट 14.5.5.2 में वर्णित आंशिक आदेश नियमों के अनुसार एफ 2 के लिए टेम्पलेट की तुलना में अधिक विशिष्ट है, या, यदि नहीं है कि , [...]

अंत में, यहां निहित रूपांतरणों की तालिका दी गई है जो मानक रूपांतरण अनुक्रम में 13.3.3.1.1/3 पर भाग ले सकते हैं।

Conversion sequences http://img259.imageshack.us/img259/851/convs.png

+0

यह गैर-टेम्पलेट वरीयता का मामला नहीं है, क्योंकि कंपाइलर द्वारा चुने जाने के लिए कोई गैर-टेम्पलेट फ़ंक्शन नहीं है। तथ्य यह है कि कॉन्स char [] टी से अधिक टी * के लिए एक बहुत करीब मैच है (क्योंकि कॉन्स चार [] और कॉन्स char * बराबर हैं)। –

+0

क्षमा करें मैंने दूसरे से पहले टेम्पलेट <...> खंड को अनदेखा किया। निश्चित :) –

+0

आपका दावा है कि 'टी *' का मिलान करीब है, हालांकि :) –

-1

कारण "" एक चार *, जो foo के लिए (टी *) समारोह पूरी तरह से फिट बैठता है। जब आप इसे हटाते हैं, तो संकलक इसे foo (T &) के साथ काम करने का प्रयास करेगा, जिसके लिए आपको स्ट्रिंग वाले चार सरणी के संदर्भ में पारित करने की आवश्यकता होती है।

कंपाइलर एक फ़ंक्शन उत्पन्न नहीं कर सकता है जो char के संदर्भ प्राप्त करेगा, क्योंकि आप पूरी सरणी पारित कर रहे हैं, इसलिए इसे इसे अव्यवस्थित करना होगा।

+0

गलत भी। कृपया अनुमान मत लगाओ। '" "' 'char const [1]' है। आप 'संदर्भ पास' भी नहीं कर सकते हैं। अभिव्यक्तियों में हमेशा गैर-संदर्भ प्रकार होता है। –

+0

मैंने कभी नहीं कहा कि यह नहीं है (असल में, यह "" है, सह का कॉन्स [2]), मेरा मतलब यह है कि टी * फ़ंक्शन को चुनना पसंद है, अगर यह मौजूद है। 'गुजरने वाले रेफरी' कथन के लिए, मैं यह कहने की कोशिश कर रहा था कि कम पसंदीदा विकल्प टी एंड है, जो मूल रूप से टी का संदर्भ है (इस मामले में, char [N] के संदर्भ में), हालांकि मेरी प्रतिक्रिया काफी अच्छी नहीं थी सही, उस के साथ आपका अधिकार। अगर मैं गलत हूं तो मुझे सही करें (और आपके बाद, मैं सिर्फ अपनी पोस्ट हटा दूंगा, क्योंकि यह आपकी तुलना में उपयोगी नहीं है, जो कि अधिक पूर्ण है)। –

0

अधिभार संकल्प नियमों के आधार पर क्योंकि संकलक चार के बीच कोई फर्क पड़ता है, स्ट्रिंग शाब्दिक (स्थिरांक चार []), टी & से टी * के करीब हैं (C++ Templates: The Complete Guide के परिशिष्ट बी एक अच्छा सिंहावलोकन है) [] और चार *, तो टी * निकटतम मैच है (कॉन्स टी * एक सटीक मैच होगा)।

वास्तव में, आप जोड़ सकते हैं यदि:

template<typename T> 
void foo(const T* a) 
+0

'टी *' किसी भी करीबी मैच से नहीं है। 'Void f (char const (&)[1]); शून्य एफ (char const *); int main() {f (" ");}': यह कॉल, जो गैर-टेम्पलेट्स का उपयोग करके ऊपर की स्थिति जैसा दिखता है, अस्पष्ट है। –

+0

@ litb: टी * इस मामले में टी और उससे बहुत करीब मैच है। हां, यदि आप एक विशिष्ट SIZE (& [N]) शामिल करते हैं, तो यह संदिग्ध बनाता है, लेकिन टी * एक मनमानी सरणी से मेल खाता है जो टी एंड करता है। –

+0

@ निक, जबकि शून्य फू (टी एक्स []) शून्य फू (टी * एक्स) का पर्याय है, इसका मतलब यह नहीं है कि आप शून्य फू (टी एंड) को टी के साथ सरणी प्रकार नहीं कर सकते हैं।समकक्ष शून्य foo (ArrayBaseType (&) [ArraySize]) – AProgrammer

2

पूरा जवाब:

template<typename T> 
void foo(const T[] a) 

(जो आप नहीं कर सकते हैं), अपने संकलक आपको बता होगा इस समारोह की एक नई परिभाषा है कि काफी तकनीकी है।

सबसे पहले, स्ट्रिंग अक्षर में char const[N] प्रकार है।

फिर char const[N] से char const* पर एक अंतर्निहित रूपांतरण है।

तो आपका टेम्पलेट फ़ंक्शन मेल खाता है, संदर्भ बाध्यकारी का उपयोग करके, एक अंतर्निहित रूपांतरण का उपयोग कर रहा है। जब वे अकेले होते हैं, तो आपके टेम्पलेट फ़ंक्शन दोनों कॉल को संभालने में सक्षम होते हैं, लेकिन जब वे दोनों उपस्थित होते हैं, तो हमें यह समझाना होगा कि क्यों दूसरा foo (टी = char const [n] के साथ तत्काल) पहले की तुलना में बेहतर मिलान है (टी = चार के साथ तत्काल)।यदि आप (litb द्वारा दिए गए) से अधिक भार नियमों को देखें, तो

void foo(char const (&x)[4)); 

और

void foo(char const* x); 

ambigous है के बीच विकल्प (नियम काफी जटिल हैं, लेकिन आप के साथ गैर टेम्पलेट कार्यों लिख कर जांच कर सकते हैं ऐसे हस्ताक्षर और देखें कि संकलक शिकायत करता है)। उस स्थिति में, विकल्प दूसरे को बनाया जाता है क्योंकि वह एक और अधिक विशिष्ट होता है (फिर से इस आंशिक क्रम के नियमों को जटिल बना दिया जाता है, लेकिन इस मामले में ऐसा इसलिए होता है क्योंकि आप char const[N] को char const* पर पास कर सकते हैं लेकिन char const* पर नहीं char const[N] उसी तरह void bar(char const*)void bar(char*) से अधिक विशिष्ट है क्योंकि आप char* को char const* पर पास कर सकते हैं लेकिन vise-versa नहीं)।

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