2010-08-23 34 views
7

नीचे एक पूरी तरह अकादमिक आविष्कार वर्ग पदानुक्रम है।अपेक्षित व्यवहार क्या है?

struct X{ 
     void f1(); 
     void f2(); 
     void f3(); 
}; 

struct Y : private X{ 
     void f4(); 
}; 

struct Z : X{ 
}; 

struct D : Y, Z{ 
     using X::f2; 
     using Z::X::f3; 
}; 

int main(){} 

मैं एक्स :: f2 के लिए घोषणा का उपयोग कर के रूप में 'एक्स' अस्पष्ट होने की उम्मीद 'डी' (visbility एक्स की पहुंच बनाम) के एक अस्पष्ट आधार है। हालांकि g ++ (ideone.com) इसे ठीक करता है।

मैंने ऑनलाइन कमौ के साथ चेक किया और यह अपेक्षित रूप से एक्स :: एफ 2 के लिए घोषणा का उपयोग करने में त्रुटि देता है। हालांकि यह ज़ेड :: एक्स :: एफ 3 के लिए घोषणा का उपयोग करने के लिए अस्पष्टता देता है।

तो अपेक्षित व्यवहार क्या है?

संपादित करें 1:

स्टैंडर्ड के उपयुक्त अनुभाग का संदर्भ उपयोगी, कृपया होगा।

संपादित करें 2:

मैं VS 2010 के साथ की जाँच की और यह केवल घोषणा का उपयोग कर एक्स :: f2 साथ आपत्ति है। हालांकि यह 'एक्स' की अस्पष्टता के बारे में नहीं है (जैसा कि जीसीसी और कमौ के मामले में)। यह "त्रुटि C2876: 'एक्स' के बारे में है: सभी ओवरलोड उपलब्ध नहीं हैं"।

संपादित करें 3:

struct X{ 
    void f(){} 
}; 

struct Y : X{ 
    struct trouble{ 
     void f(){} 
    }; 

}; 

struct trouble : X{ 
}; 

struct letscheck : Y, trouble{ 
    using trouble::f; 
}; 

int main(){} 

यहाँ मैं प्रयास कर चुके हैं (उद्देश्यपूर्ण) घोषणा का उपयोग करने में प्रकार के साथ एक मुद्दा बनाने के लिए। जीसीसी अभी भी इस जुर्माना को संकलित करता है और वीएस -2010 भी करता है। Comau अभी भी अस्पष्ट प्रकार की परेशानी के बारे में त्रुटि (जैसा कि अपेक्षित) देता है। शुरुआती प्रश्नों के लिए दिए गए स्पष्टीकरणों के अनुसार, ऐसा लगता है कि जीसीसी और वीएस -2010 गलत हैं। क्या वो सही है?

+0

डी में एक विधि जोड़ें जो f2() को कॉल करती है, देखें कि क्या होता है। –

उत्तर

2

मुझे नहीं लगता कि इनमें से कोई भी खराब बना हुआ है। सबसे पहले, using X::f2, X के लिए देखा गया है, और यह कक्षा प्रकार X को अनजाने में उपज देगा। फिर f2X में देखा गया है, और यह भी अस्पष्ट है (यह D में नहीं देखा गया है!)।

दूसरा मामला इसी कारण से काम करेगा।

लेकिन अगर आप कॉलf2 एक D वस्तु पर, कॉल अस्पष्ट क्योंकि नाम f2 प्रकार X की D के सभी subobjects में देखा जाता है हो जाएगा, और D इस तरह के दो subobjects है, और f2 एक गैर है -स्टैटिक सदस्य समारोह। दूसरे कारण के लिए एक ही कारण है। इससे Z::X या X का उपयोग करके f3 का नाम इस पर कोई फर्क नहीं पड़ता है। इनमें से दोनों कक्षा X निर्दिष्ट करते हैं।

