12

के साथ सीधे प्रारंभिकता की वैधता पर असहमत हैं क्लैंग (3.9) का नवीनतम संस्करण f की दूसरी पंक्ति पर इस कोड को अस्वीकार करता है; जीसीसी (6.2) के नवीनतम संस्करण को यह स्वीकार करता है:क्लैंग और जीसीसी रूपांतरण ऑपरेटर

struct Y { 
    Y(); 
    Y(const Y&); 
    Y(Y&&); 
}; 

struct X { 
    operator const Y(); 
}; 

void f() { 
    X x; 
    Y y(x); 
} 

तो इन परिवर्तनों के किसी भी बना रहे हैं, बजना तो कोड को स्वीकार करेंगे:

  • निकालें Y की चाल निर्माता
  • const निकालें रूपांतरण ऑपरेटर
  • से साथ Y y(x) बदलें Y y = x

मूल उदाहरण कानूनी है? कौन सा कंपाइलर गलत है? मानक में रूपांतरण कार्यों और ओवरलोड रिज़ॉल्यूशन के बारे में अनुभागों की जांच करने के बाद मुझे एक स्पष्ट उत्तर नहीं मिला है।

+0

इसके अलावा आप 'वाई (कॉन्स वाई &&);' – alexolut

+1

कर सकते हैं यह दिखाने के लिए अच्छा होगा कि अस्वीकृति संदेश –

उत्तर

4

जब हम रचनाकारों की गणना कर रहे हैं और उनकी व्यवहार्यता की जांच करते हैं - यानी चालक कन्स्ट्रक्टर के लिए एक अंतर्निहित रूपांतरण अनुक्रम है, [dcl.init.ref]/5 अंतिम बुलेट बिंदु (5.2.2) तक गिर जाता है, जिसे मूल मुद्दों द्वारा संशोधित किया गया था 1604 और 1571 (उस क्रम में)।

इन प्रस्तावों की लब्बोलुआब यह है कि

हैं T1 या T2 एक वर्ग प्रकार है और T1 नहीं T2 को संदर्भ से संबंधित है, उपयोगकर्ता के निर्धारित रूपांतरण कॉपी-आरंभीकरण के लिए नियमों का उपयोग पर विचार कर रहे हैं उपयोगकर्ता की परिभाषित रूपांतरण (8.6, 13.3.1.4, 13.3.1.5) द्वारा "सीवी 1T1" की वस्तु का एक वस्तु कार्यक्रम गैर-गठित होता है यदि संबंधित गैर-संदर्भ प्रति-प्रारंभिकता खराब हो जाएगी। गैर-संदर्भ प्रति-प्रारंभिकरण के लिए वर्णित रूपांतरण फ़ंक्शन पर कॉल का परिणाम, फिर संदर्भ को प्रत्यक्ष-प्रारंभ करने के लिए उपयोग किया जाता है।

पहला भाग केवल रूपांतरण ऑपरेटर का चयन करने का कारण बनता है। तो, बोल्डफैस्ड भाग के अनुसार, हम Y&& को प्रत्यक्ष-प्रारंभ करने के लिए const Y का उपयोग करते हैं।

हैं T1 संदर्भ से संबंधित T2 के लिए है:: फिर, हम पिछले बुलेट बिंदु है, जो विफल रहता है (5.2.2.3) की वजह से जब तक के माध्यम से गिर
- CV1 रूप में एक ही सीवी-योग्यता होगी , या सीवी 2 से अधिक सीवी-योग्यता; और

हालांकि, यह अब हमारे मूल अधिभार रिज़ॉल्यूशन से संबंधित नहीं है, जो केवल यह देखता है कि रूपांतरण ऑपरेटर का संदर्भ संदर्भित करने के लिए उपयोग किया जाएगा। आपके उदाहरण में, ओवरलोड रिज़ॉल्यूशन चालक का चयन करता है क्योंकि [over.ics.rank]/(3.2.5), और उसके बाद उपरोक्त पैराग्राफ प्रोग्राम को खराब बना देता है। यह एक दोष है और core issue 2077 के रूप में दायर किया गया है। एक समझदार समाधान ओवरलोड रिज़ॉल्यूशन के दौरान चाल कन्स्ट्रक्टर को त्याग देगा।

यह सब आपके फिक्सेस पर समझदार wrt बनाता है: const को हटाने से गिरावट आती है क्योंकि प्रकार अब संदर्भ-संगत हैं, और चालक कन्स्ट्रक्टर को हटाने से कॉपी कन्स्ट्रक्टर छोड़ देता है, जिसमें एक कॉन्स्ट रेफरेंस होता है (यानी काम करता है)। अंत में, जब हम Y y = x; लिखते हैं, [dcl.init]/(17.6.2) के बजाय, (17.6.3) लागू होता है;

