2009-03-13 11 views
45

यह थोड़ी देर के बाद से जीसीसी ने मुझे इस के साथ पकड़ा, लेकिन यह आज हुआ। लेकिन मैंने कभी नहीं समझा है कि क्यों जीसीसी को टेम्पलेट्स के भीतर टाइपपीफ टाइपनाम की आवश्यकता है, जबकि वीएस और मुझे लगता है कि आईसीसी नहीं है। क्या typedef typename चीज "बग" या ओवरस्ट्रिट मानक है, या कुछ ऐसा जो कंपाइलर लेखकों तक छोड़ा गया है?मुझे g ++ में typedef typename का उपयोग करने की आवश्यकता क्यों है लेकिन वीएस नहीं?

जो लोग नहीं जानते कि मैं यहाँ क्या मतलब के लिए एक नमूना है:

template<typename KEY, typename VALUE> 
bool find(const std::map<KEY,VALUE>& container, const KEY& key) 
{ 
    std::map<KEY,VALUE>::const_iterator iter = container.find(key); 
    return iter!=container.end(); 
} 

ऊपर कोड (और शायद आईसीसी में) वी.एस. में संकलित है, लेकिन जीसीसी में विफल रहता है क्योंकि यह इस तरह चाहता है:

template<typename KEY, typename VALUE> 
bool find(const std::map<KEY,VALUE>& container, const KEY& key) 
{ 
    typedef typename std::map<KEY,VALUE>::const_iterator iterator; //typedef typename 
    iterator iter = container.find(key); 
    return iter!=container.end(); 
} 

नोट: यह एक वास्तविक कार्य नहीं है जिसका मैं उपयोग कर रहा हूं, लेकिन कुछ मूर्खतापूर्ण समस्या है जो समस्या का प्रदर्शन करती है।

+4

जी ++ में इसकी आवश्यकता है, क्योंकि जी ++ मानक के साथ अधिक अनुपालनशील है। वीएस टेम्पलेटिसेशन पार्सिंग के इस हिस्से पर थोड़ा ढीला था (जिसने अधिक जटिल टेम्पलेट्स में अन्य समस्याओं का नेतृत्व किया है)। –

+0

हां लेकिन मानक फ्रिगिन ऐसा क्यों करता है? मैंने समान कोड से निपटाया है! –

उत्तर

52

टाइपनाम को मानक द्वारा आवश्यक है। टेम्पलेट संकलन के लिए दो चरण सत्यापन की आवश्यकता होती है। पहले पास के दौरान कंपाइलर को वास्तव में टाइप प्रतिस्थापन की आपूर्ति किए बिना टेम्पलेट सिंटैक्स को सत्यापित करना होगा। इस चरण में, std :: map :: iterator को मान माना जाता है। यदि यह किसी प्रकार को इंगित करता है, तो टाइपनाम कीवर्ड आवश्यक है।

यह आवश्यक क्यों है? वास्तविक कुंजी और VALUE प्रकारों को प्रतिस्थापित करने से पहले, संकलक गारंटी नहीं दे सकता कि टेम्पलेट विशिष्ट नहीं है और यह विशेषज्ञता इटरेटर कीवर्ड को कुछ और के रूप में फिर से परिभाषित नहीं कर रही है।

आप इस कोड के साथ देख सकते हैं:

class X {}; 
template <typename T> 
struct Test 
{ 
    typedef T value; 
}; 
template <> 
struct Test<X> 
{ 
    static int value; 
}; 
int Test<X>::value = 0; 
template <typename T> 
void f(T const &) 
{ 
    Test<T>::value; // during first pass, Test<T>::value is interpreted as a value 
} 
int main() 
{ 
    f(5); // compilation error 
    X x; f(x); // compiles fine f: Test<T>::value is an integer 
} 

आखिरी कॉल यह दर्शाता है कि च के पहले टेम्पलेट संकलन चरण के दौरान() टेस्ट :: मूल्य एक मूल्य लेकिन की इन्स्टेन्शियशन के रूप में व्याख्या की गई थी एक त्रुटि के साथ विफल टेस्ट <> प्रकार एक्स के साथ टेम्पलेट एक प्रकार पैदा करता है।

+3

विफलता मामले –

+2

