2009-03-03 6 views
26

पर विचार करें निम्न कोड से विरासत में मिली चर तक पहुंचना:टेम्प्लेटेड माता पिता वर्ग

template<class T> class Foo 
{ 
public: 
    Foo() { a = 1; } 

protected: 
    int a; 
}; 

template<class T> class Bar : public Foo<T> 
{ 
public: 
    Bar() { b = 4; }; 

    int Perna(int u); 

protected: 
    int b; 

}; 

template<class T> int Bar<T>::Perna(int u) 
{ 
    int c = Foo<T>::a * 4; // This works 
    return (a + b) * u; // This doesn't 
} 

जी ++ 3.4.6, 4.3.2 और 4.1.2 त्रुटि दिखा सकते हैं

test.cpp: In member function `int Bar<T>::Perna(int)': 
test.cpp:25: error: `a' was not declared in this scope 

जी ++ 2.96 और MSVC 6, 7 , 7.1, 8 और 9 इसे स्वीकार करते हैं, कम से कम पुराने इंटेल और एसजीआई सी ++ कंपाइलर्स करते हैं।

नई GNU सी ++ संकलक मानक का पालन करना या नहीं है? यदि वे करते हैं, तो उत्तराधिकारी वर्ग के पीछे तर्क क्या है जो संरक्षित विरासत सदस्य चर को देखने में सक्षम नहीं है?

इसके अलावा, अगर वहाँ

int A() { return a; } 
फू में

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

test.cpp:25: error: there are no arguments to A that depend on a template parameter, so a declaration of A must be available 
test.cpp:25: error: (if you use -fpermissiveâ, G++ will accept your code, but allowing the use of an undeclared name is deprecated) 

जब मैं बार के एक सदस्य समारोह में इसका इस्तेमाल करने की कोशिश करते हैं। मुझे यह उत्सुकता भी मिलती है: बार को फू विरासत में मिला है, इसलिए मुझे लगता है कि यह स्पष्ट है कि बार (ए) में बार (ए)) है।

उत्तर

37

बाद के जीसीसी संस्करण मानक को सही ढंग से कार्यान्वित करते हैं।

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

यह बेस क्लास में घोषित दोनों चर और फ़ंक्शन नामों के लिए सच है।

जैसा कि आपने देखा है कि समाधान चर या कार्य का योग्य नाम प्रदान करना है, या "उपयोग" घोषणा प्रदान करना है। जैसे

template<class T> 
int Bar<T>::Perna(int u) 
{ 
    int c = Foo<T>::a * 4; // This works 
    c = this->a * 4; // and this 

    using Foo<T>::a; 
    c = a * 4; // and with 'using', so should this 
} 

(मैं वास्तव में नहीं 100% का उपयोग संस्करण के लिए सही सिंटैक्स के बारे में यकीन है और यहाँ से परीक्षण नहीं कर सकते, लेकिन आप अंदाजा हो)।

+0

धन्यवाद। मैं अपनी आस्तीन रोल करने और कोड बदलने जा रहा हूं। –

+1

मेरा मानना ​​है कि आपको कक्षा स्तर पर उपयोग कथन करना है, यानी टेम्पलेट बार: सार्वजनिक Foo {Foo :: ए का उपयोग करना; ...}; –

4

त्रुटि संदेश जो जीसीसी देता है यह दिखाता है कि जीसीसी के आपके संस्करण में अभी भी एक बग है जिसे केवल जीसीसी 4.7 ट्रंक संस्करणों में हल किया गया है। GCC4.1 सहित पुराने संस्करण, खुशी कोड

template<typename T> 
struct A { 
    void f(int) { } 
}; 

template<typename T> 
struct B : A<T> { 
    void g() { T t = 0; f(t); } 
}; 

int main() { 
    B<int> b; b.g(); 
} 

जीसीसी निम्नलिखित आधार वर्ग A<T> भीतर f(t) में f ऊपर दिखेगा स्वीकार करेंगे और आधार वर्ग में घोषणा मिल जाएगा। जीसीसी ऐसा करता है क्योंकि f निर्भर है, क्योंकि f पर तर्क हैं कि "टेम्पलेट पैरामीटर पर निर्भर करें" (इसके त्रुटि संदेश को आपने इसे दिया है!)। लेकिन स्टैंडर्ड जीसीसी मनाही करने के लिए है कि दो कारणों से

  1. स्टैंडर्ड का कहना है कि अयोग्य नामों के उपयोग कभी नहीं एक घोषणा एक आश्रित आधार वर्ग में कोई फर्क नहीं पड़ता कि क्या नाम निर्भर है मिलेगा के लिए।

  2. मानक कहता है कि तत्काल समय पर फ़ंक्शन नाम के आश्रित लुकअप केवल एडीएल ही करेंगे।

जीसीसी 4.7 उस संबंध में मानक को सही ढंग से लागू करता है।