अन्यथा (यानी, शेष प्रति-प्रारंभिक मामलों के लिए), उपयोगकर्ता द्वारा परिभाषित रूपांतरण अनुक्रम जो स्रोत प्रकार से गंतव्य प्रकार में परिवर्तित हो सकते हैं या (जब एक रूपांतरण फ़ंक्शन का उपयोग किया जाता है) उसके व्युत्पन्न वर्ग में होते हैं जैसा कि 13.3.1.4 में वर्णित है, और सबसे अच्छा अधिभार संकल्प (13.3) के माध्यम से चुना जाता है। [...]। कॉल का उपयोग उपर्युक्त नियमों के अनुसार प्रत्यक्ष-प्रारंभ करने के लिए किया जाता है, ऑब्जेक्ट जो प्रति-प्रारंभिकता का गंतव्य है।

आईई।प्रारंभिकरण प्रभावी रूप से Y y(x.operator const Y()); जैसा ही होता है, जो सफल होता है, क्योंकि चालक कन्स्ट्रक्टर व्यवहार्य नहीं है (Y&& y = const Y उथल-पुथल में विफल रहता है) और कॉपी कन्स्ट्रक्टर का चयन किया जाता है।

+0

"ओवरलोड रिज़ॉल्यूशन का हिस्सा नहीं" मैंने इस तथ्य से घटाया कि सीडब्ल्यूजी 2077 का कहना है कि चालक कन्स्ट्रक्टर अधिभार संकल्प द्वारा सही ढंग से "चयनित" है, और केवल तभी प्रोग्राम विफल हो जाता है। थोड़ा अजीब लगता है ... विशेष रूप से क्योंकि उस आवश्यकता के दूसरे बुलेट में कोई फर्क पड़ता है (देखें [ओवर .match.viable]/3) – Columbo

+0

कॉपी-इनिट उम्मीदवारों के एक अलग सेट का उपयोग करता है (देखें [over.match.copy])। इसके परिणामस्वरूप रूपांतरण फ़ंक्शन को ओवरलोड रिज़ॉल्यूशन द्वारा सीधे चुना जा रहा है, और इसका परिणाम 'y' को प्रत्यक्ष-प्रारंभ करने के लिए उपयोग किया जा रहा है। –

+0

@ टी.सी. मैंने वास्तव में जांच नहीं की थी कि किसी भी आगे, बेवकूफ मानते हुए कि इससे कोई फर्क नहीं पड़ता .. धन्यवाद। – Columbo

4

मुझे लगता है कि यह एक क्लैंग बग है।

हम [over.match.ctor] के साथ शुरू:

(8,6), एक ही की एक अभिव्यक्ति या एक व्युत्पन्न वर्ग प्रकार (से कॉपी-प्रारंभ जब वर्ग प्रकार की वस्तुओं डायरेक्ट-प्रारंभ कर रहे हैं 8.6), या डिफ़ॉल्ट-प्रारंभिक (8.6), अधिभार संकल्प निर्माता का चयन करता है। प्रत्यक्ष-प्रारंभिकरण के लिए या डिफ़ॉल्ट-प्रारंभिकरण जो प्रति-प्रारंभिकरण के संदर्भ में नहीं है, उम्मीदवार कार्य प्रारंभ किए जा रहे ऑब्जेक्ट के वर्ग के सभी निर्माता हैं।

तो हम उदाहरण के लिए, कॉपी कन्स्ट्रक्टर पर विचार करते हैं। क्या कॉपी कन्स्ट्रक्टर व्यवहार्य है?

[dcl.init.ref] से

:

- अगर प्रारंभकर्ता अभिव्यक्ति [...] एक वर्ग प्रकार (एक वर्ग प्रकार यानी, टी 2 है), जहां टी 1 संदर्भ से संबंधित नहीं है है टी 2 तक, और प्रकार "सीवी 3 टी 3" के रूप में परिवर्तित हो सकता है, जहां "सीवी 1 टी 1" संदर्भ "सीवी 3 टी 3" (13.3.1.6 देखें) के साथ संगत है, तो संदर्भ प्रारंभकर्ता के मान से जुड़ा हुआ है पहले मामले में अभिव्यक्ति और दूसरे मामले में रूपांतरण का परिणाम।

[over.match.ref] में वे उम्मीदवार कार्य हैं:

डायरेक्ट-आरंभीकरण के लिए, उन स्पष्ट रूपांतरण कार्यों कि CV2 टी 2 के लिए एस और उपज प्रकार "lvalue संदर्भ के भीतर छिपा नहीं कर रहे हैं "या" सीवी 2 टी 2 "या" सीवी 2 टी 2 "के क्रमशः संदर्भ, जहां टी 2 टी के समान प्रकार है या योग्यता रूपांतरण (4.5) के साथ टाइप टी में परिवर्तित किया जा सकता है, उम्मीदवार कार्य भी हैं।

जिसमें हमारे operator const Y() शामिल हैं। इसलिए कॉपी कन्स्ट्रक्टर व्यवहार्य है। चाल कन्स्ट्रक्टर नहीं है (चूंकि आप const रावल्यू के गैर-const रैल्यू संदर्भ को बाध्य नहीं कर सकते हैं, इसलिए हमारे पास बिल्कुल एक व्यवहार्य उम्मीदवार है, जो प्रोग्राम को अच्छी तरह से गठित करता है।


एर, एक अनुसरण के रूप में, इस LLVM bug 16682 है, जो बनाता है यह बहुत क्या मैं शुरू में दिए गए तुलना में अधिक जटिल लगते हैं।

+1

क्या है मुझे लगता है कि रिचर्ड का विश्लेषण सही है। चाहे एक अंतर्निहित रूपांतरण अनुक्रम बनाया जा सकता है, परिणामस्वरूप रूपांतरण से भिन्न है संकलित करेंगे, और यहां [over.ics.ref]/2 ऐसा प्रतीत होता है कि ऐसा रूपांतरण अनुक्रम बनाया जा सकता है। (यह अब सीडब्ल्यूजी 2077 है।) –

+0

@TC एक बेहतर उत्तर लिखना चाहते हैं और फिर मैं इसे हटा दूंगा एक? – Barry

+0

@ टीसी वैसे भी, पीटीएएल – Columbo

-1

जब आप कोड लिखते हैं जहां दो सभ्य कंपाइलर्स असहमत हैं कि यह कानूनी है या नहीं, तो आप किनारे के बहुत करीब प्रोग्रामिंग कर रहे हैं। मान लें कि मैं उस कोड का समर्थन करने वाला एक रखरखाव प्रोग्रामर हूं। आप मुझे यह कैसे उम्मीद करते हैं कि यह कानूनी है, और इस कोड के अर्थशास्त्र वास्तव में क्या हैं, अगर यहां तक ​​कि जीसीसी और क्लैंग भी सहमत नहीं हो सकते हैं?

अपना कोड बदलें। इसे आसान बनाएं ताकि कम "चालाक" प्रोग्रामर और कंपाइलर दोनों बिना किसी समस्या के समझ सकें। चारों ओर सबसे अधिक "चालाक" प्रोग्रामर होने के लिए कोई पुरस्कार नहीं हैं।

कॉलमबो के उत्तर को देखें: मुझे कोई संदेह नहीं है कि स्थिति का उनका विश्लेषण बिल्कुल ठीक और सही है। लेकिन मैं उस कोड का समर्थन नहीं करना चाहता जिसके लिए एक बहुत ही चालाक 50 लाइन विश्लेषण की आवश्यकता है ताकि यह प्रदर्शित किया जा सके कि यह सही है। यदि आप सी ++ कंपाइलर्स लिख रहे हैं, तो आपको सावधानी से उसका जवाब पढ़ना चाहिए। यदि आप एप्लिकेशन कोड लिख रहे हैं, तो आपको कभी भी कोड लिखना नहीं चाहिए जिसके लिए उसके उत्तर को देखने की आवश्यकता है।

+1

मैं सामान्य रूप से भावना से असहमत नहीं हूं, लेकिन यह गलत लगता है; ओपी में कोड उदाहरण किसी भी विदेशी फीचर्स का उपयोग नहीं करता है: प्रतिलिपि/चालक रचनाकारों वाला एक वर्ग विशेष नहीं है, न ही एक वर्ग है जो किसी अन्य वर्ग के निहित रूपांतरण के साथ है। इसके अलावा, अपेक्षित परिणाम पूरी तरह स्पष्ट और काफी सहज है; समस्या केवल उत्पन्न हुई क्योंकि मानक में एक दोष है (नियमों के बीच कुछ अप्रत्याशित बातचीत के कारण) और एक कंपाइलर जिसने पत्र को दोष दिया। –

+0

@ टी.सी. निष्पक्ष होने के लिए, एक रूपांतरण ऑपरेटर 'कॉन्स्ट' के गैर-संदर्भ रिटर्न प्रकार को मेरे लिए थोड़ा समझ नहीं आता है, इसलिए यह तर्कसंगत रूप से एक विशिष्ट मामला है। हालांकि, मैं मानता हूं कि कार्यान्वयन के बीच असहमति जटिल कोड के कारण जरूरी नहीं है। – Columbo

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