का अच्छा उदाहरण मुझे लगता है कि आपने दो कॉलों पर 'f',' f (X()) पर अपनी टिप्पणियां मिश्रित की हैं; 'f (5) के दौरान सफल होता है; 'एक संकलन त्रुटि है। वैसे भी, एमएसवीसी इसे ठीक से संभालता है - ऐसा लगता है कि 'टेस्ट :: मान' एक मान या एक प्रकार है जब तक टेम्पलेट को तत्काल नहीं किया जाता है। हालांकि, यह क्लास टेम्पलेट के सदस्यों के लिए ऐसा नहीं करता है। –

+0

@ सुमुडू: आप सही हैं, मैंने उपरोक्त अधिक स्पष्ट कोड में 'एफ (एक्स())' कॉल को भी सही किया है। यदि एमएसवीसी चेक को तब तक देरी कर देता है जब तक कि प्रकार को तत्काल नहीं किया जाता है तो एमएसवीसी मानक का अनुपालन नहीं कर रहा है। –

31

ठीक है, जीसीसी वास्तव में typedef - typename पर्याप्त है। यह काम करता है:

#include <iostream> 
#include <map> 

template<typename KEY, typename VALUE> 
bool find(const std::map<KEY,VALUE>& container, const KEY& key) 
{ 
    typename std::map<KEY,VALUE>::const_iterator iter = container.find(key); 
    return iter!=container.end(); 
} 

int main() { 
    std::map<int, int> m; 
    m[5] = 10; 
    std::cout << find(m, 5) << std::endl; 
    std::cout << find(m, 6) << std::endl; 
    return 0; 
} 

यह एक संदर्भ संवेदनशील पार्सिंग समस्या का एक उदाहरण है। प्रश्न में पंक्ति का अर्थ केवल इस फ़ंक्शन में सिंटैक्स से स्पष्ट नहीं है - आपको यह जानने की आवश्यकता है कि std::map<KEY,VALUE>::const_iterator एक प्रकार है या नहीं।

अब, मुझे एक उदाहरण के बारे में सोचना प्रतीत नहीं होता है ... ::const_iterator एक प्रकार को छोड़कर हो सकता है, यह भी एक त्रुटि नहीं होगी। तो मुझे लगता है कि संकलक यह पता लगा सकता है कि में एक प्रकार का होना है, लेकिन गरीब संकलक (लेखकों) के लिए यह मुश्किल हो सकता है।

मानक के अनुभाग 14.6/3 द्वारा litb के अनुसार मानक को typename के उपयोग की आवश्यकता है।

+0

यहां, मुझे लगता है कि आपको "टाइपनाम" से शुरू होने वाली लाइन में कुंजी, VALUE का अर्थ है। उस परिवर्तन के साथ, यह मेरे लिए संकलित करता है। :) – unwind

+0

मैंने प्रश्न पर आपकी टिप्पणी देखी और इसे अभी ठीक कर दिया :) –

+0

हाँ, यह वास्तव में आवश्यक है। संदर्भ के लिए 14.6/3 –

4

ऐसा लगता है कि वीएस/आईसीसी typename कीवर्ड जहां भी सोचता है यह आवश्यक है। ध्यान दें कि यह एक खराब बात है (टीएम) - संकलक को यह तय करने के लिए कि आप चाहते हैं। यह आवश्यक होने पर typename छोड़ने और पोर्टेबिलिटी दुःस्वप्न होने की बुरी आदत को बढ़ावा देकर इस मुद्दे को और जटिल करता है। यह निश्चित रूप से मानक व्यवहार नहीं है। सख्त मानक मोड या Comau में आज़माएं।

+5

यह एक खराब बात होगी यदि संकलक इतना विचित्र था। वास्तव में, यह केवल टूटी हुई कोड पर कर रहा है। टूटी हुई कोड संकलित करने के खिलाफ मानक में वास्तव में कोई प्रतिबंध नहीं है। हालांकि अभी भी एक चेतावनी (नैदानिक) होना चाहिए। – MSalters

3

यह माइक्रोसॉफ़्ट सी ++ कंपाइलर में एक बग है - आपके उदाहरण में, std :: map :: iterator एक प्रकार नहीं हो सकता है (आप कुंजी, VALUE पर विशिष्ट std :: map प्राप्त कर सकते हैं ताकि std :: map: : इटरेटर उदाहरण के लिए एक चर था)।

जीसीसी आपको सही कोड लिखने के लिए मजबूर करता है (भले ही आपका मतलब स्पष्ट था), जबकि माइक्रोसॉफ्ट कंपाइलर सही ढंग से अनुमान लगाता है कि आपका क्या मतलब है (भले ही आपने जो कोड लिखा था वह गलत था)।

