2015-10-10 14 views
7
struct A { A(int);}; 
struct B { explicit B(A); B(const B&);}; 
B b({0}); 

जीसीसी 5.1.0 जबकि बजना 3.6.0 सफल होता है त्रुटिअधिभार संकल्प

/dev/fd/63:3:8: error: call of overloaded 'B(<brace-enclosed initializer list>)' 
is ambiguous 
/dev/fd/63:3:8: note: candidates are: 
/dev/fd/63:2:27: note: B::B(const B&) 
/dev/fd/63:2:21: note: B::B(A) 

देता जीसीसी और बजना के बीच अलग-अलग परिणाम हो जाता है।

कौन सा सही है? क्यूं कर?

जीसीसी 5.1.0 के लिए: http://melpon.org/wandbox/permlink/pVe9eyXgu26NEX6X

बजना 3.6.0 के लिए: http://melpon.org/wandbox/permlink/WOi1md2dc519SPW0

यह Direct list initialization compiles successfully, but normal direct initialization fails, why? जो जीसीसी और बजना ही परिणाम प्राप्त करने के लिए इसी तरह की हो सकती है।

लेकिन यह एक अलग सवाल है। B(A) यहां स्पष्ट है। जीसीसी और क्लैंग अलग-अलग परिणाम प्राप्त करते हैं।

+0

http://stackoverflow.com/q/32469979/3647361 का डुप्लिकेट? – Columbo

+0

@ कोल्लमबो बी (ए) 'यहां स्पष्ट है और http://stackoverflow.com/questions/32469979/direct-list-initialization-compiles-sccessfully-but-normal-direct-initializati दोनों जीसीसी और क्लैंग एक ही परिणाम प्राप्त करते हैं लेकिन यहाँ अलग है। – stackcpp

+0

मेरा अनुमान है कि यह विभिन्न डिफ़ॉल्ट मानकों/मानक समर्थन के कारण है। –

उत्तर

3

अंतर जीसीसी इस विफल रहता है, मानक (जो कहता है कि सूची आरंभीकरण के लिए, स्पष्ट कंस्ट्रक्टर्स माना जाता है के अनुसार पर

struct A { explicit A(int); }; 
struct B { B(int); }; 
void f(A); 
void f(B); 

int main() { 
    f({ 1 }); 
} 

को कम किया जा सकता है - तो वे एक अस्पष्टता उपज सकते हैं - लेकिन वे सिर्फ चुने जाने की अनुमति नहीं है)। क्लैंग इसे स्वीकार करता है और दूसरे समारोह को कॉल करता है।

आपके मामले में, @Columbo Direct list initialization compiles successfully, but normal direct initialization fails, why? पर उनके उत्तर में क्या कहता है लागू होता है। इस मामले में कि आपके मामले में B(const B&); अब क्लैंग को स्वीकार्य नहीं है क्योंकि {0} -> B रूपांतरण दो संभावनाओं का सामना करेगा: स्पष्ट कन्स्ट्रक्टर या कॉपी कन्स्ट्रक्टर का दो बार फिर से उपयोग करना। जैसा कि ऊपर बताया गया है, पहला विकल्प क्लैंग द्वारा नहीं माना जाएगा और इस बार @ कोल्मुबो द्वारा स्पष्टीकरण लागू होता है और कॉपी कन्स्ट्रक्टर को दूसरी बार उपयोग नहीं किया जा सकता है क्योंकि उसे उपयोगकर्ता परिभाषित रूपांतरण की आवश्यकता होगी क्योंकि हमारे पास एक तत्व है (यहां, 0)। तो संक्षेप में, केवल पहला कन्स्ट्रक्टर सफल होता है और लिया जाता है।


के बाद से मैं समझता हूँ कि इस मुद्दे को अजीब अधिभार संकल्प नियमों के बारे में है और कुछ का पालन करने में सक्षम नहीं हो सकता है, यहाँ एक अधिक सहज व्याख्या दी गई है। नियम है कि सक्रिय कर रहे हैं, ताकि

  • b({0}) में गोटो http://eel.is/c++draft/dcl.init#17 और वहाँ से http://eel.is/c++draft/over.match.ctor को जो हमारी पहली या संदर्भ है का मतलब है। {0} तर्क के साथ गणना किए गए दो रचनाकार B(A); और B(const B&) हैं।

    • B(A) के लिए यह एक उपयोगकर्ता परिभाषित रूपांतरण के साथ काम करता है।

    • B(const B&) लिए, हम एक const B& जो http://eel.is/c++draft/over.ics.ref#2 को (http://eel.is/c++draft/dcl.init#dcl.init.list-3 की मदद से तो http://eel.is/c++draft/over.ics.list#8 करने के लिए हमें लाता प्रारंभ करने की आवश्यकता "अन्यथा, अगर टी एक संदर्भ प्रकार, है प्रकार टी द्वारा संदर्भित की एक prvalue अस्थायी प्रतिलिपि-सूची है प्रारंभिक ... ") तो http://eel.is/c++draft/over.best.ics#over.ics.list-6 पर। परिणामस्वरूप या संदर्भ में B(A); और B(const B&) उम्मीदवार हैं, 0 तर्क के साथ। यह हमारा दूसरा या संदर्भ है और कॉपी-सूची-प्रारंभिकता 13.3.1.7 है (जैसा कि over.ics.ref # 2 और dcl.init.list-3 द्वारा आवश्यक है)।

      • B(A) के लिए, निर्माता स्पष्ट है और इसलिए बजना द्वारा जीसीसी (इसलिए अस्पष्टता) द्वारा (कल्पना के साथ विरोधाभास में) पर ध्यान नहीं दिया लेकिन स्वीकार कर लिया।

      • B(const B&) के लिए, यह परिदृश्य @ कोल्लमबो द्वारा संभाला गया परिदृश्य है और इसलिए उपयोगकर्ता द्वारा परिभाषित रूपांतरण की आवश्यकता होगी। नए ड्राफ्ट में अब यह नियम नहीं है (लेकिन शायद इसे वापस जोड़ा जाएगा)। लेकिन 0 से const B& सामान्य उपयोगकर्ता परिभाषित रूपांतरण (सूची प्रारंभिकरण नहीं) होगा, यह वैसे भी रूपांतरण के लिए आवश्यक स्पष्ट कन्स्ट्रक्टर को अनदेखा करेगा (प्रतिलिपि बनाने वाले इस संभावित दूसरे उपयोग के लिए), और इसलिए उपयोगकर्ता द्वारा परिभाषित वैसे भी रूपांतरण संभव नहीं होगा और जब मैंने उपर्युक्त लघु सारांश लिखा था, तो मैंने सोचा था कि नियम बहुत कम महत्व का है।

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

2

सही सूची प्रारंभ अर्थ विज्ञान

B b{0}; 

जो ठीक संकलित है। यदि आप B b({0}); लिखते हैं, तो gcc तय नहीं कर सकता कि B(A) पर कॉल करें या B ({0}) बनाएं और फिर दूसरे चरण में B(const B&) के साथ कॉपी करें। इन दो विकल्पों के बीच कोई प्राथमिकता आदेश नहीं है।

यह भाषा समस्या है, संकलक की समस्या नहीं। यह gcc bug report देखें।

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