2010-09-11 13 views
5

सी ++ सीखना, फ़ंक्शन टेम्पलेट्स पर आया। अध्याय टेम्पलेट विशेषज्ञता का उल्लेख किया।सी ++ - फ़ंक्शन टेम्पलेट विशेषज्ञता का उद्देश्य क्या है? इसका उपयोग कब करें?

  1. template <> void foo<int>(int);

  2. void foo(int);

क्यों विशेषज्ञ जब आप दूसरे का उपयोग कर सकते हैं? मैंने सोचा था कि टेम्पलेट सामान्यीकृत करने के लिए मानते थे। एक विशिष्ट डेटा प्रकार के लिए फ़ंक्शन को विशेषज्ञता देने का क्या मतलब है जब आप केवल नियमित फ़ंक्शन का उपयोग कर सकते हैं?

जाहिर है, टेम्पलेट विशेषज्ञता किसी कारण से मौजूद है। इसका इस्तेमाल कब किया जाना चाहिए? मैंने सटर के "Why not Specialize..." आलेख को पढ़ा लेकिन मुझे एक आम आदमी के संस्करण की आवश्यकता है क्योंकि मैं बस यह सामान सीख रहा हूं।

+0

शायद पता ले रहा है: 'और foo बनाम (शून्य (...)) foo' या वापसी प्रकार का विशेषज्ञ? – Anycorn

+0

[फंक्शन टेम्पलेट विशेषज्ञता महत्व और आवश्यकता] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/2197141/function-template- विशेषकरण- महत्व- और- छूट) – jamesdlin

उत्तर

11

मुख्य अंतर यह है कि पहले मामले में आप विशेष प्रकार के लिए कार्यान्वयन के साथ संकलक प्रदान कर रहे हैं, जबकि दूसरे में आप एक असंबंधित गैर-टेम्पलेटेड फ़ंक्शन प्रदान कर रहे हैं।

यदि आप हमेशा कंपाइलर को प्रकारों का अनुमान लगाते हैं, तो टेम्पलेट पर कंपाइलर द्वारा गैर-टेम्पलेट किए गए फ़ंक्शंस को प्राथमिकता दी जाएगी, और संकलक टेम्पलेट के बजाय नि: शुल्क फ़ंक्शन को कॉल करेगा, इसलिए एक गैर-टेम्पलेटेड फ़ंक्शन जो मेल खाता है अधिकांश मामलों में तर्कों का विशेषज्ञता समान प्रभाव होगा।

दूसरी ओर, यदि किसी भी स्थान पर आप टेम्पलेट तर्क (संकलक अनुमान दे के बजाय) उपलब्ध है, तो यह सिर्फ सामान्य टेम्पलेट कॉल करेंगे और शायद अप्रत्याशित परिणाम:

template <typename T> void f(T) { 
    std::cout << "generic" << std::endl; 
} 
void f(int) { 
    std::cout << "f(int)" << std::endl; 
} 
int main() { 
    int x = 0; 
    double d = 0.0; 
    f(d); // generic 
    f(x); // f(int) 
    f<int>(x); // generic !! maybe not what you want 
    f<int>(d); // generic (same as above) 
} 

आप तो टेम्पलेट के int के लिए एक विशेषज्ञता प्रदान की थी, अंतिम दो कॉल उस विशेषज्ञता को कॉल करेंगे और सामान्य टेम्पलेट नहीं।

+1

'एफ 'चीज़ के बारे में अच्छा बिंदु। –

+0

कई और अंतर हैं। ओवरलोड्स योग्य नामों के साथ अच्छी तरह से नहीं खेलते हैं, जब तक कि सभी एक ही दायरे में घोषित न हों। मानक पुस्तकालय कार्यों को विस्तारित करने के लिए अधिग्रहण की आवश्यकता होती है, अधिभार नहीं।एडीएल की चंचलता अधिक अधिभार के साथ बढ़ती है। – Potatoswatter

+0

