सामान्य कोड (यानी टेम्प्लेट) के बाहर, आप (और मैं करते हैं) हर जगह ब्रेसिज़ का उपयोग कर सकते हैं । एक फायदा यह है कि यह हर जगह काम करता है, उदाहरण के लिए इन-क्लास इनिशियलाइज़ेशन के लिए भी:
struct foo {
// Ok
std::string a = { "foo" };
// Also ok
std::string b { "bar" };
// Not possible
std::string c("qux");
// For completeness this is possible
std::string d = "baz";
};
या फ़ंक्शन तर्क के लिए:
void foo(std::pair<int, double*>);
foo({ 42, nullptr });
// Not possible with parentheses without spelling out the type:
foo(std::pair<int, double*>(42, nullptr));
चरों के लिए मैं T t = { init };
या T t { init };
शैलियों के बीच ज्यादा ध्यान नहीं देता , मुझे अंतर मामूली लगता है और एक explicit
कंस्ट्रक्टर के दुरुपयोग के बारे में एक सहायक संकलक संदेश में सबसे खराब परिणाम देगा ।
ऐसे प्रकारों के लिए जो स्वीकार करते हैं, std::initializer_list
हालांकि स्पष्ट रूप से कभी-कभी गैर- std::initializer_list
कंस्ट्रक्टरों की आवश्यकता होती है (शास्त्रीय उदाहरण std::vector<int> twenty_answers(20, 42);
)। इसके बाद ब्रेसिज़ का उपयोग नहीं करना ठीक है।
जब जेनेरिक कोड (यानी टेम्प्लेट) की बात आती है, तो बहुत अंतिम पैराग्राफ में कुछ चेतावनियां उठानी चाहिए थीं। निम्नलिखित को धयान मे रखते हुए:
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{ return std::unique_ptr<T> { new T { std::forward<Args>(args)... } }; }
फिर auto p = make_unique<std::vector<T>>(20, T {});
आकार 2 का एक वेक्टर बनाता है, तो T
उदाहरण के लिए है int
, या आकार 20 का एक वेक्टर अगर T
है std::string
। एक बहुत बड़ा संकेत यह है कि यहाँ बहुत कुछ गलत हो रहा है, ऐसा नहीं है लक्षण है जो आपको यहाँ बचा सकता है (जैसे कि SFINAE के साथ): std::is_constructible
प्रत्यक्ष-आरंभीकरण के संदर्भ में है, जबकि हम ब्रेस-इनिशियलाइज़ेशन का उपयोग कर रहे हैं, जो डायरेक्ट करने के लिए ख़राब है। इनिशियलाइज़ेशन इफ एंड इफ तभी है जब कोई कंस्ट्रक्टर std::initializer_list
हस्तक्षेप नहीं कर रहा है। उसी प्रकारstd::is_convertible
कोई मदद नहीं करता है।
मैंने जांच की है कि क्या वास्तव में एक विशेषता को हाथ से रोल करना संभव है जो इसे ठीक कर सकता है लेकिन मैं इसके बारे में अधिक आशावादी नहीं हूं। किसी भी मामले में मुझे नहीं लगता कि हम बहुत याद कर रहे हैं, मुझे लगता है कि तथ्य यह है किmake_unique<T>(foo, bar)
एक निर्माण के बराबर में परिणाम T(foo, bar)
बहुत सहज है; विशेष रूप से दिया गया है कि make_unique<T>({ foo, bar })
काफी भिन्न है और केवल अगर foo
और समझ में आता हैbar
एक ही प्रकार है।
इसलिए जेनेरिक कोड के लिए मैं केवल वैल्यू इनिशियलाइज़ेशन (जैसे T t {};
या T t = {};
) के लिए ब्रेसिज़ का उपयोग करता हूं , जो बहुत सुविधाजनक है और मुझे लगता है कि C ++ की तरह बेहतर हैT t = T();
। अन्यथा यह प्रत्यक्ष आरंभीकरण सिंटैक्स (यानी T t(a0, a1, a2);
), या कभी-कभी डिफ़ॉल्ट निर्माण है (T t; stream >> t;
केवल मामला है जहां मैं उपयोग करता हूं कि मुझे लगता है)।
इसका मतलब यह नहीं है कि सभी ब्रेसिज़ खराब हैं, हालांकि पिछले उदाहरण को फिक्स के साथ देखें:
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{ return std::unique_ptr<T> { new T(std::forward<Args>(args)...) }; }
यह अभी भी निर्माण के लिए ब्रेसिज़ का उपयोग करता है std::unique_ptr<T>
, भले ही वास्तविक प्रकार टेम्पलेट पैरामीटर पर निर्भर करता है T
।