2015-07-03 7 views
6

निम्नलिखित कोड का टुकड़ा पर विचार करें interpeted नहीं हैं:क्यों ब्रेसिज़ में अदिश के रूप में initializer_list

#include <iostream> 
#include <initializer_list> 

struct C 
{ 
    C(std::initializer_list<int>) { std::cout << "list\n"; } 
    C(std::initializer_list<int>, std::initializer_list<int>) { std::cout << "twice-list\n"; } 
}; 

int main() 
{ 
    C c1 { {1,2}, {3} }; // twice-list ctor 
    C c2 { {1}, {2} }; // why not twice-list ? 
    return 0; 
} 

Live डेमो।

c2 चर के लिए ब्रेसिज़ में स्केलर मान अलग-अलग std ::itializer_list के रूप में क्यों नहीं समझा जाता है?

उत्तर

4

सबसे पहले, कुछ बहुत ही महत्वपूर्ण: आप कंस्ट्रक्टर्स दो भिन्न प्रकार की है। विशेष रूप से पहले, C(std::initializer_list<int>) को आरंभकर्ता-सूची कन्स्ट्रक्टर कहा जाता है। दूसरा सिर्फ एक सामान्य उपयोगकर्ता परिभाषित कन्स्ट्रक्टर है।

[dcl.init.list]/p2

एक निर्माता, अगर अपनी पहली पैरामीटर प्रकार std::initializer_list<E> या संदर्भ के लिए संभवतः सीवी योग्य std::initializer_list<E> कुछ प्रकार E के लिए की है एक प्रारंभकर्ता-सूची निर्माता है और या तो कोई अन्य पैरामीटर नहीं हैं या अन्य सभी पैरामीटर में डिफ़ॉल्ट तर्क हैं (8.3.6)।

एक सूची-आरंभीकरण एक या अधिक प्रारंभकर्ता-खंड युक्त में, प्रारंभकर्ता-सूची कंस्ट्रक्टर्स किसी अन्य निर्माताओं से पहले माना जाता है। यही है, शुरुआतकर्ता सूची सूची निर्माता अधिभार संकल्प के दौरान प्रारंभिक उम्मीदवार हैं।

[over.match.list]/p1

गैर कुल वर्ग प्रकार T की वस्तुओं सूची-प्रारंभ 8.5.4 निर्दिष्ट करता है ऐसी है कि कि अधिभार संकल्प इस खंड में नियमों के अनुसार किया जाता है कर रहे हैं , अधिभार संकल्प दो चरणों में निर्माता का चयन करता है:

  • प्रारंभ में, उम्मीदवार कार्यों वर्ग T और तर्क सूची के प्रारंभकर्ता-सूची कंस्ट्रक्टर्स (8.5.4) एक एकल तर्क के रूप में प्रारंभकर्ता सूची के होते हैं ।

  • यदि कोई व्यवहार्य प्रारंभकर्ता-सूची निर्माता पाया जाता है, अधिभार संकल्प फिर से है, जहां उम्मीदवार कार्यों वर्ग T के सभी निर्माणकर्ता और तर्क सूची तत्वों प्रारंभकर्ता सूची के के होते हैं किया जाता है।

तो c1 और c2 के दोनों घोषणाओं के लिए उम्मीदवार सेट केवल C(std::initializer_list<int>) निर्माता के होते हैं।

कन्स्ट्रक्टर का चयन करने के बाद तर्कों का मूल्यांकन यह देखने के लिए किया जाता है कि क्या उन्हें पैरामीटर प्रकारों में परिवर्तित करने के लिए एक अंतर्निहित रूपांतरण अनुक्रम मौजूद है या नहीं। यह प्रारंभकर्ता-सूची रूपांतरण के लिए नियमों को करने के लिए हमें ले जाता है:

[over.ics.list]/p4 (जोर मेरा):

अन्यथा, यदि पैरामीटर प्रकार std::initializer_list<X>और सभी के तत्वों है प्रारंभकर्ता सूची को X में पूर्ण रूप से परिवर्तित किया जा सकता है, अंतर्निहित रूपांतरण अनुक्रम सूची के तत्व को X में परिवर्तित करने के लिए आवश्यक सबसे खराब रूपांतरण है, या यदि प्रारंभकर्ता सूची में कोई तत्व नहीं है, तो पहचान रूपांतरण।

इसका मतलब है कि एक रूपांतरण मौजूद है यदि प्रारंभकर्ता सूची के प्रत्येक तत्व को int में परिवर्तित किया जा सकता है।