उपयोग घोषणा के लिए अस्पष्टता प्राप्त करने के लिए, आपको इसे अलग-अलग लिखना होगा। ध्यान दें कि सी ++ 0x using ThisClass::...; में मान्य नहीं है। यह सी ++ 03 में है, हालांकि, जब तक पूरा नाम बेस-क्लास सदस्य को संदर्भित करता है।

इसके विपरीत, यह C++ 0x में अनुमति दी जाएगी अगर, घोषणा का उपयोग कर पूरी भी वैध, होगा क्योंकि C++ 0x नहीं नाम-देखने के लिए खाते में subobjects ले करता है: D::f2 स्पष्ट रूप से केवल एक ही घोषणा को संदर्भित करता है (X में से एक)। DR #39 और अंतिम पेपर N1626 देखें।

struct D : Y, Z{ 
    // ambiguous: f2 is declared in X, and X is a an ambiguous base class 
    using D::f2; 

    // still fine (if not referred to by calls/etc) :) 
    using Z::X::f3; 
}; 

struct E : D { 
    // ambiguous in C++03 
    // fine in C++0x (if not referred to by an object-context (such as a call)). 
    using D::f2; 
}; 

सी ++ 03 स्टैंडर्ड पैराग्राफ 10.2 और 3.4.3.1 में यह वर्णन करता है। Edit3 के लिए


प्रतिक्रिया:

हाँ, जीसीसी और VS2010 गलत हैं। trouble::trouble के इंजेक्शन क्लास नाम और Y::trouble के रूप में पाए गए नेस्टेड क्लास द्वारा प्राप्त प्रकार को संदर्भित करता है। नाम trouble:: पूर्ववर्ती (पहले बुलेट में 10.2 को 3.4.1/7 द्वारा, जो प्रतिनिधियों) अयोग्य देखने का उपयोग कर देखा जाता है किसी भी वस्तु, समारोह और प्रगणक नाम अनदेखी (3.4.3/1 - इस मामले में ऐसी कोई नाम हालांकि, वहाँ हैं)।

In a using-declaration used as a member-declaration, the nested-name-specifier shall name a base class of the class being defined.

यह:

If the resulting set of declarations are not all from sub-objects of the same type ... the program is ill-formed.


ऐसा नहीं है कि VS2010 और जीसीसी अलग तरह से व्याख्या C++ 0x शब्दों Comeau से है तथा वह पिछले कि शब्दों को लागू संभव है: यह तो 10.2 की आवश्यकता है कि के खिलाफ का उल्लंघन करती है इसका मतलब है कि गैर-बेस क्लास माना जाता है, लेकिन गैर-बेस क्लास नामित होने पर यह एक त्रुटि है। स्टैंडर्ड गैर आधार वर्ग के नाम की अनदेखी करने का इरादा चाहते हैं, तो इसे यहाँ कहेंगे केवल कर सकते हैं, या स्पष्ट रूप से यह उल्लेख (दोनों प्रथाओं किया जाता है)। मानक हालांकि के उपयोग के परिणामस्वरूप और कर सकते हैं। और जीसीसी सी ++ 0x शब्द लागू करता है, क्योंकि यह अन्यथा पूरी तरह से ठीक सी ++ 03 कोड को अस्वीकार करता है, सिर्फ इसलिए कि उपयोग की घोषणा में इसका वर्ग-नाम होता है।

अस्पष्ट शब्दों का एक उदाहरण के लिए, निम्न अभिव्यक्ति पर विचार करें:

a.~A(); 

क्योंकि यह एक सदस्य समारोह कॉल किया जा सकता है अगर a एक वर्ग वस्तु है यह, वाक्य रचना अस्पष्ट है, लेकिन यह एक छद्म हो सकता है -डिस्टक्टर-कॉल (जो नो-ऑप है) यदि a में स्केलर प्रकार है (जैसे int)। लेकिन क्या स्टैंडर्ड कहते 5.2.4 पर एक छद्म नाशक कॉल और वर्ग के सदस्य के लिए उपयोग की वाक्य रचना के लिए है और 5.2.5 क्रमशः

