दिलचस्प पोस्ट
Google मैप इन्फोलाइन इंडेक्स ठीक से नहीं दिखा रहा है प्रत्येक ऑब्जेक्ट के लिए एक जेनेरिक रिपॉजिटरी बनाम विशिष्ट रिपॉजिटरी बनाने का लाभ? सी – निर्धारित करें कि कोई संख्या प्रधान है या नहीं ग्रिड दृश्य छँटाई: क्रमबद्ध दिशा हमेशा बढ़ते जा रहे हैं एक सरणी में व्युत्क्रम की गिनती क्या उद्देश्य-सी और कोको के लेखन के दौरान उपयोग किए जाने वाले सर्वोत्तम प्रथाएं हैं? Appcelerator टाइटेनियम मोबाइल कैसे काम करता है? डिवाइस पर SQLite डेटाबेस का स्थान बूटस्ट्रैप 3 में कॉलम से पैडिंग निकालें जावास्क्रिप्ट नोड लिस्ट को अर्रे में बदलने का सबसे तेज़ तरीका है? एक्सेंट / डायैरिटिक्स को जावास्क्रिप्ट में एक स्ट्रिंग में निकालें एक जेएसओएन स्ट्रिंग को एक हैशमैप में कनवर्ट करें बाश में दो स्ट्रिंग्स की तुलना करते हुए "कमांड नहीं मिला" त्रुटि प्राप्त करना जब आप पोस्ट का उपयोग करते हैं और आप GET का उपयोग कब करते हैं? क्वेरी के दौरान MySQL सर्वर से कनेक्शन टूट गया

इस संकेतक के माध्यम से मुझे टेम्प्लेट बेस वर्ग के सदस्यों का उपयोग क्यों करना है?

अगर नीचे दिए गए वर्ग टेम्पलेट्स नहीं थे तो मुझे derived वर्ग में बस x । हालांकि, नीचे दिए गए कोड के साथ, मुझे this->x का उपयोग करना होगा क्यूं कर?

 template <typename T> class base { protected: int x; }; template <typename T> class derived : public base<T> { public: int f() { return this->x; } }; int main() { derived<int> d; df(); return 0; } 

वेब के समाधान से एकत्रित समाधान "इस संकेतक के माध्यम से मुझे टेम्प्लेट बेस वर्ग के सदस्यों का उपयोग क्यों करना है?"

संक्षिप्त उत्तर: x एक आश्रित नाम बनाने के लिए, ताकि टेम्प्लेट पैरामीटर ज्ञात होने तक लुकअप स्थगित हो जाए।

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

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

सी ++ (और सी) में, कोड के व्याकरण को हल करने के लिए, आपको कभी-कभी यह जानना होगा कि कुछ एक प्रकार है या नहीं उदाहरण के लिए:

 #if WANT_POINTER typedef int A; #else int A; #endif static const int x = 2; template <typename T> void foo() { A *x = 0; } 

अगर ए एक प्रकार है, जो एक संकेतक घोषित करता है (ग्लोबल x छाया के अलावा कोई प्रभाव नहीं)। यदि ए वस्तु है, तो यह गुणा है (और कुछ ऑपरेटर इसे ओवरलोड करने को छोड़कर, एक rvalue बताए)। यदि यह गलत है, तो चरण 1 में इस त्रुटि का निदान होना चाहिए, यह मानक द्वारा परिभाषित किया गया है, टेम्पलेट में कोई त्रुटि होने के कारण , इसके कुछ विशेष अवसरों में नहीं। भले ही टेम्प्लेट कभी भी इन्टरिटिएटेड न हो, अगर ए एक int तो उपरोक्त कोड बीमार नहीं होता है और इसका निदान किया जाना चाहिए, जैसे कि यह foo एक टेम्प्लेट नहीं था, बल्कि एक सादा फ़ंक्शन था।