+1

दरअसल, ऐसा लगता है कि एमएसवीसी यह देखने के लिए जांच करेगा कि क्या std :: map :: iterator एक प्रकार है या निर्णय लेने से पहले नहीं। मेरे पास मानक की प्रति नहीं है लेकिन यह गैर-अनुरूप व्यवहार की तरह प्रतीत होता है, लेकिन इसका मतलब यह है कि यह कुछ गलत प्रोग्रामों को सही और संकलित करेगा (सही करने की कोशिश करें), सही त्रुटियों में त्रुटियों को पेश नहीं करेगा। –

+1

हां, यह एक बग है क्योंकि संकलक अवैध कोड के लिए निदान जारी नहीं करता है। –

+2

अवैध कोड जैसी कोई चीज़ नहीं है। एक निदान केवल तभी जरूरी है जब कार्यक्रम खराब हो। – Yttrill

2

यह ध्यान दिया जाना चाहिए कि मूल्य/प्रकार दयालु मुद्दा मौलिक समस्या नहीं है। प्राथमिक समस्या पार्सिंग है।

template<class T> 
void f() { (T::x)(1); } 

यह बताने का कोई तरीका नहीं है कि यह एक कास्ट या फ़ंक्शन कॉल है जब तक कि टाइपनाम कीवर्ड अनिवार्य नहीं है। उस स्थिति में, उपर्युक्त कोड में फ़ंक्शन कॉल होता है। सामान्य तौर पर पसंद, पूरी तरह पार्स करने forgoing बिना देरी नहीं किया जा सकता सिर्फ टुकड़ा

(a)(b)(c) 

मामले में पर विचार तुम्हें याद नहीं किया, कलाकारों सी में समारोह कॉल की तुलना में अधिक पूर्वता है, एक कारण Bjarne चाहता था समारोह शैली डाले। इसलिए यह संभव बताने के लिए नहीं है अगर इसके बाद के संस्करण का मतलब है

(a)(b) (c) // a is a typename 

या

(a) (b)(c) // a is not a typename , b is 

या

(a)(b) (c) // neither a nor b is a typename 

जहाँ मैं समूहीकरण इंगित करने के लिए अंतरिक्ष डाला।

नोट "templatename" कीवर्ड को "टाइपनाम" के समान कारण के लिए आवश्यक है, आप सी/सी ++ में अपनी तरह के बिना चीजों को पार्स नहीं कर सकते हैं।

+0

एमएसवीसी इस समस्या के लिए एक अविश्वसनीय रूप से सरल समाधान का उपयोग करता है: यह टेम्पलेट फ़ंक्शन के अंदर कोड को पार्स नहीं करता है जब तक कि टेम्पलेट को एक विशिष्ट टी आईएमओ के साथ तत्काल नहीं किया जाता है जो कि डेवलपर्स के लिए बहुत अधिक सुखद समाधान है, "अतिरिक्त-" , "टाइपनाम" और "टेम्पलेट" कीवर्ड, और कई अतिरिक्त टाइपिफ़ीफ जिन्हें नामों को फिर से परिभाषित करने के लिए * पहले से परिभाषित * बेस क्लास में हैं। (हाँ, हाँ, मुझे पता है, एमएसवीसी मानक नहीं है - लेकिन इसका उपयोग करना आसान है।) – Qwertie

+0

हालांकि यह व्यवहार संभावनाओं को एक खुलासा करता है कि दो अलग-अलग तत्कालताओं के अर्थशास्त्र मौजूदा गरीब सी ++ नियमों की तुलना में अधिक अलग हैं। – Yttrill

+0

सच है, लेकिन मेरे टेम्पलेट कोड को कई मानक सिंकैक्टिक शोर जोड़कर सही मानक सी ++ में परिवर्तित करने के बाद दर्जनों घंटों खर्च करने के बाद, मेरे कुछ पसंदीदा: "ऑपरेटर = 'की घोषणा गैर-फ़ंक्शन के रूप में" , "बहुत कम टेम्पलेट-पैरामीटर-सूचियां", "अपेक्षित प्राथमिक अभिव्यक्ति '>' टोकन से पहले") ... मैं सी ++ के आधिकारिक नियमों को नाराज करने आया हूं। – Qwertie