C++ में template और typename: कब, कहाँ और क्यों ज़रूरी है

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

C++ में template और typename: कहाँ लगाएं और क्यों ये ज़रूरी हैं

\n\n

अगर आपने कभी C++ में टेम्पलेट के साथ कोड लिखा या पढ़ा है, तो आपने ज़रूर ऐसी स्थिति देखी होगी जब कंपाइलर अचानक से एरर देने लगता है। आपको लगता है कि कोड बिल्कुल सही है, लेकिन कंपाइलर बार-बार template या typename लगाने की ज़िद करता है। ये बात आपको जानी-पहचानी लग रही है? तो आप सही जगह पर हैं।

\n\n

यह सवाल Stack Overflow पर सबसे लोकप्रिय सवालों में से एक है (हज़ारों व्यूज़ और दर्जनों जवाब)। और इसमें कोई आश्चर्य नहीं: अनुभवी डेवलपर्स भी कभी-कभी भ्रमित हो जाते हैं कि इन कीवर्ड्स का उपयोग कहाँ करना है। इस लेख में हम एक बार और हमेशा के लिए समझ लेंगे: C++ में template और typename कहाँ, कब और क्यों लिखना चाहिए। और सबसे ज़रूरी बात - हम समझेंगे कि इस जाल में कैसे न फँसें।

\n\n

यह समस्या क्यों पैदा हुई?

\n\n

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

\n\n

कल्पना करें कि आप लिख रहे हैं:

\n\n
template<typename T>\nvoid foo() {\n    T::something * p;\n}\n
\n\n

यह क्या है? T::something पर पॉइंटर p की घोषणा? या T::something का p से गुणा? अतिरिक्त जानकारी के बिना, कंपाइलर नहीं जानता। और इसी अस्पष्टता को हल करने के लिए typename और template कीवर्ड बनाए गए।

\n\n

typename कीवर्ड: जब टाइप स्पष्ट न हो

\n\n

मुख्य नियम

\n\n

typename कीवर्ड का उपयोग कंपाइलर को यह बताने के लिए किया जाता है: "अरे, जो आगे आ रहा है वह एक टाइप है, कोई और चीज़ नहीं"। इसकी ज़रूरत उन मामलों में होती है जब नाम टेम्पलेट पैरामीटर पर निर्भर करता है, और कंपाइलर स्वयं यह निर्धारित नहीं कर सकता कि यह एक टाइप है।

\n\n

आइए एक क्लासिक उदाहरण देखें:

\n\n
template<typename T>\nclass MyClass {\npublic:\n    // typename के बिना — कंपाइलेशन एरर\n    typename T::value_type getValue() const {\n        return data;\n    }\nprivate:\n    T data;\n};\n
\n\n

यहाँ T::value_type एक डिपेंडेंट नेम है। typename के बिना, कंपाइलर सोचेगा कि value_type एक स्टैटिक डेटा मेंबर या नेस्टेड क्लास है, लेकिन टाइप नहीं। जबकि हम जानते हैं कि यह एक टाइप है (उदाहरण के लिए, int, अगर T = std::vector<int> है)।

\n\n

और कहाँ typename की ज़रूरत है?

\n\n

नियम सरल है: निम्नलिखित संदर्भों में डिपेंडेंट टाइप नेम्स से पहले typename अनिवार्य है:

\n\n
    \n
  • वेरिएबल और क्लास मेंबर की घोषणाओं में
  • \n
  • फंक्शन पैरामीटर्स में
  • \n
  • रिटर्न टाइप्स में
  • \n
  • using-डिक्लेरेशन (टाइप एलियास) में
  • \n
  • बेस क्लासेस में (अगर बेस क्लास एक डिपेंडेंट टाइप है)
  • \n
\n\n

using का उदाहरण:

\n\n
template<typename T>\nclass Container {\n    using Iterator = typename T::iterator;  // typename अनिवार्य है!\n    // ...\n};\n
\n\n

typename कब ज़रूरी नहीं है?

\n\n

कुछ महत्वपूर्ण अपवाद हैं जब typename की आवश्यकता नहीं होती:

\n\n
    \n
  • टेम्पलेट पैरामीटर लिस्ट में: template<typename T> — यहाँ typename सिंटैक्स का हिस्सा है
  • \n
  • बेस क्लासेस में: class Derived : public Base<T>::Nested — यहाँ typename की ज़रूरत नहीं
  • \n
  • कंस्ट्रक्टर की इनिशियलाइज़ेशन लिस्ट में
  • \n
  • उस संदर्भ में जहाँ नाम स्पष्ट रूप से एक टाइप है (जैसे new के बाद)
  • \n
\n\n

template कीवर्ड: जब टेम्पलेट के अंदर टेम्पलेट हो

\n\n

समस्या का सार

\n\n

template के साथ स्थिति उलटी है। इसकी ज़रूरत तब होती है जब आप किसी टेम्पलेट मेंबर को एक्सेस कर रहे हों

ब्लॉग

पुस्तक अनुशंसाएँ