2014-09-18 3 views
13

मान लीजिए मैं इस तरह एक वर्ग है:जब कोई प्रारंभकर्ता_सूची कन्स्ट्रक्टर बाद में जोड़ा जाता है तो ब्रेस-इनिट सिंटैक्स निर्माण निर्माण व्यवहार का उपयोग करेगा?

class Foo 
{ 
public: 
    Foo(int something) {} 
}; 

और मैं इसे इस सिंटैक्स का उपयोग बनाने के लिए: बाद में

Foo f{10}; 

तो मैं एक नया निर्माता जोड़ें:

class Foo 
{ 
public: 
    Foo(int something) {} 
    Foo(std::initializer_list<int>) {} 
}; 

क्या करने के लिए होता f का निर्माण? मेरी समझ यह है कि यह अब पहले कन्स्ट्रक्टर को कॉल नहीं करेगा बल्कि इसके बजाय अब init सूची कन्स्ट्रक्टर को कॉल करें। यदि ऐसा है, तो यह बुरा लगता है।पर () पर ऑब्जेक्ट निर्माण के लिए शुरुआतीकरण_सूची कन्स्ट्रक्टर जोड़ने के बाद इतने सारे लोग चुपचाप चीजों को तोड़ सकते हैं?

मैं एक ऐसे मामले की कल्पना कर सकता हूं जहां मैं {} सिंटैक्स (अधिकतर परेशानी पार्स से बचने के लिए) का उपयोग करके एक रावल्यू का निर्माण कर रहा हूं लेकिन बाद में कोई उस ऑब्जेक्ट में std::initializer_list कन्स्ट्रक्टर जोड़ता है। अब कोड टूट जाता है और अब मैं इसे एक रावल्यू का उपयोग करके नहीं बना सकता क्योंकि मुझे () सिंटैक्स पर वापस जाना होगा और इससे अधिकतर परेशानी पार्स का कारण बन जाएगा। इस स्थिति को कैसे संभाला जाएगा?

+3

कुछ लोग इस और अन्य कारणों से इसकी अनुशंसा नहीं करते हैं। (बीटीडब्ल्यू, आप सही हैं कि 'intializer_list' ctor को प्राथमिकता दी जाएगी।) – dyp

+0

@dyp लेकिन फिर मुझे आश्चर्य है, क्या बात है? ब्रेस-इनिट सिंटैक्स का उपयोग करने के लिए सबसे अधिक परेशान पार्स और संकुचन रोकथाम बहुत अच्छे कारण हैं। लेकिन अब मुझे एक परेशानी या किसी अन्य को चुनना है? –

+4

बिल्कुल। यह सभी प्रारंभिकरणों के लिए एक वाक्यविन्यास बनाने का प्रयास रहा है, लेकिन प्रारंभिक रूप से किए जाने के कई तरीके होने पर जरूरी है कि इसमें कमी हो सकती है - एक असंबद्धता होनी चाहिए, और शायद यह सही नहीं हो सकता है। – dyp

उत्तर

2

एफ के निर्माण का क्या होता है? मेरी समझ यह है कि यह अब पहले कन्स्ट्रक्टर को कॉल नहीं करेगा बल्कि इसके बजाय अब init सूची कन्स्ट्रक्टर को कॉल करें। यदि ऐसा है, तो यह बुरा लगता है। कन्स्ट्रक्टर जोड़ते समय ऑब्जेक्ट निर्माण के लिए () पर () पर {} सिंटैक्स का उपयोग करने के लिए इतने सारे लोग क्यों अनुशंसा कर रहे हैं?

एक तरफ, प्रारंभकर्ता-सूची निर्माता और दूसरा दोनों व्यवहार्य होना असामान्य है। दूसरी तरफ, "सार्वभौमिक प्रारंभिकरण" को सी ++ 11 मानक रिलीज के आसपास थोड़ा अधिक प्रचार मिला, और इसे बिना किसी सवाल के इस्तेमाल किया जाना चाहिए।

ब्रेसेस समेकित और कंटेनरों के लिए सबसे अच्छा काम करते हैं, इसलिए मैं उन चीज़ों के आस-पास का उपयोग करना पसंद करता हूं जिनके स्वामित्व/निहित होंगे। दूसरी तरफ, ब्रांड्स तर्क के लिए अच्छे हैं जो केवल वर्णन करते हैं कि कुछ नया कैसे उत्पन्न होगा।

मैं एक मामले में जहां मैं {} सिंटैक्स का उपयोग एक rvalue निर्माण कर रहा हूँ कल्पना कर सकते हैं (सबसे अप्रिय पार्स से बचने के लिए), लेकिन फिर बाद में किसी को उस वस्तु के लिए एक std :: initializer_list निर्माता कहते हैं। अब कोड टूट जाता है और अब मैं इसे एक रावल्यू का उपयोग करके नहीं बना सकता क्योंकि मुझे वापस() वाक्यविन्यास पर स्विच करना होगा और इससे अधिकतर परेशानी पार्स का कारण बन जाएगा। इस स्थिति को कैसे संभाला जाएगा?