अब, मानक कहते हैं कि नाम जो टेम्पलेट पैरामीटर पर निर्भर नहीं हैं चरण 1 में हल किया जाना चाहिए। यहाँ एक आश्रित नाम नहीं है, यह एक ही बात को संदर्भित करता है, चाहे वह प्रकार T । इसलिए चरण 1 में पाया और जाँच करने के लिए टेम्पलेट परिभाषित होने से पहले इसे परिभाषित करने की आवश्यकता है।

T::A नाम होगा जो टी पर निर्भर करता है। हम चरण 1 में संभवत: पता नहीं कर सकते हैं कि यह एक प्रकार है या नहीं जिस प्रकार का अंततः T रूप में उपयोग किया जायेगा, वह अभी तक परिभाषित नहीं है, और यहां तक ​​कि अगर हम यह नहीं जानते हैं कि हमारे टेम्प्लेट पैरामीटर के रूप में किस प्रकार का उपयोग किया जाएगा। लेकिन हमारे लिए अनमोल चरण 1 चेक करने के लिए हमें व्याकरण को हल करना होगा। इसलिए मानक के नाम पर निर्भर नियम हैं- संकलक को यह अवश्य ग्रहण करना चाहिए कि वे गैर-प्रकार के हैं, जब तक कि वे विशिष्ट प्रकार के typename से योग्य नहीं होते हैं, या कुछ विशिष्ट संदर्भों में उपयोग करते हैं । उदाहरण के लिए template <typename T> struct Foo : T::A {}; , T::A को एक बेस क्लास के रूप में प्रयोग किया जाता है और इसलिए यह एक प्रकार का न तो है। यदि Foo को किसी प्रकार के साथ शुरू किया जाता है, तो उसमें नेस्टेड प्रकार A बजाय डेटा सदस्य A , जो तत्काल (चरण 2) कोड में एक त्रुटि है, टेम्पलेट (चरण 1) में कोई त्रुटि नहीं है।

लेकिन एक आश्रित आधार वर्ग के साथ एक वर्ग के टेम्पलेट के बारे में क्या?

 template <typename T> struct Foo : Bar<T> { Foo() { A *x = 0; } }; 

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

 typename std::string s = "hello, world"; 

क्योंकि std::string एक आश्रित नाम होगा, और इसलिए अन्यथा निर्दिष्ट नहीं किया जाता है, जब तक कि इसे एक गैर-प्रकार माना जा सकता है। आउच!

अपने पसंदीदा कोड ( return x; ) को अनुमति देने के साथ दूसरी समस्या यह है कि भले ही Foo से पहले Bar परिभाषित किया गया हो, और x उस परिभाषा में सदस्य नहीं है, बाद में किसी ने Baz लिए Bar के Baz को परिभाषित कर दिया है, जैसे Bar<Baz> डेटा सदस्य x , और उसके बाद Foo<Baz> इन्स्तांत होता है तो उस तत्काल में, आपका टेम्पलेट ग्लोबल x लौटने के बजाय डेटा सदस्य वापस करेगा या इसके विपरीत यदि बार की आधार टेम्पलेट परिभाषा x थी, तो वे इसके बिना एक विशेषीकरण को परिभाषित कर सकते थे, और आपका टेम्पलेट Foo<Baz> में लौटने के लिए वैश्विक x तलाश करेगा मुझे लगता है कि यह आपके लिए जितनी समस्या है, उतनी ही आश्चर्यजनक और परेशान होने का निर्णय लिया गया था, लेकिन आश्चर्यचकित त्रुटि को फेंकने के विरोध में, यह आश्चर्यजनक रूप से आश्चर्यजनक है।

