2010-07-12 11 views
7

जी ++ 4.2.1 का उपयोग कर इस कोड संकलन:त्रुटिपूर्ण निजी बेस क्लास पहुंच योग्य नहीं है?

struct S { }; 
template<typename T> struct ST { }; 

template<typename BaseType> 
class ref_count : private BaseType { }; 

template<typename RefCountType> 
class rep_base : public RefCountType { }; 

class wrap_rep : public rep_base<ref_count<S> > { 
    typedef rep_base<ref_count<S> > base_type;  // line 11 
}; 

मैं:

bug.cpp:1: error: ‘struct S’ is inaccessible 
bug.cpp:11: error: within this context 

हालांकि, अगर मैं ST उपयोग करने के लिए wrap_rep वर्ग बदलने के लिए:

class wrap_rep : public rep_base<ref_count< ST<int> > > { 
    typedef rep_base<ref_count< ST<int> > > base_type; 
}; 

यह ठीक संकलित । वैकल्पिक रूप से, यदि मैं मूल कोड को बदलता हूं:

class wrap_rep : public rep_base<ref_count<S> > { 
    typedef rep_base<ref_count<::S> > base_type; // now using :: 
}; 

यह भी ठीक संकलित करता है। मेरे लिए, मूल कोड ठीक जैसा लगता है। क्या यह एक जी ++ बग है? यदि नहीं, तो टेम्पलेट का उपयोग क्यों करते हैं? और, दूसरे मामले के लिए, ::S क्यों आवश्यक है?

उत्तर

7

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

class S { }; 

class S::S object; // creates an S object 
class X : S::S::S::S { }; // derives from class S 

कक्षा टेम्पलेट्स भी एक इंजेक्शन वर्ग के नाम की है। इंजेक्शन वाले क्लास नाम की तरह, इसे व्युत्पन्न कक्षाओं में विरासत में मिला है, और इस प्रकार ST<int> खराब गठित है क्योंकि यह उस इंजेक्शन क्लास नाम का उपयोग करता है, जो कि तब तक पहुंच योग्य नहीं है। आप जीसीसी कम 4.5 उपयोग करते हैं, यह GCC4.5 के साथ एक change introduced के साथ कुछ हो सकता है:

जी ++ अब डॉ 176. लागू करता है इससे पहले जी ++ एक टेम्पलेट आधार वर्ग के इंजेक्शन-वर्ग-नाम का उपयोग का समर्थन नहीं किया एक प्रकार के नाम के रूप में, और नाम के लुकअप को संलग्न क्षेत्र में टेम्पलेट की घोषणा मिली। अब नाम की तलाश इंजेक्शन-क्लास-नाम पाती है, जिसे किसी प्रकार या टेम्पलेट के रूप में इस्तेमाल किया जा सकता है, इस पर निर्भर करता है कि नाम टेम्पलेट तर्क सूची के बाद है या नहीं। इस परिवर्तन, कुछ कोड क्योंकि

  1. इंजेक्शन-वर्ग-नाम सुलभ क्योंकि यह एक निजी आधार से है नहीं है कि पहले स्वीकार कर लिया गया हो सकता है बीमार का गठन किया जा, या
  2. इंजेक्शन-वर्ग के परिणामस्वरूप नाम टेम्पलेट टेम्पलेट पैरामीटर के लिए तर्क के रूप में उपयोग नहीं किया जा सकता है।

इन दोनों स्थितियों में, कोड एक नेस्टेड-नाम-विनिर्देशक स्पष्ट रूप से टेम्पलेट नाम के लिए जोड़कर तय किया जा सकता है। पहले -फनो-एक्सेस-कंट्रोल के साथ पहले काम किया जा सकता है; दूसरा केवल उन्माद के साथ खारिज कर दिया गया है।


इंजेक्शन वर्ग नाम के साथ थोड़ा और मजा करने के लिए - ध्यान दें कि इंजेक्शन वर्ग के नाम एक typedef के बराबर के रूप में एक पहले सोच सकते हैं नहीं है। इंजेक्शन वर्ग के नाम एक वर्ग-नाम है, लेकिन एक typedef-नाम है, जो यह समारोह, वस्तु या प्रगणक नामों से छिपा हो सकता है इसका मतलब है के रूप में वर्गीकृत नहीं किया गया है:

// valid, the data-member hides the injected class name 
struct S { int S; }; 

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

0

मूल कोड "सन वर्कशॉप 6 अपडेट 2 कंपाइलर्स सी ++" में ठीक संकलित किया गया। यह केवल एकमात्र है जिसके पास मेरे कार्यालय में पहुंच है। आपके पास किसी अन्य कंपाइलर पर आज़माएं।

3

आपकी संरचना Swrap_rep का आधार वर्ग है जिसका अर्थ है कि इसे wrap_rep में इंजेक्शन दिया गया है जैसे कि अनामित टाइपिफ़ाफ़ था।

अपने typedef में S से पहले ऑपरेटर :: का उपयोग करते हुए अपने संकलक का उपयोग नहीं बता देंगे S आप से विरासत है, लेकिन ग्लोबल नेम स्पेस में S

this link देखें।

+0

लेकिन फिर कोड टेम्पलेट बेस क्लास के साथ क्यों काम करता है? –