2016-01-10 17 views
18

है मैं निम्नलिखित निर्माता:दो खाली खाली घुंघराले ब्रेसिज़ क्यों {{}} एक तत्व के साथ एक std :: startizer_list <double> बनाता है, शून्य नहीं?

MyItem(std::initializer_list<double> l) { 
    std::cout << "l size " << l.size() << ")" << std::endl; 
} 

जो बाद में डबल घुंघराले ब्रेसिज़ के साथ कहा जाता है:

MyItem{{}} 

परिणाम l.size() देता है 1.

है यांत्रिकी के पीछे क्या है ऐसा व्यवहार?

ऐसा लगता है कि एकमात्र तत्व के लिए एक डिफ़ॉल्ट कन्स्ट्रक्टर की तरह नेस्टेड {} नाटकों की तरह लगता है, लेकिन मुझे समझ में नहीं आता कि कटौती क्यों और कैसे टाइप करती है।

+1

ध्यान दें कि http://ru.stackoverflow.com पर एक रूसी स्टैक ओवरफ्लो है –

उत्तर

10

जब आप MyItem ऑब्जेक्ट को प्रारंभ करने के लिए ब्रेसिज़ (सूची-प्रारंभिकरण) का उपयोग करते हैं, तो आपके द्वारा दिखाए गए सूची निर्माता बहुत लालची हैं।

MyItem foo{{}}; 

यह काम करता है क्योंकि वहाँ कुछ संदर्भों हैं: - एक मूल्य-प्रारंभ double (0,0)

MyItem foo({}); 
MyItem foo{std::initializer_list<double>{}}; 

यह एक एक भी तत्व से युक्त सूची से गुजरता है:

ये एक खाली सूची से होकर गुजरेगा जहां आप ज्ञात प्रकार के स्थान पर बस ब्रेसिज़ का उपयोग कर सकते हैं। यहां, यह सूची निर्माता को पसंद करने से जानता है कि दी गई सूची में double होना चाहिए।

पूर्णता के लिए, ऐसा लगता है कि यह एक खाली सूची पास करता है, लेकिन यह वास्तव में foo को प्रारंभ करता है यदि उसके पास डिफ़ॉल्ट कन्स्ट्रक्टर है (या विशेष मामलों में, लगभग कुछ समकक्ष करता है)। यदि कोई डिफ़ॉल्ट कन्स्ट्रक्टर नहीं है, तो यह सूची निर्माता, as shown here का चयन करेगा।

MyItem foo{}; 
+0

क्या आप इस प्रकार को वास्तव में कैसे घटा सकते हैं? क्या {} डिफॉल्ट कन्स्ट्रक्टर की भूमिका निभाता है? कोई प्रकार या 'ऑटो' निर्दिष्ट नहीं है। मुझे यांत्रिकी में दिलचस्पी है जैसे संकलक इसे कम करने के लिए कदम उठाते हैं। –

+1

@ निकोलय पोलिवानोव, यह सबसे मुश्किल संदर्भ हो सकता है जहां ब्रेसिज़ की अनुमति है। आम तौर पर, जब आप प्रकार को दोहराएंगे तो उन्हें अनुमति दी जाएगी और संकलक पहले ही इसे जानता है। उदाहरण के लिए, आपके पास 'void foo (string)' है। मान लीजिए कि आप "abcde" के पहले n अक्षर पास करना चाहते हैं, जहां n एक चर है। आप आमतौर पर कुछ ऐसा करेंगे जैसे 'foo (string ("abcde", n)); '। हालांकि, यह स्पष्ट रूप से एक स्ट्रिंग है, तो इस प्रकार को दोहराएं क्यों? 'foo ({" abcde ", n}); 'जब आप' {} 'का उपयोग करते हैं, तो यह आम तौर पर मूल्य-प्रारंभिक होता है, जो आमतौर पर 0 या डिफ़ॉल्ट कन्स्ट्रक्टर होता है। 'foo ({}); 'एक खाली स्ट्रिंग पास करता है। – chris

+1

फिर भी, सूची निर्माता बहुत लालची है। उदाहरण के लिए, 'std :: string' में' char' की एक सूची लेते हुए एक सूची निर्माता है। यदि आप 'foo ({5,' ए '}) करते हैं, तो, आप पांच ए अक्षर (एएएएएए) के साथ एक स्ट्रिंग प्राप्त करने की उम्मीद कर सकते हैं क्योंकि इसके लिए एक कन्स्ट्रक्टर है। हालांकि, भले ही 5 'char' नहीं है, फिर भी यह एक के लिए परिवर्तनीय है, जिसका अर्थ है कि आप वास्तव में मूल्य 5 (संभावित रूप से एक नियंत्रण चरित्र) के साथ चरित्र प्राप्त करते हैं, उसके बाद एक ही ए। इसके बाद यह लालची है। '(कॉन्स char *, size_t) 'कॉल काम करता है क्योंकि' abcde "' परिवर्तनीय नहीं है' char'। – chris

5

यह अभिव्यक्ति

MyItem{{}} 

स्पष्ट प्रकार रूपांतरण (कार्यात्मक संकेतन) को दर्शाता है।

सी ++ मानक के अनुसार (5.2.3 स्पष्ट प्रकार रूपांतरण (कार्यात्मक अंकन))

  1. इसी तरह, एक सरल प्रकार-विनिर्देशक या typename-विनिर्देशक के बाद ब्रेस्ड-इनिट-लिस्ट निर्दिष्ट प्रकार डायरेक्ट-लिस्ट-प्रारंभिक (8.5.4) निर्दिष्ट ब्रेस्ड-इनिट-सूची, के साथ एक अस्थायी ऑब्जेक्ट बनाता है और इसका मान अस्थायी वस्तु के रूप में है।

कक्षा MyItem रूपांतरण प्रारंभकर्ता-सूची निर्माता

MyItem(std::initializer_list<double> l) { 
    std::cout << "l size " << l.size() << ")" << std::endl; 
} 

कि स्पष्ट प्रकार रूपांतरण के लिए चयन किया जाता है है।वास्तव में यह तो निर्माता एक तत्व

{ {} } 

प्रकार का एक अदिश वस्तु डबल एक रिक्त ब्रेसेस {} साथ प्रारंभ किया जा सकता है के साथ एक प्रारंभकर्ता सूची हो जाता है कॉल

MyItem({{}}); 

के बराबर है।

परिणामस्वरूप अभिव्यक्ति MyItem प्रकार का अस्थायी ऑब्जेक्ट बनाता है जिसे प्रारंभकर्ता सूची द्वारा प्रारंभ किया जाता है जिसमें डबल ब्रेसिज़ के माध्यम से मूल्य-प्रारंभिक प्रकार का एक तत्व होता है।

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