2012-01-21 20 views
6
#include <iostream> 
template <class T> 
void foo(T) { 
    std::cout << "foo(T)" << std::endl; 
} 

template <class T> 
void foo(T*) { //#3 
    std::cout << "foo(T*)" << std::endl; 
} 

#define TEST 

#ifdef TEST 
template <> 
void foo(int*) { //#1 
    std::cout << "foo(int*)" << std::endl; 
} 
#else 
template <> 
void foo<int*>(int*) { //#2 
    std::cout << "foo<int*>(int*)" << std::endl; 
} 
#endif 

int main(int argc, char **argv) { 
    int* p = 0; 
    foo(p); 
    return 0; 
} 

# 1 और # 2 के बीच क्या अंतर है। अगर मैं टेस्ट, # 1 काम परिभाषित करता हूं। लेकिन अगर मैं इसे टिप्पणी करता हूं, # 3 काम ... और फ़ंक्शन टेम्पलेट विशेषज्ञता लिखने का सही तरीका कौन सा है ...फ़ंक्शन टेम्पलेट विशेषज्ञता विफल रही?

उत्तर

3

# 1 # 3 के एक समारोह टेम्पलेट विशेषज्ञता वाणी और स्वचालित रूप से टेम्पलेट मापदंडों deduces। # 2 T=int* के लिए आपके द्वारा परिभाषित किए गए पहले टेम्पलेट का एक विशेषज्ञता है (बिना किसी संख्या के, इसे # 0 पर कॉल करें)। यह # 3 का विशेषज्ञता नहीं हो सकता है क्योंकि निर्दिष्ट int* के साथ T को प्रतिस्थापित करने से int** पैरामीटर होगा।

जब आप foo पर कॉल करते हैं, तो ओवरलोड रिज़ॉल्यूशन अब सबसे अच्छा फिटिंग बेस टेम्पलेट चुनता है, फिर किसी भी मौजूदा विशेषज्ञता के लिए उस टेम्पलेट को चेक करता है। TEST परिभाषित के साथ, दो आधार टेम्पलेट्स (# 0 और # 3) हैं और # 3 एक बेहतर मिलान है और चयनित हो जाता है। फिर संकलक उस टेम्पलेट की विशेषज्ञता के लिए जांच करता है, और # 1 एक बेहतर फिट है और इसे बुलाया जा रहा है।

TEST परिभाषित किए बिना, अभी भी दो आधार टेम्पलेट्स (# 0 और # 3) हैं और # 3 एक बेहतर मिलान है और चुना जाता है।फिर संकलक उस टेम्पलेट की विशेषज्ञता के लिए जांच करता है, लेकिन चूंकि # 2 # 0 और # 3 नहीं है, इसलिए इसे नहीं माना जाता है और # 3 सिरों को बुलाया जाता है।

यह Why not Specialize Function Templates का शास्त्रीय उदाहरण है। समस्याओं को और अधिक विस्तार से समझाया गया है।

सरल उपाय बिल्कुल समारोह टेम्पलेट्स विशेषज्ञ नहीं है, लेकिन बस विशेष प्रकार के लिए नए भार के जोड़ने है:

// no template, just a normal function 
void foo(int*) { 
    std::cout << "foo(int*)" << std::endl; 
} 
0

मैं वास्तव में यह नहीं बता सकता कि कौन सा फ़ंक्शन # 2 विशेषज्ञ होना चाहिए, या बिल्कुल बेहद जटिल ओवरलोड रिज़ॉल्यूशन नियम कॉल करने के लिए फ़ंक्शन का चयन करेंगे।

मुझे पता है कि आप अक्सर काम करने के लिए की आवश्यकता नहीं है, लेकिन इसके बजाय अधिभार पर भरोसा कर सकते हैं। int* के लिए एक समारोह प्राप्त करने के लिए आप बस जरूरत

void foo(int*) { 
    std::cout << "foo(int*)" << std::endl; 
} 

एक गैर टेम्पलेट समारोह टेम्पलेट्स के ऊपर वरीयता दी जाएगी, जब तक कि पैरामीटर से मेल खाता।

+0

कुछ संदर्भों जहां यह सुविधाजनक या टेम्पलेट तर्क निर्दिष्ट करने के लिए आवश्यक है (रों) कर रहे हैं । स्पष्ट स्थान जहां तर्क निर्दिष्ट करना आवश्यक है, यदि टेम्पलेट तर्क गैर-कटौती नहीं है। स्थान जहां यह सुविधाजनक है, जब आपको तर्क को उचित रूप से परिवर्तित प्रकार पर निर्देशित करने की आवश्यकता होती है। जब आप स्पष्ट रूप से तर्क निर्दिष्ट करना चाहते हैं तो आप अक्सर ओवरलोडिंग का उपयोग नहीं कर सकते हैं। –

2

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

template <typename T> void foo(T); 
template <typename T> void foo(T*); 

उत्तरार्द्ध को देखते हुए एक सूचक तर्क के लिए एक बेहतर मुकाबला नहीं है। एक बार उचित प्राथमिक टेम्पलेट मिलने के बाद, संकलक इस प्राथमिक टेम्पलेट की संभावित विशेषज्ञता की तलाश करता है। हालांकि, आपका उदाहरण # 2 वास्तव में एक पॉइंटर तर्क लेने वाले फ़ंक्शन टेम्पलेट का एक विशेषज्ञ नहीं है, हालांकि इसमें एक पॉइंटर तर्क शामिल है। आप प्राथमिक घोषणा

template <typename T> void foo(T*); 

लेने के लिए और आप स्पष्ट रूप से निर्दिष्ट टेम्पलेट तर्क int* द्वारा T की जगह यदि आप

template <> void foo<int*>(int**); 

है, घोषणा

template <> void foo<int*>(int*); 

कुछ अलग है मिलता है। आप शायद अभी जब टेम्पलेट तर्क को निर्दिष्ट सूचक कम करना चाहते:

template <> void foo<int>(int*); 
+1

आप क्यों कहते हैं कि '# 2' संकलित नहीं होना चाहिए? यह पहला टेम्पलेट फिट करता है, 'टी = int * 'के साथ' टेम्पलेट शून्य foo (टी)'। –

+0

@AaronMcDaid ओह, क्षमा करें, आप सही हैं: मैंने नहीं देखा कि दो प्राथमिक टेम्पलेट्स हैं और सवाल यह है कि इनमें से किस का उपयोग किया जाता है। हालांकि, चूंकि प्राथमिक मिलान का सूचक संस्करण संस्करण बेहतर विकल्प है, इसलिए यह टेम्पलेट चुना जाएगा, भले ही इसका विशेषज्ञता बेहतर मिलान हो: अधिभार संकल्प प्राथमिक टेम्पलेट्स के संदर्भ में काम करता है। एक बार फ़ंक्शन टेम्पलेट का निर्णय लेने के बाद, उचित विशेषज्ञता का चयन किया जाता है। मुझे लगता है, मुझे इसे प्रतिबिंबित करने के लिए जवाब संपादित करना चाहिए ... –

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