2012-12-17 26 views
8

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

template <> 
void Foo<char,int>::f() {} 

लेकिन आंशिक विशेषज्ञता एक साथ विफल ":

template <typename T, typename S> 
class Foo 
{ 
public: 
    void f(){} 
    void g(){} 
}; 

हम, हम पूरी तरह से किसी भी एक सदस्य समारोह विशेषज्ञ कर सकते हैं करना चाहते हैं तो निम्न टेम्पलेट परिभाषा पर विचार करें (MinGW जी ++ 4.6.2 के साथ संकलित) अधूरा प्रकार के अवैध उपयोग 'वर्ग फू < ...>' "त्रुटि:

template <typename T, typename S> 
void Foo<T,S*>::f() 
{ 
} 

template <typename T> 
void Foo<T,int>::f() 
{ 
} 

और मैं समझ नहीं क्यों। क्या यह किसी समस्या से बचने के लिए एक सचेत डिज़ाइन निर्णय है जिसे मैं पूर्ववत नहीं कर सकता? क्या यह एक निरीक्षण है?

अग्रिम धन्यवाद।

+0

लगभग डुप्लिकेट: http://stackoverflow.com/questions/12335762/partial-specialization-of-member- कार्यक्षमता और http://stackoverflow.com/questions/165101/invalid-use-of-incomplete-type- त्रुटि-साथ-आंशिक-टेम्पलेट विशेषज्ञता। – jogojapan

उत्तर

6

आंशिक विशेषज्ञता केवल वर्ग टेम्पलेट्स (§14.5.5 द्वारा वर्णित) और सदस्य टेम्पलेट्स के लिए मौजूद है की धारणा (एक टेम्पलेट वर्ग के यानी सदस्यों को बताया कि खुद को कर रहे हैं टेम्पलेट काम करता है, §14.5.5.3/2 द्वारा वर्णित)। यह क्लास टेम्पलेट्स के सामान्य सदस्यों के लिए मौजूद नहीं है, न ही यह फ़ंक्शन टेम्पलेट्स – के लिए मौजूद है क्योंकि यह मानक द्वारा वर्णित नहीं है।

अब, आप एक सदस्य समारोह का आंशिक विशेषज्ञता की परिभाषा देकर कि तर्क कर सकता है, के रूप में

template <typename T> 
void Foo<T,int>::f() 
{ } 

आप परोक्ष वर्ग टेम्पलेट का आंशिक विशेषज्ञता को परिभाषित इस तरह: Foo<T,int>।यही कारण है कि, हालांकि, स्पष्ट रूप से मानक से की संभावना से इनकार है:

(§14.5.5/2) Each class template partial specialization is a distinct template and definitions shall be provided for the members of a template partial specialization (14.5.5.3).

(§14.5.5.3/1) [...] The members of the class template partial specialization are unrelated to the members of the primary template. Class template partial specialization members that are used in a way that requires a definition shall be defined; the definitions of members of the primary template are never used as definitions for members of a class template partial specialization. [...]

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

दूसरी ओर, स्पष्ट विशेषज्ञता की धारणा (या पूर्ण विशेषज्ञता, जैसा कि आप इसे बुलाते हैं) वर्ग टेम्पलेट्स के सदस्य कार्यों के लिए मौजूद है। यह स्पष्ट स्टैंडर्ड द्वारा वर्णित है:

(§14.7.3/14) A member or a member template of a class template may be explicitly specialized for a given implicit instantiation of the class template, even if the member or member template is defined in the class template definition. [...]

,, वर्ग टेम्पलेट काम करता है के बाकी के इन्स्टेन्शियशन इसलिए सदस्यों की स्पष्ट विशेषज्ञताओं के लिए:

(§14.7.3/1) An explicit specialization of any of the following:
[...]
— member function of a class template
[...]
can be declared by a declaration introduced by template<>; [...]

§14.7.3/14 विवरण का वर्णन करता है निहित – यह प्राथमिक टेम्पलेट परिभाषा, या परिभाषित किए गए किसी भी आंशिक विशेषज्ञता से लिया गया है।

+0

वही है जो मैं ढूंढ रहा हूं। मानक के प्रासंगिक भागों को समझने में सक्षम नहीं था। धन्यवाद :) – StoryTeller

3

मुझे लगता है कि अंतर यह है कि जब आप पहली बार (वैध) स्पष्ट f की विशेषज्ञता करना है कि: आप Foo<char,int> का एक अंतर्निहित इन्स्टेन्शियशन कर रहे हैं

template <> 
void Foo<char,int>::f() {} 

। लेकिन जब आप के साथ आंशिक विशेषज्ञता का प्रयास करें:

template <typename T> 
void Foo<T,int>::f() 
{ 
} 

संकलक विशेषज्ञता करने से पहले परोक्ष Foo<T,int> का दृष्टांत की आवश्यकता होगी, लेकिन यह ऐसा नहीं कर सकते उसकी वजह से T। और यह विफल रहता है।

आप देख सकते हैं कि निम्न कोड के साथ मामला है:

test.cpp:15:7: error: specialization of ‘Foo<char, int>’ after instantiation 
test.cpp:15:7: error: redefinition of ‘class Foo<char, int>’ 
test.cpp:2:7: error: previous definition of ‘class Foo<char, int>’ 

clang++ के साथ एक सा स्पष्ट है:

test.cpp:15:7: error: explicit specialization of 'Foo<char, int>' after instantiation 
class Foo<char,int> 
     ^~~~~~~~~~~~~ 
test.cpp:11:6: note: implicit instantiation first required here 
void Foo<char,int>::f() 
    ^
+0

धन्यवाद, वह अंतर्दृष्टिपूर्ण था :) – StoryTeller

5

template <typename T, typename S> 
class Foo 
{ 
public: 
    void f(){} 
    void g(){} 
}; 


template <> 
void Foo<char,int>::f() //line 11 
{} 

template <> 
class Foo<char,int> //line 15 
{}; 

g++ के साथ यह त्रुटियों देता है

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

चलिए एक सेकंड के लिए टेम्पलेट्स भूल जाते हैं। सी ++ में, कक्षा के नाम और फ़ंक्शन नामों के बीच एक बड़ा अंतर है। किसी दिए गए दायरे में केवल कक्षा की एक परिभाषा हो सकती है। (आप विभिन्न घोषणाएं कर सकते हैं, लेकिन वे सभी एक ट्रू क्लास को संदर्भित करते हैं।) इसलिए नाम वास्तव में कक्षा की पहचान करता है।

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

तो, कोई बड़ा सौदा नहीं है। आप ये सब जानते थे, है ना? लेकिन अब चलिए टेम्पलेट्स पर वापस जाएं।

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

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

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

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

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

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

आशा है कि मदद करता है ...

+0

यह वास्तव में मदद करता है, वास्तव में एक बड़ा सौदा है। धन्यवाद :) – StoryTeller

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