भ्रामक टेम्पलेट त्रुटि


91

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

पूरी बात आसानी से एक न्यूनतम उदाहरण के लिए नीचे ले जाया जा सकता है:

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कोड को सही ढंग से सही करने के लिए कीवर्ड डालने के लिए वास्तव में एक को कहां सम्मिलित किया जाना चाहिए?


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

3
करने के लिए इसी तरह के इस और इस
प्रसून सौरव

जवाबों:


104

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

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

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

इसलिए इसमें बदलाव t->f0<U>()करें t->template f0<U>()


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

24
क्या आप शायद इस पर टिप्पणी कर सकते हैं कि ऐसा क्यों है? C ++ को इस प्रकार के सिंटैक्स की आवश्यकता क्यों होगी?
जिज्ञासु

2
हाँ यह अजीब है। भाषा "पता लगा" सकती है कि टेम्पलेट कीवर्ड को उपस्थित होने की आवश्यकता है। यदि वह ऐसा कर सकता है तो उसे वहां पर ही कीवर्ड डालना होगा।
एनरिको बोरबा

26

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

#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;
}

यह पहले प्रिंट 0करते समय, लेकिन इसे सम्मिलित करते समय प्रिंट करता है। मैं इसे एक अभ्यास के रूप में छोड़ता हूं ताकि यह पता लगाया जा सके कि कोड क्या करता है।templatef<int()>1


3
अब वह एक शैतानी उदाहरण है!
मथिउ एम।

1
मैं दृश्य स्टूडियो 2013 में आपके द्वारा बताए गए व्यवहार को पुन: पेश नहीं कर सकता। यह हमेशा कॉल करता है f<U>और हमेशा प्रिंट करता है 1, जो मेरे लिए एकदम सही समझ में आता है। मुझे अभी भी समझ नहीं आया कि templateकीवर्ड की आवश्यकता क्यों है और इससे क्या फर्क पड़ता है।
वायलेट जिराफ

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

1
यह उत्तर बताता है कि क्यों templateआवश्यक है: stackoverflow.com/questions/610245/… बिना मानक शब्दों पर पूरी तरह भरोसा किए, जिन्हें समझना मुश्किल है। कृपया रिपोर्ट करें कि क्या उत्तर में कुछ भी अभी भी भ्रमित है।
जोहान्स शाउब -

@ जोहान्सचैब-लिट: धन्यवाद, एक शानदार जवाब। पता चला, मैंने इसे पहले पढ़ा है क्योंकि यह मेरे द्वारा पहले से ही अपडाउन किया गया था। जाहिरा तौर पर, मेरी स्मृति meh है।
वायलेट जिराफ

12

उस बिंदु से ठीक पहले डालें जहाँ कैरेट है:

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

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


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

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

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

11

C ++ टेम्प्लेट से अंश

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

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

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

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

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