2011-07-03 8 views
5

कभी कभी मैं घोषणा के नीचे तरह देखें:टेम्पलेट में टाइपनाम के लिए नाम घोषित करने के उपयोग के मामले क्या हैं?

template<typename> // <-- not "typename T" 
struct A { ... }; 

क्या इस तरह घोषणा के लिए उपयोग-मामले हैं। क्या वे उपयोगी हैं या शैली की बात है?

उत्तर

0
  1. यह A के स्थिर सदस्यों के प्रकार से संकलित-समय मानचित्रण बना सकता है।

    template<typename> 
    struct sort_statistics { static size_t times_comparator_called = 0; }; 
    
    template<typename T> 
    size_t sort_statistics<T>::times_comparator_called; 
    
    template<typename Titer> 
    void my_sort(Titer first, Titer last) 
    { 
        //... 
        ++sort_statistics<iterator_traits<Titer>::value_type>::times_comparator_called; 
        if (*itA < *itB) { 
        //... 
    } 
    
  2. यह अभी भी विशिष्ट हो सकता है।

+1

क्या आप विस्तार से विस्तार से विस्तार कर सकते हैं? – iammilind

+0

@iammiling: वह कैसा है? –

3

क्या आप वास्तव में टेम्पलेट परिभाषा के लिए उपयोग करते हैं, और नहीं, कहें, एक टेम्पलेट घोषणा (केवल)?

कुछ का उपयोग करता है:

// declaration only: the parameter name has no use beyond documentation 
template<typename> 
struct A; 

// this is fine 
template<typename T> 
void eat_an_a(A<T> a); 

// later, we can name the parameter to use it 
template<typename T> 
struct A { ... }; 

// C++0x only 
template< 
    typename T 
    // We don't care for the actual type (which will default to void) 
    // the goal is sfinae 
    , typename = typename std::enable_if< 
     std::is_array<typename std::decay<T>::type>::value 
    >::value 
> 
void 
f(T&& t); 

// We still don't care to name that defaulted parameter 
template<typename T, typename> 
void f(T&& t) 
{ ... } 

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

// no definition 
template<typename TypeToExamine, typename ImplementationDetail = void> 
struct trait; 

मैं उनके नाम में प्रकार पैरामीटर की भूमिका वर्तनी रहा हूँ। अब यह घोषणा क्या करती है, क्योंकि दूसरा पैरामीटर डिफॉल्ट किया गया है, सिंटैक्टिक चीनी का थोड़ा सा है। जहां भी trait<U> प्रकट होता है, यह बिल्कुल जैसा कि हमने लिखा है trait<U, void> लिखा गया था। हमें अब हमारे विशेषता के आधार मामले के लिए एक परिभाषा प्रदान करते हैं:

// assume previous declaration is still in scope so we do not default 
// the second parameter again 
template<typename T, typename> struct trait: std::false_type {}; 

यह एक बहुत ही उपयोगी विशेषता नहीं है। अब जब हम trait<U> लिखते हैं, जो trait<U, void> के लिए छोटा है, तो हम इस परिभाषा के साथ समाप्त होते हैं। इसका मतलब है कि trait<U>::value मान्य है और वास्तव में false है। की गुप्त संघटक जोड़कर हमारी कक्षा अधिक उपयोगी बनाने करते हैं:

template<typename> struct void_ { typedef void type; }; 
// again, assume previous declarations are in scope 
template<typename T, typename void_<decltype(T() + T())>::type> 
struct trait: std::true_type {}; 

फिर, जब हम trait<U> लिखते हैं, यह के रूप में अगर हम trait<U, void> लिखा था है। आंशिक विशेषज्ञता उसमें बदलाव नहीं करती है (इसकी अनुमति नहीं है)। लेकिन जब हम trait<U>::value पर सवाल करते हैं तो हमें किस परिभाषा का उपयोग करना चाहिए? खैर, सबसे पहले, हमें यह जानना होगा कि विशेषज्ञता वास्तव में क्या है ... या, रहस्यमय दूसरा तर्क typename void_<decltype(T() + T())>::type क्या है?

सबसे आसान मामला तब होता है जब U() + U() खराब गठित होता है। फिर SFINAE में लाता है और ऐसा लगता है जैसे विशेषज्ञता मौजूद नहीं थी; इस प्रकार हम गैर-विशिष्ट परिभाषा प्राप्त करते हैं, और valuefalse है। यदि U() + U() अच्छी तरह से गठित है, तो decltype एक प्रकार उत्पन्न करता है, और पूरे void में बदल जाता है, क्योंकि सभी प्रकार void_<T>::typevoid है। तो इसका मतलब है कि हमारे पास फॉर्म trait<T, void> का विशेषज्ञता है। यह trait<U> से मेल खा सकता है, से U के साथ मेल खाता है। और अब valuetrue है।

यदि फिर भी विशेषज्ञता हैं

template<typename T> 
struct trait<T, decltype(T() + T())>: std::true_type {}; 

लिखा गया है तो एक ही तरीका है यह इस्तेमाल किया जाएगा जब trait<U, decltype(U() + U())> लेखन,decltype(U() + U())जब तक शून्य होने के लिए happended। याद रखें, trait<U>trait<U, void> के लिए चीनी है। तो trait<int> हमारी विशेषज्ञता से कभी मेल नहीं खाएगा क्योंकि बाद वाला फॉर्म trait<int, int> है।

इस प्रकार void_ हमेशा trait<T, void> फॉर्म की विशेषज्ञता रखने की भूमिका निभाता है यदि वे SFINAE'd नहीं हैं। चूंकि हम टाइप पैरामीटर का उपयोग करने की परवाह नहीं करते हैं, इसलिए इसका नाम नहीं है।

+0

नहीं, मुझे केवल आगे की घोषणा में नहीं देखा है। इसका उपयोग 'वर्ग' शरीर को परिभाषित करने के लिए भी किया जाता है। यहां देखें: http://stackoverflow.com/questions/6540948/c-templates-how-to-determine-if-a-type-is-suitable-for-subclassing?answertab=votes#tab-top – iammilind

+0

@iammilind चाहिए उस लिंक को प्रश्न में डाल दिया है! तब हम आपको सीधे बता सकते हैं ** कभी ** ** टेम्पलेट स्ट्रक्चर ए ... देखा। आपने 'टेम्पलेट संरचना ए ...' देखा। यह * बहुत * अलग है, आंशिक रूप से आपके लिंक के अंदर टिप्पणियों में वर्णित है, और आप मेरे उत्तर में एक अनाम डिफ़ॉल्ट पैरामीटर का एक और उपयोग देख सकते हैं। –

+0

यह 'typename = void' से संबंधित नहीं है। उत्तर में देखें: 'टेम्पलेट संरचना void_ {typedef शून्य प्रकार; }; ' – iammilind

संबंधित मुद्दे