एमवीपी केवल एक declarator और एक अभिव्यक्ति के बीच अस्पष्टता के साथ होता है, और कहा कि केवल सभी कंस्ट्रक्टर्स आप कॉल करने के लिए डिफ़ॉल्ट निर्माता ये हैं कोशिश कर रहे हैं, तब तक होता है। एक खाली सूची {} हमेशा डिफ़ॉल्ट कन्स्ट्रक्टर को कॉल करती है, न कि एक खाली सूची के साथ प्रारंभकर्ता-सूची निर्माता। (इसका मतलब यह है कि यह खतरे में डाले बिना इस्तेमाल किया जा सकता। "यूनिवर्सल" मूल्य आरंभीकरण एक असली बात है।)

ब्रेसिज़/कोष्ठक के अंदर किसी भी उपसूचक होती है, तो एमवीपी समस्या पहले से ही हल किया जाता है।

0

अद्यतन कोड में प्रारंभकर्ता सूचियों के साथ कक्षाओं को पुन: स्थापित करना ऐसा कुछ है जो ऐसा लगता है कि ऐसा होना आम बात होगी। इसलिए लोग कक्षा के अपडेट होने से पहले मौजूदा रचनाकारों के लिए {} वाक्यविन्यास का उपयोग शुरू करते हैं, और हम स्वचालित रूप से किसी भी पुराने उपयोग को पकड़ना चाहते हैं, विशेष रूप से उन टेम्पलेट्स में उपयोग किए जाते हैं जहां उन्हें अनदेखा किया जा सकता है।

यदि मेरे पास वेक्टर जैसे वर्ग थे, जो आकार लेते थे, तो तर्कसंगत रूप से {} वाक्यविन्यास का उपयोग करके "गलत" होता है, लेकिन संक्रमण के लिए हम वैसे भी इसे पकड़ना चाहते हैं। C c1 {val} का निर्माण करना संग्रह के लिए कुछ (एक, इस मामले में) मान लेना है, और C c2 (arg) का मतलब कक्षा के लिए मेटाडेटा के वर्णनात्मक टुकड़े के रूप में वैल का उपयोग करना है।

दोनों उपयोगों का समर्थन करने के लिए, जब तत्व का प्रकार वर्णनात्मक तर्क के साथ संगत होता है, तो C c2 {arg} का उपयोग करने वाला कोड अर्थ बदल जाएगा। ऐसा लगता है कि अगर हम अलग-अलग अर्थों के साथ दोनों रूपों का समर्थन करना चाहते हैं तो उस मामले में इसके आसपास कोई रास्ता नहीं है।

तो मैं क्या करूँगा? यदि संकलक को कोई चेतावनी जारी करने का कोई तरीका प्रदान करता है, तो मैं एक तर्क के साथ प्रारंभकर्ता सूची को चेतावनी देता हूं। यह मुश्किल लगता है कि संकलक विशिष्ट का उल्लेख न करें, इसलिए मैं इसके लिए एक सामान्य टेम्पलेट बनाउंगा, अगर यह बूस्ट में पहले से नहीं है, और इसके उपयोग को बढ़ावा देता है।

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

प्रारंभकर्ताइज़र सूची सुविधाओं के साथ एक गैर-कंटेनर को बढ़ाया जा रहा है, तो यह विशेष रूप से एक-तर्क निर्माता को डिजाइन करने से बचने के लिए पर्याप्त हो सकता है जिसे गलत किया जा सकता है। इसलिए, एक-तर्क कन्स्ट्रक्टर को अद्यतन कक्षा में हटा दिया जाएगा, या प्रारंभकर्ता सूची को पहले (संभावित रूप से टैग) तर्कों की आवश्यकता होगी। यही है, कोड समीक्षा पर पाई-इन-फेस के दंड के तहत ऐसा न करें।

कंटेनर जैसी कक्षाओं के लिए भी, एक कक्षा जो मानक पुस्तकालय वर्ग नहीं है, यह लागू कर सकती है कि एक-तर्क कन्स्ट्रक्टर फॉर्म अब उपलब्ध नहीं है। जैसे C c3 (size); को C c3 (size, C()); के रूप में लिखा जाना होगा या एक गणना तर्क भी लेने के लिए डिज़ाइन किया जाना चाहिए, जो कि एक मान बनाम आरक्षित आकार में प्रारंभ करने के लिए आसान है, ताकि आप तर्क दे सकें कि यह एक सुविधा है और आरक्षित करने के लिए एक अलग कॉल के साथ शुरू होने वाला कोड इंगित करता है । तो फिर, ऐसा न करें अगर मैं उचित रूप से इससे बच सकता हूं।

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