2008-08-14 17 views
32

निम्नलिखित कोड जीसीसी के साथ संकलन नहीं करता है पर निर्भर करता है के एक सदस्य का उपयोग कर, लेकिन दृश्य स्टूडियो के साथ करता है:जीसीसी मुद्दा: एक आधार वर्ग है कि एक टेम्पलेट तर्क

:

template <typename T> class A { 
public: 
    T foo; 
}; 

template <typename T> class B: public A <T> { 
public: 
    void bar() { cout << foo << endl; } 
}; 

मैं त्रुटि मिलती है

test.cpp: In member function ‘void B::bar()’:

test.cpp:11: error: ‘foo’ was not declared in this scope

लेकिन यह होना चाहिए! अगर मैं

void bar() { cout << this->foo << endl; } 

को bar बदल तो यह संकलन करता है, लेकिन मुझे नहीं लगता कि मैं यह करने के लिए है। क्या सी ++ के आधिकारिक चश्मा में कुछ है कि जीसीसी यहां चल रहा है, या यह सिर्फ एक क्विर्क है?

+0

देखें [एक टेम्पलेटेड व्युत्पन्न कक्षा में, मुझे सदस्य वर्ग के अंदर "यह->" के साथ बेस क्लास सदस्य नामों को अर्हता प्राप्त करने की आवश्यकता क्यों है?] (Http://stackoverflow.com/questions/7908248/in-a- templated-derived-class-why-do-i-need-to-qualify-base-class-सदस्य-names-w) – curiousguy

उत्तर

10

यह gcc-3.4 में बदल गया। सी ++ पार्सर को उस रिलीज में बहुत अधिक सख्त मिला - spec के प्रति लेकिन विरासत या बहु-मंच कोड अड्डों वाले लोगों के लिए अभी भी परेशान है।

18

वाह। सी ++ कभी भी मुझे अजीबता से आश्चर्यचकित नहीं करता है।

In a template definition, unqualified names will no longer find members of a dependent base (as specified by [temp.dep]/3 in the C++ standard). For example,

template <typename T> struct B { 
    int m; 
    int n; 
    int f(); 
    int g(); 
}; 
int n; 
int g(); 
template <typename T> struct C : B<T> { 
    void h() 
    { 
    m = 0; // error 
    f(); // error 
    n = 0; // ::n is modified 
    g(); // ::g is called 
    } 
}; 

You must make the names dependent, e.g. by prefixing them with this->. Here is the corrected definition of C::h,

template <typename T> void C<T>::h() 
{ 
    this->m = 0; 
    this->f(); 
    this->n = 0 
    this->g(); 
} 

As an alternative solution (unfortunately not backwards compatible with GCC 3.3), you may use using declarations instead of this->:

template <typename T> struct C : B<T> { 
    using B<T>::m; 
    using B<T>::f; 
    using B<T>::n; 
    using B<T>::g; 
    void h() 
    { 
    m = 0; 
    f(); 
    n = 0; 
    g(); 
    } 
}; 

कि सिर्फ पागल के सभी प्रकार है। धन्यवाद, डेविड।

यहाँ "temp.dep/3" के मानक खंड है [आईएसओ/आईईसी 14882: 2003]:

In the definition of a class template or a member of a class template, if a base class of the class template depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member. [Example:

typedef double A; 
template<class T> class B { 
    typedef int A; 
}; 
template<class T> struct X : B<T> { 
    A a; // a has typedouble 
}; 

The type name A in the definition of X<T> binds to the typedef name defined in the global namespace scope, not to the typedef name defined in the base class B<T> . ] [Example:

struct A { 
    struct B { /* ... */ }; 
    int a; 
    int Y; 
}; 
int a; 
template<class T> struct Y : T { 
    struct B { /* ... */ }; 
    B b; //The B defined in Y 
    void f(int i) { a = i; } // ::a 
    Y* p; // Y<T> 
}; 
Y<A> ya; 

The members A::B , A::a , and A::Y of the template argument A do not affect the binding of names in Y<A> . ]

33

है कि वे बात कर रहे हैं डेविड जॉयनेर का इतिहास था, यही कारण है।

B<T> संकलित करते समय समस्या यह है कि इसकी बेस क्लास A<T> कंपाइलर से टेम्पलेट क्लास होने के कारण अज्ञात है, इसलिए बेस क्लास से किसी भी सदस्य को कंपाइलर को जानने का कोई तरीका नहीं है।

पहले के संस्करणों ने वास्तव में आधार टेम्पलेट वर्ग को पार्स करके कुछ अनुमान लगाया था, लेकिन आईएसओ सी ++ ने कहा कि यह अनुमान उन संघर्षों का कारण बन सकता है जहां नहीं होना चाहिए। gcc manual में

template <typename T> class A { 
public: 
    T foo; 
}; 

template <typename T> class B: public A <T> { 
public: 
    void bar() { cout << A<T>::foo << endl; } 
}; 

अधिक जानकारी:

एक टेम्पलेट में एक आधार वर्ग सदस्य संदर्भ के लिए समाधान (जैसे तुमने किया था) this उपयोग करने के लिए या विशेष रूप से आधार वर्ग का नाम है।

+8

एक तरफ, इस तरह की समझ में आता है। लेकिन दूसरी ओर, यह वास्तव में लंगड़ा लगता है। संकलक को * यह जानने की आवश्यकता नहीं है कि 'foo' क्या है जब तक कि टेम्पलेट तत्काल नहीं हो जाता है, उस बिंदु पर, यह 'ए' में' foo' सदस्य को पहचानने में सक्षम होना चाहिए। सी ++ में इन अजीब कोने के मामलों में से बहुत सारे तरीके हैं। –

+0

हाँ, यह पूरी तरह से अस्वीकार्य है ... तत्काल से पहले नहीं पता? तो टेम्पलेट्स में सामान्य रूप से तत्काल के लिए प्रतीक्षा करें .. यह उसकी भावना है, नहीं? क्या गड़बड़ है ... –

8

मुख्य कारण सी ++ कुछ भी नहीं मान सकता है कि बेस टेम्पलेट को बाद में एक प्रकार के लिए विशेषीकृत किया जा सकता है। मूल उदाहरण जारी रखना:

template<> 
class A<int> {}; 

B<int> x; 
x.bar();//this will fail because there is no member foo in A<int> 
3

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

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