2010-09-24 21 views
68

मैं थोड़ी देर के साथ खेल रहा हूं, और मैंने "टेस्ट/सेमा टेम्पलेट/आश्रित-टेम्पलेट-पुनर्प्राप्ति सीपीपी" (क्लैंग वितरण में) पर ठोकर खाई है, जिसे टेम्पलेट से पुनर्प्राप्त करने के लिए संकेत प्रदान करना है त्रुटि।उलझन में टेम्पलेट त्रुटि

template<typename T, typename U, int N> struct X { 
    void f(T* t) 
    { 
     // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}} 
     t->f0<U>(); 
    } 
}; 

त्रुटि संदेश बजना द्वारा उत्पन्न होने वाले:

tpl.cpp:6:13: error: use 'template' keyword to treat 'f0' as a dependent template name 
     t->f0<U>(); 
      ^
      template 
1 error generated. 

... लेकिन मैं जहां वास्तव में एक कठिन समय समझ है

पूरी बात को आसानी से एक कम से कम उदाहरण के लिए नीचे छीन लिया जा सकता है कोड को वाक्य रचनात्मक रूप से सही करने के लिए template कीवर्ड डालना चाहिए?

template<typename T, typename U, int N> struct X { 
    void f(T* t) 
    { 
     t->template f0<U>(); 
    } 
}; 

संपादित करें:: यदि आप एक संकलक की तरह लगता है इस नियम के लिए कारण स्पष्ट हो जाता है

+9

क्या आपने इसे डालने का प्रयास किया जहां तीर इंगित कर रहा है? –

+3

[इस] के समान (http://stackoverflow.com/questions/3691420/compiler-error-when-using-integer-as-template-parameter/) और [यह] (http://stackoverflow.com/questions/362171 9/सी-टेम्पलेट-सिंटैक्स) –

उत्तर

65

आईएसओ सी ++ 03 14.2/4:

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

t->f0<U>();f0<U> में एक सदस्य टेम्पलेट विशेषज्ञता जो -> के बाद दिखाई देता है और जो स्पष्ट रूप से टेम्पलेट पैरामीटर U पर निर्भर करता है, इसलिए सदस्य टेम्पलेट विशेषज्ञता template कीवर्ड से उपसर्ग होना चाहिए।

तो t->f0<U>() से t->template f0<U>() बदलें।

+0

दिलचस्प बात यह है कि मैंने अभिव्यक्ति को कोष्ठक में डालने का विचार किया: 't -> (f0 ()) 'मैंने तय किया होगा, जैसा कि मैंने सोचा था कि' f0 ()' स्टैंडअलोन में रखेगा अभिव्यक्ति ... अच्छा, मैंने गलत सोचा, ऐसा लगता है ... –

+5

क्या आप शायद इस पर टिप्पणी क्यों कर सकते हैं? C++ को इस तरह के वाक्यविन्यास की आवश्यकता क्यों होगी? – Curious

7

सिर्फ बिंदु जहां कैरट है इससे पहले कि यह डालें। कंपाइलर्स आम तौर पर केवल एक या दो टोकन एक बार में देखते हैं, और आमतौर पर शेष अभिव्यक्ति के लिए "आगे देखो" नहीं देखते हैं। [संपादित करें: टिप्पणी देखें] कीवर्ड का कारण समान है कि आपको typename कीवर्ड को निर्भर प्रकार के नामों को इंगित करने के लिए क्यों चाहिए: यह संकलक को बता रहा है "अरे, पहचानकर्ता जिसे आप देखना चाहते हैं वह टेम्पलेट का नाम है, एक स्थिर डेटा सदस्य के नाम के बजाय कम से कम संकेत के बाद "।

+0

मैं ** कभी ** अनुमान लगाने में सक्षम नहीं था ... लेकिन धन्यवाद ;-)। C++ के बारे में जानने के लिए हमेशा कुछ स्पष्ट रूप से होता है! –

+3