यद्यपि यदि आपका इंटरफ़ेस बताता है कि एक फ़ंक्शन (-टेम्पलेट) 'एफ' है जिसे आप कॉल कर सकते हैं, तो आपको काम करने के लिए 'f ' जैसी किसी चीज़ पर भरोसा करने की अनुमति नहीं है और आपको इसकी आवश्यकता नहीं है क्योंकि टेम्पलेट तर्क वैसे भी घटाया जाता है। मानक लाइब्रेरी कार्यक्षमता को विस्तारित किया जा सकता है जैसे कि एडीएल (जैसे 'std :: swap') के साथ, जबकि नामस्थान' std' में विशेषज्ञता करके अक्सर ऐसा करना संभव नहीं है (उदाहरण के लिए आप इसे टेम्पलेट तर्क के लिए विशेषज्ञ नहीं कर सकते - यह आंशिक विशेषज्ञता की आवश्यकता होगी)। लूप के लिए श्रेणी पूरी तरह से एडीएल पर आधारित है। –

1

आप विशेषज्ञता का उपयोग जब आप एक विशिष्ट वर्ग सामान्य विधि कुशल हो सकता है के लिए पता कर सकते हैं।

template<typename T> 
void MySwap(T& lhs, T& rhs) 
{ 
    T tmp(lhs); 
    lhs = rhs; 
    rhs = tmp; 
} 

अब वैक्टर के लिए मेरे स्वैप काम करेंगे, लेकिन बहुत कुशल नहीं है। लेकिन मुझे यह भी पता है कि std :: वेक्टर अपनी स्वयं की स्वैप() विधि लागू करता है।

template<> 
void MySwap(std::vector<int>& lhs,std::vector<int>& rhs) 
{ 
    lhs.swap(rhs); 
} 

कृपया std :: स्वैप की तुलना करें, जो बहुत अधिक जटिल और बेहतर लिखा गया है। यह दिखाने के लिए सिर्फ एक उदाहरण है कि MySwap() का एक सामान्य संस्करण काम करेगा लेकिन हमेशा कुशल नहीं हो सकता है। नतीजतन मैंने दिखाया है कि इसे एक विशिष्ट टेम्पलेट विशेषज्ञता के साथ और अधिक कुशल कैसे बनाया जा सकता है।

हम यह भी निश्चित रूप से एक ही प्रभाव को प्राप्त करने ओवरलोडिंग उपयोग कर सकते हैं।

void MySwap(std::vector<int>& lhs,std::vector<int>& rhs) 
{ 
    lhs.swap(rhs); 
} 

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

+0

सवाल यह था कि विशेषज्ञता के बजाय ओवरलोडिंग का उपयोग क्यों नहीं किया जाए? –

+0

मार्टिन, मुझे लगता है कि वह, पूछ रहा था क्यों विशेषज्ञता बजाय MySwap की एक गैर टेम्पलेट अधिभार() प्रदान करते हैं। –

4

मैं व्यक्तिगत रूप से फ़ंक्शन टेम्पलेट को विशेषज्ञता देने से कोई लाभ नहीं देख सकता। इसे किसी भिन्न फ़ंक्शन टेम्पलेट या गैर-टेम्पलेट फ़ंक्शन द्वारा ओवरलोड करना तर्कसंगत रूप से बेहतर है क्योंकि इसकी हैंडलिंग अधिक सहज है और यह समग्र रूप से अधिक शक्तिशाली है (प्रभावी रूप से टेम्पलेट को ओवरलोड करके, आपके पास टेम्पलेट का आंशिक विशेषज्ञता है, भले ही तकनीकी रूप से इसे आंशिक कहा जाता है आदेश)।

हर्ब सटर ने एक लेख Why not specialize function templates? लिखा है जहां वह या तो उन्हें अधिभारित करने या उन्हें लिखने के पक्ष में फ़ंक्शन टेम्पलेट्स को विशेषज्ञता प्रदान करता है ताकि वे केवल क्लास टेम्पलेट के स्थैतिक फ़ंक्शन पर आगे बढ़ सकें और इसके बजाय क्लास टेम्पलेट को विशेषज्ञता दे सकें।

+0