अब के लिए c1 पर आइए फोकस: प्रारंभकर्ता-सूची {{1, 2}, {3}} के लिए, प्रारंभकर्ता-खंड {3}int में बदला जा सकता ([over.ics.list] /p9.1), लेकिन नहीं {1, 2} (यानी int i = {1,2} बीमार है -formed)। इसका मतलब है उपरोक्त उद्धरण के लिए शर्त का उल्लंघन किया जाता है। चूंकि कोई रूपांतरण है, अधिभार संकल्प विफल रहता है के बाद से वहाँ कोई अन्य व्यवहार्य निर्माता ये हैं और हम [over.match.list] की/p1 दूसरे चरण के लिए वापस लिया जाता है:

  • कोई व्यवहार्य प्रारंभकर्ता-सूची तो कन्स्ट्रक्टर पाया जाता है, ओवरलोड रिज़ॉल्यूशन फिर से किया जाता है, जहां उम्मीदवार कार्य कक्षा T के सभी रचनाकार होते हैं और तर्क सूची में प्रारंभकर्ता सूची के तत्व होते हैं।

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

प्रारंभकर्ता-सूची {1, 2} में, दोनों प्रारंभकर्ता-खंड, int में बदला जा सकता है ताकि पूरे प्रारंभकर्ता-खंड initializer_list<int>, {3} के लिए एक ही बदला जा सकता है। अधिभार संकल्प को दूसरे कन्स्ट्रक्टर के साथ चुना जा रहा है।

अब c2 पर ध्यान केंद्रित करें, जो अब आसान होना चाहिए। प्रारंभकर्ता-सूची निर्माता का पहले मूल्यांकन किया जाता है, और, { {1}, {2} } का उपयोग करके int पर {1} और {2} से रूपांतरण निश्चित रूप से मौजूद है, इसलिए पहला कन्स्ट्रक्टर चुना गया है।

+0

नहीं है, क्यों मैं दूसरे कन्स्ट्रक्टर को 'सी (std :: startizer_list , std :: startizer_list ) में बदल दूंगा और 'सी 2' {सी c2 {{1.0}, {2}} को' c2' घोषणा; 'मैं संकलक प्राप्त करूंगा त्रुटि? आपके उत्तर के अनुसार इस के लिए दूसरा कन्स्ट्रक्टर चुना जाना चाहिए। या मुझे गलत निष्कर्ष निकाला गया था? [लाइव डेमो] (http://coliru.stacked-crooked.com/a/e299e66462e220cf) – alexolut

+1

@alexolut [over.isc.list]/p4: "[...] और प्रारंभकर्ता सूची के सभी तत्व कर सकते हैं स्पष्ट रूप से 'एक्स' में परिवर्तित हो जाएं," ए 'डबल' को निश्चित रूप से 'int' में परिवर्तित किया जा सकता है, इसलिए इस खंड में। आगे पढ़ना: "अंतर्निहित रूपांतरण अनुक्रम सूची के तत्व को 'एक्स'' में परिवर्तित करने के लिए आवश्यक सबसे खराब रूपांतरण है। यह निहित रूपांतरण अनुक्रम * संकुचित रूपांतरण अनुक्रम * है। तो ऐसा नहीं है कि एक व्यवहार्य प्रारंभकर्ता सूची निर्माता नहीं मिला (चरण 2 पर जाने का मतलब है कि हमें एक नहीं मिला है), यह है कि रूपांतरण स्वयं प्रोग्राम को खराब बना देता है। – 0x499602D2

+0

आईई। व्यावहारिक कन्स्ट्रक्टर पाया गया था, लेकिन तर्क रूपांतरण स्वयं व्यवहार्य नहीं है (बीमार गठित)। इस मामले में हम दूसरे चरण तक नहीं पहुंच पाए हैं। - क्या मैं इसे सही समझता हूँ? – alexolut

0

C c2 { {1}, {2} };

इस लाइन std::initializer_list<int> के दो तर्क में पारित नहीं करता, बल्कि, यह एक std::initializer_list<std::initializer_list<int> > में गुजर रहा है। एक समाधान के बजाय इतनी तरह c2 का दृष्टांत होगा:

C c2({1}, {2});

+1

प्रश्न "क्यों" है। –

+0

मैं देखता हूं। मुझे एक संदर्भ वास्तव में त्वरित और संपादित करने दें। – ross

+0

असल में, "क्यों" का उत्तर है क्योंकि std :: startizer_list को एक निर्माता में दिखाई देने पर एक विशेष प्राथमिकता है।यदि आपके पास std :: startizer_list के साथ कोई कन्स्ट्रक्टर है और आप ऑब्जेक्ट को ब्रेस प्रारंभिकरण के साथ बनाते हैं, तो संकलक std :: startizer_list कंस्ट्रक्टर फिट करने के लिए आपके द्वारा इनपुट किए गए रूपांतरित करने के लिए अपना सर्वश्रेष्ठ प्रयास करेगा, भले ही यह सबसे अच्छा फिट – KABoissonneault

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