टेम्प्लेट में कीवर्ड 'टाइपनेम' और 'क्लास' का अंतर?


504

टेम्प्लेट के लिए मैंने दोनों घोषणाएं देखी हैं:

template < typename T >
template < class T >

क्या फर्क पड़ता है?

और निम्नलिखित उदाहरणों में वास्तव में उन खोजशब्दों का क्या मतलब है (जर्मन विकिपीडिया लेख से टेम्पलेट्स के बारे में लिया गया)?

template < template < typename, typename > class Container, typename Type >
class Example
{
     Container< Type, std::allocator < Type > > baz;
};

जवाबों:


430

typenameऔर classएक टेम्पलेट निर्दिष्ट करने के मूल मामले में विनिमेय हैं:

template<class T>
class Foo
{
};

तथा

template<typename T>
class Foo
{
};

समतुल्य हैं।

कहा जाता है कि, ऐसे विशिष्ट मामले हैं जहां typenameऔर के बीच अंतर है class

पहले एक निर्भर प्रकारों के मामले में है। typenameयह घोषित करने के लिए प्रयोग किया जाता है कि आप एक नेस्टेड प्रकार को संदर्भित कर रहे हैं जो किसी अन्य टेम्पलेट पैरामीटर पर निर्भर करता है, जैसे कि typedefइस उदाहरण में:

template<typename param_t>
class Foo
{
    typedef typename param_t::baz sub_t;
};

दूसरा वह जो आप वास्तव में अपने प्रश्न में दिखाते हैं, हालांकि आप इसे महसूस नहीं कर सकते हैं:

template < template < typename, typename > class Container, typename Type >

किसी टेम्पलेट टेम्पलेट को निर्दिष्ट करते समय , classकीवर्ड को उपरोक्त के रूप में उपयोग किया जाना चाहिए - यह इस मामले में विनिमेय नहीं है (ध्यान दें: चूंकि C ++ 17 दोनों कीवर्ड इस मामले में अनुमत हैं)typename

classकिसी टेम्पलेट को स्पष्ट रूप से त्वरित करते समय आपको इसका उपयोग करना चाहिए :

template class Foo<int>;

मुझे यकीन है कि ऐसे अन्य मामले हैं जिन्हें मैंने याद किया है, लेकिन नीचे की रेखा है: ये दो कीवर्ड समतुल्य नहीं हैं, और ये कुछ सामान्य मामले हैं जहां आपको एक या दूसरे का उपयोग करने की आवश्यकता है।


45
पिछले एक बहुत अधिक तथ्य यह है कि आप वर्ग या संरचना का उपयोग करना चाहिए का एक विशेष मामला है, एक वर्ग को परिभाषित करने के लिए टाइपनेम नहीं। जाहिर है कि आपके पहले दो बिट्स कोड के साथ प्रतिस्थापित नहीं किए जा सकते template <typename T> typename Foo {};, क्योंकि फू <टी> सबसे निश्चित रूप से एक वर्ग है।
स्टीव जेसोप

2
std::vector<int>::value_typeएक आश्रित प्रकार नहीं है, आपको typenameवहाँ ज़रूरत नहीं है - आपको केवल इसकी ज़रूरत है यदि कोई प्रकार टेम्पलेट पैरामीटर पर निर्भर करता है, तो कहोtemplate<class T> struct C { typedef typename std::vector<T>::value_type type; };
Georg Fritzsche

2
और फिर, param_tएक आश्रित प्रकार नहीं है। आश्रित प्रकार वे नाम हैं जो टेम्पलेट पैरामीटर पर निर्भर होते हैं , उदाहरण के लिए foo<param_t>::some_type, स्वयं टेम्पलेट पैरामीटर नहीं।
जॉर्ज फ्रिट्जशे

2
एक C ++ 1z प्रस्ताव N4051 आपको उपयोग करने की अनुमति देगा typename, अर्थात template <typename> typename C
user4112979

4
G ++ के अनुसार GCC 5, अब टेम्पलेट टेम्पलेट पैरामीटर में टाइपनेम की अनुमति देता है
चोनोसोस

95

टेम्पलेट मापदंडों के नामकरण के लिए, typenameऔर classसमतुल्य हैं। §14.1.2:

टेम्पलेट-पैरामीटर में वर्ग और टाइपनेम के बीच कोई शब्दार्थ अंतर नहीं है।

typenameहालाँकि, टेम्पलेट का उपयोग करते समय एक और संदर्भ में संभव है - कंपाइलर पर संकेत देने के लिए कि आप एक निर्भर प्रकार का उल्लेख कर रहे हैं। §14.6.2:

टेम्प्लेट घोषणा या परिभाषा में उपयोग किया जाने वाला नाम और जो टेम्प्लेट-पैरामीटर पर निर्भर है, यह माना जाता है कि एक प्रकार का नाम नहीं दिया जाता है जब तक कि लागू नाम लुकअप में एक प्रकार का नाम नहीं मिलता है या नाम कीवर्ड टाइपनेम द्वारा योग्य है।

उदाहरण:

typename some_template<T>::some_type

typenameसंकलक के बिना सामान्य रूप से यह नहीं बताया जा सकता है कि आप किसी प्रकार का उल्लेख कर रहे हैं या नहीं।


2
मैं नियम को समझता हूं, लेकिन क्या वास्तव में संकलक को कुछ प्रकार से आंतरिक रूप से some_template <T> का इलाज करने से रोकता है? क्षमा करें यदि मुझे कुछ स्पष्ट याद आ रहा है।
बैटब्रेट

23

जबकि कोई तकनीकी अंतर नहीं है, मैंने देखा है कि दोनों ने कुछ अलग चीजों का इस्तेमाल किया है।

