विषय पर बढ़ें

अंतिम अद्यतन:2026-10-12

STL typename सोर्स कोड विश्लेषण

STL के निचले स्तर के सोर्स कोड में नीचे की कुछ पंक्तियाँ हैं जिनमें typedef का typename के साथ उपयोग हुआ है — ये देखकर बहुत जटिल लगती हैं, आख़िर इनका अर्थ क्या है, आज हम इन्हें एक साथ विश्लेषित करेंगे!

template<typename _Iterator>
struct iterator_traits
{
  typedef typename _Iterator::iterator_category iterator_category;
  typedef typename _Iterator::value_type        value_type;
  typedef typename _Iterator::difference_type   difference_type;
  typedef typename _Iterator::pointer           pointer;
  typedef typename _Iterator::reference         reference;
};

typename की सामान्य उपयोग-विधियाँ

पहले typename की सामान्य उपयोग-विधियाँ सीख लेते हैं:

template <typename T>
int compare(const T &a, const T &b)
{
    return a>b?a:b;
}

ऊपर दिया गया केवल एक उदाहरण प्रोग्राम है; यदि बड़ा-छोटा तुलना करने वाला कोड अधिक संपूर्ण रूप से लिखना हो तो स्पेशलाइज़्ड संस्करणों पर भी विचार करना होगा। शायद आपके मन में आया होगा कि उपरोक्त कोड में typename के स्थान पर class भी लिखा जा सकता है — बिल्कुल सही! तो यहाँ एक प्रश्न उठता है: क्या इन दोनों तरीकों में कोई अंतर है? C++ Primer देखने के बाद पता चलता है कि दोनों पूर्णतः समान हैं.

क्लास स्कोप

क्लास के बाहर से क्लास के भीतर के नामों तक पहुँचने के लिए क्लास-स्कोप ऑपरेटर का उपयोग किया जा सकता है। MyClass::name जैसे कॉल सामान्यतः तीन प्रकार के होते हैं: स्टैटिक डेटा मेंबर, स्टैटिक मेंबर फंक्शन और नेस्टेड टाइप:

struct MyClass {
    static int A; //静态成员
    static int B(){cout<<"B()"<<endl; return 100;} //静态函数
    typedef int C;  //嵌套类型
    struct A1 { //嵌套类型
        static int s;
    };
};

कॉल करते समय सीधे कॉल किया जा सकता है:

cout<<MyClass::A<<endl;
cout<<MyClass::B()<<endl;
MyClass:C c;
...

पूर्ण उदाहरण का प्रयास

आइए एक typename उदाहरण पर लौटें:

template <class T>
void foo() {
    T::iterator * iter;
    // ...
}

इस कोड का उद्देश्य क्या है? अधिकांश लोगों की पहली प्रतिक्रिया यह होगी: लेखक एक पॉइंटर iter परिभाषित करना चाहता है जो क्लास स्कोप T में निहित iterator टाइप की ओर इशारा करे। संभवतः ऐसा कोई स्ट्रक्चर मौजूद हो जिसमें iterator टाइप शामिल हो:

struct MyIterator {
    struct iterator {

    };
};

कॉल इस प्रकार है:

foo<MyIterator>();

इस तरह iter वाली पंक्ति एकदम स्पष्ट हो जाती है — यह MyIterator::iterator टाइप का एक पॉइंटर है। हमने ऐसा अनुमान लगाया, पर क्या वास्तव में ऐसा ही है?

परंतु यदि बात T::iterator जैसी हो तो? T टेम्प्लेट का एक टाइप पैरामीटर है; टेम्प्लेट के इंस्टैंशिएट होने तक यह ज्ञात नहीं होता कि यह कौन-सा टाइप है, भीतर के iterator की तो बात ही छोड़ दें। पहले की क्लास-स्कोप चर्चा से हम जानते हैं कि T::iterator वास्तव में निम्न तीन में से कोई भी टाइप हो सकता है:

  • स्टैटिक डेटा मेंबर
  • स्टैटिक मेंबर फंक्शन
  • नेस्टेड टाइप

पिछले उदाहरण में ContainsAType::iterator एक नेस्टेड टाइप है, इसमें कोई समस्या नहीं। परंतु यदि वह स्टैटिक डेटा मेंबर हो तो? यदि foo टेम्प्लेट फंक्शन को इंस्टैंशिएट करने वाला टाइप इस तरह का हो:

struct MyIterator {
    static int iterator;
};

तब T::iterator * iter; कंपाइलर द्वारा MyIterator::iterator * iter; के रूप में इंस्टैंशिएट होगा — यह क्या है? आगे वाला भाग एक स्टैटिक मेंबर वेरिएबल है, टाइप नहीं, अतः यह एक गुणा (multiplication) एक्सप्रेशन बन जाता है; केवल इतना है कि iter यहाँ परिभाषित नहीं है, इसलिए कंपाइलर त्रुटि देगा:

error: no type named ‘iterator’ in ‘struct MyIterator’

typename

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

अतः यदि आप कंपाइलर को सीधे बताना चाहते हैं कि T::iterator एक टाइप है, वेरिएबल नहीं, तो बस typename से युक्त करें:

template <class T>
void foo() {
    typename T::iterator * iter;
}

इस तरह कंपाइलर यह निश्चित कर सकता है कि T::iterator एक टाइप है, और इंस्टैंशिएशन के समय तक प्रतीक्षा करने की आवश्यकता नहीं रहती, जिससे पहले उल्लिखित अस्पष्टता दूर हो जाती है।

सोर्स कोड विश्लेषण

STL सोर्स कोड पर लौटते हैं

template<typename _Iterator>
struct iterator_traits
{
  typedef typename _Iterator::iterator_category iterator_category;
  typedef typename _Iterator::value_type        value_type;
  typedef typename _Iterator::difference_type   difference_type;
  typedef typename _Iterator::pointer           pointer;
  typedef typename _Iterator::reference         reference;
};

ऊपर का कोड देखते ही बात एकदम स्पष्ट हो जाती है — बस typename के उपयोग से कंपाइलर को बताया गया है कि _Iterator::iterator_category एक टाइप है, और फिर typedef से उसका नाम बदल दिया गया है; शेष भी इसी प्रकार हैं!

संबंधित विषय

टिप्पणियाँ