9

सी ++ 11 में, ऐसा लगता है जैसे कि यह इस प्रकार एक std::map<std::string, int> प्रारंभ करने में कानूनी है:कौन से भाषा नियम सी ++ 11 को कम करने के लिए अनुमति देते हैं कि यह जोड़े की प्रारंभकर्ता_सूची है?

std::map<std::string, int> myMap = { 
    { "One", 1 }, 
    { "Two", 2 }, 
    { "Three", 3 } 
}; 

Intuitively, इस समझ में आता है - ब्रेस संलग्न प्रारंभकर्ता तार के जोड़े की एक सूची है, और std::map<std::string, int>::value_typestd::pair<std::string, int> है (संभवतः कुछ const योग्यता के साथ।

हालांकि, मुझे यकीन नहीं है कि मैं समझता हूं कि टाइपिंग कैसे काम करती है। अगर हम यहां परिवर्तनीय घोषणा को खत्म करते हैं और केवल ब्रेस-संलग्न प्रारंभकर्ता है, तो संकलक यह नहीं जानता कि यह std::initializer_list<std::pair<std::string, int>> पर देख रहा था क्योंकि यह नहीं पता था कि ब्रेसिड जोड़े फिर से प्रस्तुत std::pair एस। इसलिए, ऐसा लगता है कि संकलक किसी भी तरह से ब्रेस-संलग्न प्रारंभकर्ता को एक प्रकार निर्दिष्ट करने के कार्य को परिभाषित कर रहा है जब तक कि std::map कन्स्ट्रक्टर से पर्याप्त प्रकार की जानकारी न हो, यह पता लगाने के लिए कि नेस्टेड ब्रेसिज़ जोड़े के लिए हैं। मुझे ऐसा कुछ याद नहीं है जैसे सी ++ 03 में हो रहा है; मेरे सबसे अच्छे ज्ञान के लिए, अभिव्यक्ति का प्रकार कभी भी इसके संदर्भ पर निर्भर नहीं था।

कौन से भाषा नियम इस कोड को सही तरीके से संकलित करने के लिए अनुमति देते हैं और संकलक के लिए यह निर्धारित करने के लिए कि प्रारंभकर्ता सूची के लिए किस प्रकार का उपयोग करना है? मैं सी ++ 11 spec के विशिष्ट संदर्भों के साथ उत्तर की उम्मीद कर रहा हूं, क्योंकि यह वास्तव में दिलचस्प है कि यह काम करता है!

धन्यवाद!

+0

सी ++ 03 में ब्रेस-संलग्न सूचियां प्रारंभिक संदर्भ के लिए पहले से ही बहुत विशिष्ट थीं। सी ++ 03 नेस्टेड समेकित (शायद 'std :: pair myArray []') से ब्रेसिज़ का उपयोग करके प्रारंभ में कोई महत्वपूर्ण अंतर नहीं है, सिवाय इसके कि प्रकार का नाम सीधे नहीं है, यह अनुमानित है उपलब्ध कन्स्ट्रक्टर। –

+0

बीटीडब्ल्यू, निहित रूपांतरण ऑपरेटर (सदस्य 'ऑपरेटर टी() ') दूसरी जगह है जहां संदर्भ अभिव्यक्ति के प्रकार को निर्धारित करता है (और ओवरलोड रिज़ॉल्यूशन के लिए उपयोग किया जाता है)। –

+2

'ब्रेस्ड-इनिट-लिस्ट 'अभिव्यक्ति नहीं है और इसमें कोई प्रकार नहीं है। कोई कटौती नहीं है, प्रारंभकर्ता-सूची कन्स्ट्रक्टर के बीच केवल अधिभार संकल्प (जिसमें से केवल एक है) – Cubbi

उत्तर

9

अभिव्यक्ति

std::map<std::string, int> myMap = { 
    { "One", 1 }, 
    { "Two", 2 }, 
    { "Three", 3 } 
}; 

सही पक्ष पर में आप एक braced-init-सूची प्रत्येक तत्व का भी एक braced-init-सूची है। पहली बात यह होती है कि std::map की प्रारंभकर्ता सूची निर्माता माना जाता है।

map(initializer_list<value_type>, 
    const Compare& = Compare(), 
    const Allocator& = Allocator()); 

map<K, V>::value_typepair<const K, V> के लिए एक typedef, इस मामले pair<const string, int> में है। आंतरिक ब्रेसिड-इनिट-सूचियों को सफलतापूर्वक map::value_type में परिवर्तित किया जा सकता है क्योंकि std::pair में एक निर्माता है जो अपने दो घटक प्रकारों के संदर्भ लेता है, और std::string में एक अंतर्निहित रूपांतरण कन्स्ट्रक्टर है जो char const * लेता है।

इस प्रकार std::map की प्रारंभकर्ता सूची कन्स्ट्रक्टर व्यवहार्य है, और निर्माण नेस्टेड ब्रेस्ड-इनिट-सूचियों से हो सकता है।

प्रासंगिक standardese §13.3.1.7/1 में मौजूद है [over.match.list]

गैर कुल वर्ग प्रकार T की वस्तुओं सूची-प्रारंभ (8.5.4) कर रहे हैं, ओवरलोड रिज़ॉल्यूशन दो चरणों में कन्स्ट्रक्टर का चयन करता है:
- प्रारंभ में, उम्मीदवार फ़ंक्शन T वर्ग के प्रारंभकर्ता-सूची निर्माता (8.5.4) हैं और तर्क सूची में प्रारंभिक सूची को एकल तर्क के रूप में शामिल किया गया है।
- यदि कोई व्यवहार्य प्रारंभकर्ता-सूची निर्माता नहीं मिला है, तो ओवरलोड रिज़ॉल्यूशन फिर से किया जाता है, जहां उम्मीदवार कार्य T वर्ग के सभी निर्माता होते हैं और तर्क सूची प्रारंभकर्ता सूची के तत्व होते हैं।

पहले बुलेट क्या, map की initializer_list निर्माता का कारण बनता है बाहरी braced-init-सूची के लिए चयनित किया है, जबकि आंतरिक के लिए सही pair निर्माता के चयन में दूसरी गोली परिणाम braced init--है सूचियों।

+0

अद्भुत, धन्यवाद! – templatetypedef

2

यह सूची-प्रारंभिकरण है। नियमों में §8.5.4 [dcl.init.list]/मानक की p3 पाए जाते हैं:

एक वस्तु या प्रकार टी के संदर्भ की सूची-प्रारंभ के रूप में परिभाषित किया गया है इस प्रकार है:

  • यदि प्रारंभकर्ता सूची में कोई तत्व नहीं है और टी एक डिफ़ॉल्ट प्रकार के साथ एक वर्ग प्रकार है, तो वस्तु मान-प्रारंभिक है।
  • अन्यथा, यदि टी कुल है, तो कुल प्रारंभिक कार्य (8.5.1) किया जाता है। नीचे वर्णित और एक ही प्रकार के एक वर्ग से एक वस्तु का आरंभीकरण के लिए नियमों के अनुसार वस्तु को प्रारंभ करने के लिए इस्तेमाल के रूप में [उदाहरण छोड़े गए]
  • अन्यथा, अगर टी std::initializer_list<E> की एक विशेषज्ञता है, एक initializer_list वस्तु का निर्माण किया है (8.5)।
  • अन्यथा, यदि टी एक वर्ग प्रकार है, तो रचनाकारों पर विचार किया जाता है। लागू कन्स्ट्रक्टर की गणना की जाती है और अधिभार संकल्प (13.3, 13.3.1.7) के माध्यम से सबसे अच्छा चुना जाता है। यदि कोई तर्क रूपांतरण (नीचे देखें) किसी भी तर्क को बदलने के लिए आवश्यक है, प्रोग्राम खराब है।
  • [उदाहरण और नियमों के शेष के छोड़े गए]

नोट संकल्प ओवरलोड है कि इन मामलों में (§13.3.1.7 [over.match.list]) में std::initializer_list कंस्ट्रक्टर्स का चुनाव करेगा।

इस प्रकार जब संकलक एक गैर कुल की एक वस्तु, गैर std::initializer_list वर्ग प्रकार से प्रारंभ करने के लिए इस्तेमाल एक braced सूची देखता है, यह उचित निर्माता का चयन करने के अधिभार संकल्प प्रदर्शन करेंगे, initializer_list निर्माता पसंद करते हैं, तो एक व्यवहार्य एक मौजूद है (क्योंकि यह std::map के लिए करता है)।

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

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