चूंकि फ़ंक्शन टेम्पलेट स्पेशलाइजेशन ओवरलोडिंग प्रक्रिया में भाग नहीं लेते हैं, इसलिए 'फ़ंक्शन टेम्पलेट विशेषज्ञता' एक लाभ है क्योंकि यह ओवरलोड रिज़ॉल्यूशन – Chubsdad

+0

@Chubsdad को गति देता है: मैं संकलन समय को अनुकूलित करने का कभी भी प्रयास नहीं करता। कोड को संसाधित करने के लिए संकलक लेने के समय से अधिक आधार पर निर्णय किए जाने चाहिए। –

+0

आपको संकलक स्वयं को आजमाएं और अनुकूलित करना चाहिए :) –

0

मुझे यह बहुत महत्वपूर्ण लगता है। आप इसका उपयोग कर सकते हैं क्योंकि आप वर्चुअल विधि का उपयोग करेंगे। वर्चुअल तरीकों में कोई बिंदु नहीं होगा जब तक कि उनमें से कुछ विशिष्ट नहीं थे। मैंने इसे सरल प्रकारों (int, short, float) और ऑब्जेक्ट्स, ऑब्जेक्ट पॉइंटर्स और ऑब्जेक्ट रेफरेंस के बीच अंतर करने के लिए बहुत कुछ उपयोग किया है। एक उदाहरण serialize/unserialize तरीकों कि बुला वस्तुओं को क्रमानुसार/unserialize विधि है, जबकि साधारण प्रकार एक धारा के लिए सीधे लिखा जाना चाहिए द्वारा वस्तुओं को संभालने होगी।

+0

वर्चुअल विधि टेम्पलेट नहीं हो सकता है। – Potatoswatter

+0

@Potato: मुझे लगता है कि वह समानांतर चित्रकारी कर रहा था। यदि आप वर्क वर्चुअल घोषित करते हैं, लेकिन कोई व्युत्पन्न कक्षाएं इसे अधिभारित नहीं करती हैं, तो आभासी प्रकार बर्बाद हो जाता है। यह सुनिश्चित करने के लिए, यह बहुत अच्छा समानांतर नहीं है। –

-1

टेम्पलेट विशेषज्ञता के लिए एक मामला ओवरलोडिंग के साथ संभव नहीं है टेम्पलेट मेटा-प्रोग्रामिंग के लिए है। निम्नलिखित पुस्तकालय से वास्तविक कोड है जो संकलन समय पर कुछ सेवाएं प्रदान करता है।

namespace internal{namespace os{ 
    template <class Os> std::ostream& get(); 

    struct stdout{}; 
    struct stderr{}; 

    template <> inline std::ostream& get<stdout>() { return std::cout; } 
    template <> inline std::ostream& get<stderr>() { return std::cerr; } 
}} 

// define a specialization for os::get() 
#define DEFINE_FILE(ofs_name,filename)\ 
    namespace internal{namespace os{      \ 
     struct ofs_name{         \ 
      std::ofstream ofs;        \ 
      ofs_name(){ ofs.open(filename);}      \ 
      ~ofs_name(){ ofs.close(); delete this; }     \ 
     };           \ 
     template <> inline std::ostream& get<ofs_name>(){ return (new ofs_name())->ofs; } \ 
    }}            \ 
    using internal::os::ofs_name; 
+0

यह सही नहीं दिख रहा है। 'stdout' एक ऑब्जेक्ट है (और इसे एक मैक्रो होने की अनुमति है, जो कि सबकुछ बहुत अधिक खंडित करता है) इसलिए इसे तर्क प्रकार 'क्लास ओएस' से मेल नहीं करना चाहिए। यदि कुछ भी है, तो आपको 'टेम्पलेट < FILE * > std :: ostream और get(); ' – Potatoswatter

+0

@Potatoswatter की आवश्यकता है: इसकी आंतरिक (नेमस्पेस आंतरिक)। बाद में इसे उचित नाम के तहत पुस्तकालय के सार्वजनिक (वैश्विक नहीं) नामस्थान में लाया गया है। टेम्पलेट भी अच्छा है। – Daniel

0

