13

मैंने हाल ही में सी ++ 11 वैरिएडिक टेम्पलेट फ़ंक्शन उपयोग को चित्रित करने के लिए यह उदाहरण कोड बनाया है।अग्रेषित घोषित टेम्पलेट कार्यों की आवश्यकता

template <typename Head, typename... Tail> void foo (Head, Tail...); 
template <typename... Tail> void foo (int, Tail...); 
void foo() {} 

template <typename... Tail> 
void foo (int x, Tail... tail) 
{ 
    std :: cout << "int:" << x; 
    foo (tail...); 
} 

template <typename Head, typename... Tail> 
void foo (Head x, Tail... tail) 
{ 
    std :: cout << " ?:" << x; 
    foo (tail...); 
} 

foo (int (123), float (123)); // Prints "int:123 ?:123.0" 

तो पहले दो लाइनों जो आगे की घोषणा foo छोड़े गए हैं तो यह बजाय int:123int:123 प्रिंट करता है। यह एक निश्चित अनुभवी और जानकार सी ++ प्रोग्रामर आश्चर्यचकित हुआ।

वह आश्वस्त था कि आगे की घोषणाओं को जरूरी नहीं होना चाहिए क्योंकि शरीर को दो चरण के लुकअप के दूसरे चरण तक तत्काल नहीं किया जाएगा। वह सोचता है कि कंपाइलर (जीसीसी 4.6) में एक बग है।

मेरा मानना ​​है कि संकलक सही है क्योंकि दो foodifferent base template functions कर रहे हैं और मूल टेम्पलेट के चुनाव पहले चरण के दौरान बंद कर दिया-इन करने की जरूरत है या फिर आप इसे के सभी संस्करणों से पहले foo instantiating द्वारा एक परिभाषा नियम का उल्लंघन कर सकता है परिभाषित किया गया है और फिर बाद में (विचार करें कि लिंकर मानता है कि अनावश्यक टेम्पलेट फ़ंक्शन परिभाषाएं समान, विनिमय करने योग्य और निष्कासित हैं)।

तो, कौन सही है?


ऊपर से जुड़े GOTW अच्छी तरह से बताते हैं कि कैसे और क्यों समारोह टेम्पलेट्स आंशिक रूप से विशेषज्ञ नहीं है, लेकिन variadic टेम्पलेट कार्यों के अस्तित्व भ्रम में जोड़ने के लिए लगता है - कि foo<int,Tail...> के एक आंशिक विशेषज्ञता होना चाहिए अंतर्ज्ञान foo<Head,Tail...> कम से कम मेरे लिए गैर-भिन्न कार्यों के लिए अंतर्ज्ञान से अधिक मजबूत है।

+0

Fwiw, बजना ++ जीसीसी के रूप में ही उत्पादन पैदा करता है। – Cubbi

+0

मैं बिल्कुल यकीन नहीं है, लेकिन ऐसा लगता है कि जब foo() कहा जाता है, यह foo (पूंछ ...) foo (int, पूंछ ...) जो तब की कोशिश करता है का दृष्टांत और चाहिए जब आगे घोषणा वहाँ नहीं है , यह foo (हेड, टेल ...) नहीं देखेगा और केवल foo (int, tail ...) को चुना जा सकता है ... आप बार (x) पर कॉल भी जोड़ सकते हैं; foo में (int, पूंछ ...) और फिर एक बार() सभी foo() फ़ंक्शन के बाद घोषित ... यह नहीं मिलेगा भी – PlasmaHH

उत्तर

8

जीसीसी (और क्लैंग) सही हैं। एमएसवीसी इसे गलत समझ पाएगा क्योंकि यह लुक-अप को सही तरीके से लागू नहीं करता है।

ऐसा लगता है कि, आपके सहयोगी से एक गलतफहमी है। लुक-अप के लिए नियम हैं:

  • बेस टेम्पलेट समारोह से पहले यह instantiated है

नोट विशेष टेम्पलेट समारोह घोषित करने की आवश्यकता से पहले यह एक परिभाषा

  • से कहा जाता है की घोषणा करने की आवश्यकता : उन नियमों में फ्री-फ़ंक्शंस के लिए आवेदन किया जाता है, कक्षा के भीतर कोई आगे की घोषणा की आवश्यकता नहीं होती है

    ध्यान दें कि एक परिभाषा भी घोषणा के रूप में कार्य करती है, यह आपके उदाहरण में अनावश्यक है, आगे बढ़ने के लिए int संस्करण घोषित करें।

    सही उदाहरण:

    template <typename T> void foo(T);    // declare foo<T> 
    
    template <typename T> void bar(T t) { foo(t); }// call foo<T> (dependent context) 
    
    template <> void foo<int>(int);    // declare specialiaztion foo<int> 
    
    void bar(int i) { foo(i); }     // instantiate foo<T> with int 
                   // which is the specialization 
    

    अगर वहाँ आधार टेम्पलेट उपलब्ध है, यह एक त्रुटि है। यदि तत्कालता से पहले विशेषज्ञता घोषित नहीं की जाती है, तो इसका उपयोग नहीं किया जाएगा, और इसके बाद, इसका मतलब है कि ओडीआर नियम का उल्लंघन (यदि कोई अन्य तत्काल विशेषज्ञता का उपयोग करता है)।

    स्टैंडर्ड (C++ 0x एफ डी आई) से:

    14.6.4.2

    1. एक समारोह कॉल कि टेम्पलेट पैरामीटर पर निर्भर करता है के लिए, उम्मीदवार कार्यों पाए जाते हैं सामान्य लुकअप नियमों का उपयोग (3.4.1, 3.4.2, 3.4.3) को छोड़कर:

    - अनुपयुक्त नाम लुकअप (3.4.1) या योग्य नाम लुकअप (3.4.3) का उपयोग करके लुकअप के हिस्से के लिए , केवल समारोह घोषणाएं टेम्पलेट परिभाषा संदर्भ पाए जाते हैं।

    - देखने संबद्ध नेमस्पेस (3.4.2) का उपयोग कर के भाग के लिए, केवल समारोह घोषणाओं या तो टेम्पलेट परिभाषा संदर्भ या टेम्पलेट इन्स्टेन्शियशन संदर्भ में पाया पाए जाते हैं।

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

    ध्यान दें कि निर्दिष्ट पैराग्राफ नियमित कार्यों के लिए हैं।

  • +1

    मुझे यकीन है कि कैसे अपने उदाहरण सवाल के लिए प्रासंगिक है नहीं कर रहा हूँ। प्रश्न में कोई स्पष्ट विशेषज्ञता नहीं है, केवल ओवरलोडेड फ़ंक्शन टेम्पलेट्स हैं। –

    +0

    @ चार्ल्स: मैंने पत्थर के साथ दो पक्षियों पर हमला करने का अवसर लिया। –

    6

    दो चरण देखने मिलेगा:

    • कार्य करता है जो परिभाषा के बिंदु पर दिखाई दे रहे हैं, और
    • कार्यों इन्स्टेन्शियशन के बिंदु पर ADL द्वारा पाया जा सकता है।

    template <typename Head, typename... Tail> void foo (Head x, Tail... tail) एडीएल द्वारा नहीं पाया जा सकता है, इसलिए यदि परिभाषा के बिंदु पर दिखाई नहीं दे रहा है तो यह बिल्कुल नहीं मिलेगा।

    दूसरे शब्दों में, जीसीसी सही है।