इन समस्याओं से बचने के लिए, प्रभाव में मानक कहते हैं कि क्लास टेम्प्लेट्स के आश्रित आधार वर्गों को नाम के लिए नहीं खोजा जाता है, जब तक कि नाम पहले से किसी अन्य कारण के लिए निर्भर नहीं होते हैं। यह निर्भर होने से सबकुछ रोकता है क्योंकि यह किसी आश्रित आधार में पाया जा सकता है। यह भी अवांछनीय प्रभाव है जिसे आप देख रहे हैं – आपको बेस क्लास से सामग्री को अर्ह करना होगा या यह नहीं मिला है। A आश्रित बनाने के तीन आम तरीके हैं:

  • using Bar<T>::A; कक्षा में – A अब Bar<T> में कुछ संदर्भित करता है, इसलिए निर्भर
  • Bar<T>::A *x = 0; उपयोग के समय – फिर, A निश्चित रूप से Bar<T> यह गुणा है क्योंकि typename का उपयोग नहीं किया गया था, इसलिए संभवतः एक बुरा उदाहरण है, लेकिन हमें यह पता लगाने के लिए कि operator*(Bar<T>::A, x) एक रैवल्यू देता है operator*(Bar<T>::A, x) तब तक प्रतीक्षा करना होगा। कौन जानता है, शायद यह …
  • this->A; उपयोग के समय – A एक सदस्य है, इसलिए यदि यह Foo में नहीं है, तो यह आधार वर्ग में होना चाहिए, फिर मानक मानता है कि यह निर्भर करता है।

दो-चरण संकलन बेवक़ूफ़ और मुश्किल है, और आपके कोड में अतिरिक्त शब्दाडंबर के लिए कुछ आश्चर्यजनक आवश्यकताओं का परिचय देता है। बल्कि लोकतंत्र की तरह यह संभवतः काम करने का सबसे खराब संभव तरीका है, अन्य सभी के अलावा

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

आप संभवतया तर्क दे सकते हैं कि निर्भर नामों के लिए मूलभूत विपरीत होना चाहिए (किसी प्रकार किसी ऑब्जेक्ट के रूप में निर्दिष्ट नहीं होने तक प्रकार स्वीकार करें) या डिफ़ॉल्ट को अधिक संदर्भ संवेदनशील होना चाहिए ( std::string s = ""; std::string को एक प्रकार के रूप में पढ़ा जा सकता है क्योंकि कुछ नहीं व्याकरण संबंधी है, भले ही std::string *s = 0; अस्पष्ट है) फिर, मैं नहीं जानता कि नियम कितने सहमत थे। मेरा अनुमान है कि पाठ की पन्नों की संख्या की आवश्यकता होगी, बहुत सारे विशिष्ट नियम बनाने के लिए कम किया गया है, जिसके लिए संदर्भ एक प्रकार लेते हैं और जो एक गैर-प्रकार का है

(10 जनवरी 2011 से मूल उत्तर)

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


अपडेट: सी ++ 11 मानक के मसौदा N3337 से, mmichael की टिप्पणी के जवाब में:

14.6.2 निर्भर नाम [temp.dep]
[…]
3 एक क्लास या क्लास टेम्प्लेट की परिभाषा में, यदि एक बेस क्लास टेम्पलेट-पैरामीटर पर निर्भर करता है, तो बेस क्लास के स्कोप को अयोग्य नाम के दौरान क्लास टेम्प्लेट या सदस्य की परिभाषा के बिंदु पर या तत्काल के दौरान जांच नहीं की जाती है वर्ग टेम्पलेट या सदस्य

चाहे "मानक कहता है" एक जवाब के रूप में गिना जाता है, मैं नहीं जानता हम अब पूछ सकते हैं कि मानक जनादेश, लेकिन स्टीव जेसप के उत्कृष्ट उत्तर और अन्य लोगों के मुताबिक, इस सवाल का जवाब बहुत लंबा और तर्कसंगत है। दुर्भाग्य से, जब यह सी ++ मानक की बात आती है, तो मानक अधिसूचना क्यों कुछ के रूप में एक छोटी और आत्म-निहित व्याख्या देना अक्सर लगभग असंभव है; यह बाद के सवाल पर भी लागू होता है

x विरासत के दौरान छिपा हुआ है आप निम्न के माध्यम से देख सकते हैं:

 template <typename T> class derived : public base<T> { public: using base<T>::x; // added "using" statement int f() { return x; } };