The left-hand side of the dot operator shall be of scalar type.

For the first option (dot) the type of the first expression (the object expression) shall be “class object” (of a complete type).

गलत इस्तेमाल होता है यही कारण है, क्योंकि यह सब पर अस्पष्टता स्पष्ट नहीं है। इसे "केवल कर सकते हैं" का उपयोग करना चाहिए, और संकलक इस तरह से इसकी व्याख्या करते हैं। इसमें ज्यादातर ऐतिहासिक कारण हैं, क्योंकि कुछ समिति-सदस्य ने हाल ही में मुझे यूजनेट पर बताया था। The rules for the structure and drafting of International Standards देखें, अनुलग्नक एच।

+0

@ लिटब: मैंने श्रेणी 'डी' को निम्नानुसार संशोधित किया है: संरचना डी: वाई, जेड {एक्स :: एफ 2 का उपयोग; जेड :: एक्स :: एफ 3 का उपयोग करना; शून्य एफ() {एक्स * पी = यह;}}; अब मुझे त्रुटि मिली है prog.cpp: 19: त्रुटि: X :: f3 'prog.cpp का उपयोग करके घोषणा का उपयोग करके दोहराया गया: सदस्य फ़ंक्शन' शून्य डी :: एफ() 'में: prog.cpp: 20: त्रुटि:' एक्स 'डी' का एक संदिग्ध आधार है 'नाम लुकअप' – Chubsdad

+0

@chubsdad के दौरान 'घोषणा का उपयोग करके' नियम अलग-अलग हैं, मैं मानक को दोहराने के लिए कर सकता हूं। मुझे नहीं पता कि उन कंपाइलर्स क्या कार्यान्वित करते हैं। मुझे आपके कोड में "घोषणा का उपयोग करके दोहराया नहीं गया" दिखाई नहीं देता है। –

+0

@ लिटब: मेरे कोड में मामूली टाइपो और इसलिए संकलक आउटपुट।संशोधित त्रुटि निम्नानुसार है: prog.cpp: सदस्य फ़ंक्शन 'शून्य डी :: एफ()': prog.cpp: 20: त्रुटि: 'एक्स' 'डी' – Chubsdad

0

एक्स :: एफ 2 का उपयोग कर; कोड

struct Y : private X{ 
    void f4(); 
}; 

नीचे की निजी वंशानुक्रम के कारण काम नहीं करना चाहिए यह वाई के माध्यम से तो एक्स :: f2 होगा संघर्ष एक्स के सदस्यों तक पहुँचने के लिए संभव नहीं है।

Z::X::f2 काम करना चाहिए। या Z::f2 काम करना चाहिए।

+0

सी ++ में एकाधिक-पहुंच नियम है। यदि बेस क्लास पदानुक्रम में एकाधिक पथों से कोई नाम पाया जा सकता है, और उनमें से एक सार्वजनिक है, तो सार्वजनिक पहुंच पथ लिया जाता है। '11.7/1' देखें। –

+0

@ लिटब: तो इसका मतलब है कि 'एक्स :: एफ 2 का उपयोग करना ठीक है' एक्स 'ओपी में' जेड 'के माध्यम से सुलभ है। लेकिन फिर 'एक्स' संदिग्ध है और इसलिए अस्पष्टता से संबंधित त्रुटि है। तो, वीएस -2010 त्रुटि संदेश 'सभी अधिभार योग्य नहीं हैं' शायद मुश्किल है। इसका मतलब है कि Comau सही है। मुझे कम से कम 'Z :: X :: f3' के लिए घोषणा का उपयोग करने में त्रुटि का संदेह है। – Chubsdad

+0

