सामान्य कोड (यानी टेम्प्लेट) के बाहर, आप (और मैं करते हैं) हर जगह ब्रेसिज़ का उपयोग कर सकते हैं । एक फायदा यह है कि यह हर जगह काम करता है, उदाहरण के लिए इन-क्लास इनिशियलाइज़ेशन के लिए भी:
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।