असीमित रूप से आगे भी, आपको अभी भी 'टेम्पलेट' की आवश्यकता होगी। ऐसे मामले हैं जहां 'टेम्पलेट' के साथ और बिना दोनों अलग-अलग व्यवहार के साथ वैध कार्यक्रम प्रस्तुत करेंगे। तो यह न केवल एक वाक्य रचनात्मक समस्या है ('t-> f0 (0) 'कम से कम और टेम्पलेट तर्क सूची संस्करण दोनों के लिए सिंटैक्टिक रूप से मान्य है)। –

+0

@ जोहान्स शैब - litb: ठीक है, इसलिए आगे की ओर देखने की तुलना में अभिव्यक्ति के लिए लगातार अर्थपूर्ण अर्थ असाइन करने की समस्या अधिक है। – Doug

6

अंश C++ Templates

से .template एक बहुत ही इसी तरह की समस्या का निर्माण typename के आने के बाद पता चला था। मानक बिटसेट प्रकार का उपयोग करके निम्नलिखित उदाहरण पर विचार करें:

template<int N> 
void printBitset (std::bitset<N> const& bs) 
{ 
    std::cout << bs.template to_string<char,char_traits<char>, 
             allocator<char> >(); 
} 

इस उदाहरण में अजीब निर्माण है। टेम्पलेट। टेम्पलेट के उस अतिरिक्त उपयोग के बिना, कंपाइलर यह नहीं जानता कि निम्न से कम टोकन (<) निम्नानुसार है "वास्तव में" नहीं बल्कि टेम्पलेट तर्क सूची की शुरुआत है। ध्यान दें कि यह केवल एक समस्या है यदि अवधि से पहले निर्माण टेम्पलेट पैरामीटर पर निर्भर करता है। हमारे उदाहरण में, पैरामीटर बीएस टेम्पलेट पैरामीटर पर निर्भर करता है एन

निष्कर्ष में, टेम्पलेट नोटेशन (और इसी तरह के नोटेशन जैसे -> टेम्पलेट) का उपयोग केवल टेम्पलेट्स के अंदर किया जाना चाहिए और केवल तभी जब वे कुछ ऐसा मानते हैं जो निर्भर करता है टेम्पलेट पैरामीटर पर।

+0

वास्तव में, उत्कृष्ट उदाहरण के लिए +1 –

19

अंक दूसरों बना के अलावा, सूचना है कि कभी कभी संकलक अपना मन बनाने नहीं कर सका और दोनों व्याख्याओं विकल्प वैध कार्यक्रमों उपज कर सकते हैं जब

#include <iostream> 

template<typename T> 
struct A { 
    typedef int R(); 

    template<typename U> 
    static U *f(int) { 
    return 0; 
    } 

    static int f() { 
    return 0; 
    } 
}; 

template<typename T> 
bool g() { 
    A<T> a; 
    return !(typename A<T>::R*)a.f<int()>(0); 
} 


int main() { 
    std::cout << g<void>() << std::endl; 
} 

instantiating यह प्रिंट 0 जब f<int()> से पहले template को छोड़ते हुए लेकिन 1 इसे डालने पर। मैं यह समझने के लिए एक अभ्यास के रूप में छोड़ देता हूं कि कोड क्या करता है।

+1

अब यह एक शैतानी उदाहरण है! –

+1

मैं विजुअल स्टूडियो 2013 में आपके द्वारा वर्णित व्यवहार को पुन: उत्पन्न नहीं कर सकता। यह हमेशा 'f 'कहता है और हमेशा' 1' प्रिंट करता है, जो मुझे सही समझ में आता है। मुझे अभी भी समझ में नहीं आता कि क्यों 'टेम्पलेट' कीवर्ड की आवश्यकता है और इससे क्या फर्क पड़ता है। –

+0

@ VSClet VSC++ कंपाइलर एक अनुपालन सी ++ कंपाइलर नहीं है। यदि आप जानना चाहते हैं कि वीएससी ++ हमेशा प्रिंट क्यों करता है तो एक नया प्रश्न जरूरी है। –

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