ऐसे टेम्पलेट के लिए जिसे T के रूप में किसी भी प्रकार को स्वीकार करना चाहिए, जिसमें बिल्ट-इन (जैसे एक सरणी) शामिल है

template<typename T>
class Foo { ... }

एक टेम्पलेट के लिए जो केवल काम करेगा जहां टी एक वास्तविक वर्ग है।

template<class T>
class Foo { ... }

लेकिन ध्यान रखें कि यह विशुद्ध रूप से एक स्टाइल चीज़ है जिसका कुछ लोग उपयोग करते हैं। मानक द्वारा अनिवार्य या संकलक द्वारा लागू नहीं


15
मैं इसका उल्लेख करने के लिए आपको दोषी नहीं ठहराता, लेकिन मुझे लगता है कि यह नीति बहुत ही गलत है, क्योंकि प्रोग्रामर कुछ सोचने के लिए समय निकालते हैं, इससे कोई फर्क नहीं पड़ता ("क्या मैंने सही इस्तेमाल किया है?") कुछ ऐसा इंगित करने के लिए जो 'नहीं' टी मैटर ("क्या कोई अंतर्निहित प्रकार मौजूद है जो इस टेम्पलेट पैरामीटर के लिए आवश्यक इंटरफ़ेस को लागू करता है?")। यदि टेम्पलेट पैरामीटर के किसी भी सदस्य का उपयोग किया जाता है ( T t; int i = t.toInt();) तो आपको एक "वास्तविक वर्ग" की आवश्यकता होती है, और यदि आप आपूर्ति intकरते हैं तो आपका कोड संकलित नहीं होगा T...
स्टीव जेसप

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

2
चूंकि उनका मतलब एक ही था, कृपया केवल एक का उपयोग करें। अन्यथा, यह इनलाइन {, जब तक कि यह मंगलवार का उपयोग न हो, और तब आप अगली पंक्ति {का उपयोग कर रहे हों] जैसे हों।
पॉल ड्रेपर

+1 मैं कभी-कभी खुद ऐसा करता हूं ... classतात्पर्य यह है कि आप केवल "मूल्य" की उम्मीद नहीं कर रहे हैं, शायद कुछ ऑपरेटरों का समर्थन कर रहे हैं, निर्माण या / या असाइनमेंट की प्रतिलिपि बना रहे हैं, लेकिन विशेष रूप से कुछ सदस्य-पहुंच शब्दार्थों का समर्थन करने वाले एक प्रकार की आवश्यकता है। घोषणा पर सबसे तेज नज़र उम्मीदों को स्थापित करती है और उदाहरणों के लिए बिल्ट-इन प्रकारों की आपूर्ति को हतोत्साहित करती है classजब वह निश्चित रूप से एक त्रुटि होगी।
टोनी डेलारॉय

मैं यह समझना चाहता हूं कि वास्तविक-दुनिया की कौन-सी परिस्थितियाँ मौजूद हैं जहाँ कोई भी टेम्पलेट किसी भी वर्ग के लिए काम करेगा, लेकिन बिल्ट-इन प्रकारों के साथ काम नहीं करेगा। आपके पास कोई उदाहरण है?
लेफलिन

7
  1. कोई फर्क नहीं
  2. टेम्पलेट प्रकार पैरामीटर Containerअपने आप में दो प्रकार के मापदंडों के साथ एक टेम्पलेट है।

3
सामान्य रूप से अंतर है।
हसन सैयद

उन दो मापदंडों के साथ कंटेनर को नामांकित किया गया है जिनका नाम भी हो सकता है? उदाहरण में उनका कोई नाम नहीं है। और यह भी - इस उदाहरण में इसे 'क्लास कंटेनर' लिखा गया है - क्या इसके स्थान पर 'टाइपनाम कंटेनर' भी लिखा जा सकता है?
Mat

2
@ मेत: हाँ, टेम्प्लेट टेम्पलेट पैरामीटर / तर्कों के लिए खोज करने के लिए शब्द है । जैसे:template<template<class U> class V> struct C {};
जॉर्ज फ्रिट्ज़शे

6

स्निपेट का यह टुकड़ा c ++ प्राइमर किताब से है। हालांकि मुझे यकीन है कि यह गलत है।

प्रत्येक प्रकार के पैरामीटर को कीवर्ड वर्ग या टाइपनेम से पहले होना चाहिए:

// error: must precede U with either typename or class
template <typename T, U> T calc(const T&, const U&);

इन कीवर्ड का एक ही अर्थ है और इसे एक टेम्पलेट पैरामीटर सूची के अंदर परस्पर उपयोग किया जा सकता है। एक टेम्प्लेट पैरामीटर सूची दोनों कीवर्ड का उपयोग कर सकती है:

// ok: no distinction between typename and class in a template parameter list
template <typename T, class U> calc (const T&, const U&);

टेम्प्लेट टाइप पैरामीटर को निर्दिष्ट करने के लिए कक्षा के बजाय कीवर्ड टाइपनेम का उपयोग करना अधिक सहज हो सकता है। आखिरकार, हम बिल्ट-इन (नॉनक्लास) प्रकारों का उपयोग टेम्पलेट प्रकार के तर्क के रूप में कर सकते हैं। इसके अलावा, टाइपनाम अधिक स्पष्ट रूप से इंगित करता है कि नाम इस प्रकार है। हालाँकि, पहले से ही व्यापक उपयोग में आने के बाद टाइपनेम को C ++ में जोड़ा गया था; कुछ प्रोग्रामर विशेष रूप से क्लास का उपयोग करना जारी रखते हैं

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.