एक ही नाम पर एक से अधिक भार के समान काम करते हैं। विशेषज्ञता सटीक उसी चीज़, लेकिन विभिन्न प्रकारों पर करती है। अधिभारों का एक ही नाम है, लेकिन अलग-अलग क्षेत्रों में परिभाषित किया जा सकता है। एक टेम्पलेट को केवल एक गुंजाइश में घोषित किया जाता है, और एक विशेषज्ञता घोषणा का स्थान महत्वहीन होता है (हालांकि यह संलग्न नामस्थान के दायरे में होना चाहिए)।

उदाहरण के लिए, यदि आप std::swap का विस्तार अपने प्रकार का समर्थन करने के लिए, तुम इतनी विशेषज्ञता से, क्योंकि समारोह std::swap, नहीं बस swap नाम पर है, और <algorithm> में कार्य काफी विशेष रूप से ::std::swap(a, b); के रूप में यह कॉल करने के लिए सही होगा करना चाहिए। इसी प्रकार किसी भी नाम के लिए जो नामस्थानों पर अलियाकृत हो सकता है: नाम को अर्हता प्राप्त करने के बाद फ़ंक्शन को कॉल करना "कठिन" हो सकता है।

स्कॉइंग समस्या argument-dependent lookup द्वारा आगे उलझन में है। अक्सर एक अधिभार पाया जा सकता है क्योंकि इसे इसके तर्कों में से किसी एक के प्रकार के निकटता में परिभाषित किया जाता है। (उदाहरण के लिए, एक स्थिर सदस्य समारोह के रूप में।) इस से पूरी तरह से अलग कैसे टेम्पलेट विशेषज्ञता पाया जा होता है, जो केवल टेम्पलेट के नाम को देख, और फिर स्पष्ट विशेषज्ञता को देख एक बार टेम्पलेट लक्ष्य के रूप में चुना गया है के द्वारा होता है कॉल का

एडीएल के नियम मानक का सबसे भ्रमित हिस्सा हैं, इसलिए मैं इस पर निर्भरता से बचने के बहुमूल्य पर स्पष्ट विशेषज्ञता पसंद करता हूं।

+0

खैर, औपचारिक रूप से अधिभार वास्तव में केवल एक गुंजाइश में होता है। यदि दो कार्य घोषणा अलग-अलग क्षेत्रों में हैं, तो वे प्रत्येक ओहेर को अधिभारित नहीं करते हैं। लेकिन वास्तविक बिंदु मैं बनाना चाहता हूं - कल्पना करें कि आपके पास 'टेम्पलेट क्लास कंटेनर {...}; '- आप उस कंटेनर पर काम करने के लिए' std :: swap' विशेषज्ञ कैसे करना चाहते हैं? यह संभव नहीं है, और आप एडीएल का उपयोग कर ऐसा करने की संभावना समाप्त कर रहे हैं। इसी कारण से, सामान्य कार्य केवल 'std :: swap' को कॉल नहीं करेंगे क्योंकि यह कार्यान्वयन की पूरी तरह से लंगड़ा गुणवत्ता होगी। –

+1

मुझे लगता है कि सामान्य पैटर्न '{std :: swap का उपयोग करके लिख रहा है; स्वैप (ए, बी); } 'जो एडीएल और 'std :: swap' की विशेषज्ञता दोनों घोषणाओं को पाता है। मुझे अधिभार करना आसान लगता है। प्रत्येक व्यक्ति को फिट होना चाहिए जैसा कि वह फिट देखता है :) –

+0

@ जोहान्स: आपके पास एक व्यावहारिक समाधान है, लेकिन मानक यह निर्दिष्ट नहीं करता है। बिंदु एक वर्ग के लिए 'स्वैप' को लागू करना है जैसे कि यह '' द्वारा पाया गया है। (हां, केवल "सर्वश्रेष्ठ" गुंजाइश का उपयोग एक मैच खोजने के लिए किया जाता है ... लेकिन निराशा का स्रोत भी हो सकता है! वहां एक स्पष्ट प्राथमिकता उलटा है, क्योंकि उपयोगकर्ता शायद सबसे महत्वपूर्ण कारक के रूप में स्कोपिंग विवरण नहीं देख पाएगा।) – Potatoswatter

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