@chubsdad इसका मतलब यह है कि यह एक पहुंच त्रुटि नहीं है। यह उस पथ तक पहुंच को बदलता है जो सबसे अधिक पहुंच प्रदान करता है। यह 11.7/1 के बिना भी एक अस्पष्ट लुकअप नहीं होगा, लेकिन फिर हम नहीं जान पाएंगे कि हमें निजी या सार्वजनिक पहुंच लागू करने की आवश्यकता है या नहीं। –

0

सबसे पहले, जोहान्स के उत्तर को स्पष्ट करने के लिए। जब आप using Z::X::f2; कहते हैं, तो संकलक इसे कैसे ट्रैक किया जाना चाहिए इसका ट्रैक रखने के लिए f2 पर "पथ बनाएं" नहीं है। चूंकि Z::XX जैसा ही है, घोषणा बिल्कुल using X::f2; कहने जैसा ही है। इस उदाहरण के साथ यह कंट्रास्ट:

struct A { void f() {} void g() {} }; 
struct B { void f() {} void g() {} }; 
struct C { typedef A X; }; 
struct D { typedef B X; }; 
struct E : A, B { 
    using C::X::f; // C::X == A 
    using D::X::g; // D::X == B 
}; 

वाक्य रचना Z::X विरासत या सदस्यता की वजह से नहीं काम करता है, लेकिन क्योंकि पहचानकर्ता X गुंजाइश Z से सुलभ है। आपको Z::Z::Z::Z::X::X::X::X विज्ञापन मतली लिखने की भी अनुमति है, क्योंकि प्रत्येक वर्ग अपना नाम अपने दायरे में लाती है। इस प्रकार :: यहां विरासत व्यक्त नहीं करता है।

अब समस्या को हल करने के लिए। f2Y और ZX से विरासत में मिला है। इस प्रकार, यह Y और Z का प्रथम श्रेणी सदस्य है। E को X के बारे में जानने की आवश्यकता नहीं है क्योंकि यह एक छिपी हुई कार्यान्वयन जानकारी है। तो, आप

struct D : Y, Z{ 
    using Y::f2; // error: inaccessible 
    using Z::f3; 
}; 

चाहते 9.1/2 के संदर्भ में व्याख्या करने के लिए के रूप में आप से पूछना:

A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.

नाम XX::X रूप X में इंजेक्ट किया जाता। इसके बाद इसे Y और Z में विरासत में मिलाया जाता है। Y और Z अपने स्वयं के दायरे में X घोषित नहीं करते हैं।

10,2/2:

The following steps define the result of name lookup in a class scope, C. First, every declaration for the name in the class and in each of its base class sub-objects is considered. … If the resulting set of declarations are not all from sub-objects of the same type, or the set has a nonstatic member and includes members from distinct sub-objects, there is an ambiguity and the program is ill-formed. Otherwise that set is the result of the lookup.

ध्यान दें कि मैं बहुवचन शब्द उप वस्तुओं बोल्ड। यद्यपि X नाम दो उप-ऑब्जेक्ट्स में पाया गया है, वे दोनों एक ही प्रकार हैं, अर्थात् X

+0

'डी' के दायरे में, दो 'एक्स' उप-प्रोजेक्ट ('वाई' (पहुंच योग्य) से एक और ' जेड '(सुलभ))। $ 9.2 (इंजेक्शन क्लास नाम) के संदर्भ में।' एक्स :: एफ 2 का उपयोग नहीं करना चाहिए 'उपरोक्त तर्क के साथ अस्पष्ट होना चाहिए क्योंकि' एक्स '' डी 'का अस्पष्ट आधार है? – Chubsdad

+0

@chubs: 'एक्स' नामक केवल एक वर्ग है। 'एक्स' एक वर्ग का नाम है, उप-प्रोजेक्ट नहीं: यह मेरी बीमारियों का मुद्दा है ustration। – Potatoswatter

+0

@chubs: §9.1/2 ($ 9.2 नहीं) के रूप में, अद्यतन उत्तर देखें। स्पष्टीकरण के लिए – Potatoswatter

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

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