2016-08-30 9 views
10

में तीन रचनाकारों के बारे में प्रश्न http://en.cppreference.com/w/cpp/utility/variant/variant से std::variant के लिए कन्स्ट्रक्टर (4) क्यों मौजूद है? ऐसा लगता है कि यह कोड में बहुत अस्पष्टता का कारण बन रहा है जो अन्यथा स्पष्ट होने से बचा जा सकता है .. उदाहरण के लिए cppreference पर कोड नमूना संभावित अस्पष्टता को हाइलाइट करता है जो उपयोगकर्ता नोटिस नहीं कर सकते हैं (तीसरी पंक्ति)std :: variant के प्रस्तावित इंटरफ़ेस

variant<string> v("abc"); // OK 
variant<string, string> w("abc"); // ill-formed, can't select the alternative to convert to 
variant<string, bool> w("abc"); // OK, but chooses bool 

क्या ऐसा कोई मामला है जहां इसकी पूरी आवश्यकता हो रही है?

दूसरा प्रश्न यह था कि क्यों एक ही cppreference पृष्ठ से रचनाकार (6) और (8) की आवश्यकता होती है। नहीं (5) और (7) उन प्रयोजनों को पूरा करेंगे जो (6) और (8) के लिए हैं? मैं उनके उपयोग गलतफहमी हो सकता है ..


पाठक के लिए निर्माताओं है कि मैं अपने सवाल में कहा जाता है

constexpr variant();    // (1) (since C++17) 

variant(const variant& other); // (2) (since C++17) 

variant(variant&& other);   // (3) (since C++17) 

template< class T >    // (4) (since C++17) 
constexpr variant(T&& t); 

template< class T, class... Args > 
constexpr explicit variant(std::in_place_type_t<T>, Args&&... args); // (5) (since C++17) 

template< class T, class U, class... Args > 
constexpr explicit variant(std::in_place_type_t<T>, 
          std::initializer_list<U> il, Args&&... args); // (6) (since C++17) 

template< std::size_t I, class... Args > 
constexpr explicit variant(std::in_place_index_t<I>, Args&&... args) // (7) (since C++17) 

template <size_t I, class U, class... Args> 
constexpr explicit variant(std::in_place_index_t<I>, 
          std::initializer_list<U> il, Args&&... args); // (8) (since C++17) 
+0

ठीक है, क्या आप वास्तव में 'in_place ' कन्स्ट्रक्टर * का उपयोग करना चाहते हैं * हर बार जब आप बाध्य प्रकारों में से एक के साथ एक संस्करण शुरू करते हैं? – Brian

+1

प्रारंभकर्ता_सूची रचनाकारों के लिए, मुझे पूरा यकीन है कि यदि आप कभी भी एक प्रारंभिकज़र_सूची ऑब्जेक्ट बनाने के बजाय सीधे ब्रेसिड-इनिट-सूची पास करना चाहते हैं, तो उसे आवश्यक है। – Brian

+0

@Brian व्यक्तिगत रूप से, ऐसा लगता है यह इंटरफ़ेस मुझे लगता है कि एक संस्करण बनाने के बारे में जाने का सबसे अच्छा तरीका है। क्योंकि (4) कई बार संदिग्ध हो सकता है ... – Curious

उत्तर

9

वहाँ कुछ मामले में जहां यह बिल्कुल जरूरत होने जा रही है है?

नहीं, लेकिन चीजें शामिल नहीं होती हैं क्योंकि वे "पूरी तरह से जरूरी होने जा रहे हैं"। वे जोड़े गए क्योंकि वे उपयोगी हैं।

और इसके घटक प्रकारों में से एक से स्पष्ट रूप से परिवर्तनीय होने के कारण variant के लिए बहुत उपयोगी है। हां, यह कुछ कोने मामलों में अस्पष्टता पैदा करता है। लेकिन यह अस्पष्टता आमतौर पर प्रकार के डिज़ाइन में दोषों के कारण होती है (जैसे उपयोगकर्ता परिभाषित रूपांतरणों पर bool में परिवर्तित करने के लिए स्ट्रिंग अक्षर का चयन करना)।

यदि कोई संदिग्ध मामला है, तो आपको बस इसके बारे में स्पष्ट होना होगा। नग्न स्ट्रिंग अक्षर के बजाय "abc"s यूडीएल अक्षरों का उपयोग करने की तरह (अभी तक ऐसा करने का एक अन्य कारण)। लेकिन बल कोई भी कारण नहीं है जब आप अच्छी तरह से डिज़ाइन किए गए प्रकार से निपट रहे हों।

नहीं (5) और (7) प्रयोजनों को पूरा करेगा (6) और (8) के लिए हैं?

उचित तरीके से नहीं।

मानक, जब एक समारोह variadic तर्क है कि एक निर्माता को दे दिया जाएगा लेता में हर मामले में, वे निर्माता वाक्य रचना बजाय उस वस्तु पर {} सिंटैक्स का उपयोग होगा। तो यदि आपके पास यह है:

using type = vector<int>; 
variant<type> t(in_place<type>, 6); 

आपको vector<int>(6) पर कॉल प्राप्त होगा। ध्यान दें कि यह vector<int>{6} से अलग है। यही है, जब तक कि आप वास्तव में प्रारंभकर्ता सूची पास नहीं करते हैं, तब तक आपको प्रारंभकर्ता सूची निर्माता नहीं मिलते हैं।

अब, आप कर सकता है:

variant<type> t(in_place<type>, initializer_list<int>{6}); 

लेकिन वह जरूरत से ज्यादा वर्बोज़ है। इसके विपरीत:

variant<type> t(in_place<type>, {6}); 

यह बहुत कम वर्बोज़ है। कंपाइलर प्रारंभकर्ता सूची के प्रकार को कम कर सकता है।जबकि टेम्पलेट तर्क प्रकार कटौती विफल हो जाती है यदि आप braced-init-list को मनमाने ढंग से T के रूप में कम करने का प्रयास करते हैं।

अन्य तरीकों के अलावा टेम्पलेट कटौती auto के साथ कटौती से अलग है क्योंकि यहसे braced-init-list अभिव्यक्तियों को घटाता नहीं है। उदाहरण

लिए
template <typename Type> 
void func(const Type&); 

Type अनुमान नहीं होगा निम्नलिखित कॉल

func({1, 2, 3, 4, 5}); 

अधिक जानकारी के लिए इस बारे में देखें Universal references and std::initializer_list देखने के लिए एक std::initializer_list किया जाना है।

+0

जब आप 'ब्रेसिड-इनिट-लिस्ट' को मनमाने ढंग से 'टी' के रूप में कोशिश करते हैं और कटौती करते हैं तो कटौती विफल क्यों होती है? मैंने सोचा कि इसे 'startizer_list' में डिफ़ॉल्ट होना चाहिए? मैं यह इसलिए कहता हूं क्योंकि 'ब्रेसिड-इनिट-लिस्ट' के साथ 'ऑटो' एक 'प्रारंभकर्ता_सूची' – Curious

+0

@ क्रूर के लिए डिफ़ॉल्ट है, यह एक अलग सवाल है, और अलग से पूछा जाना चाहिए। मैं खुद जवाब भी जानना चाहता हूं। – Brian

+0

@ ब्रायन अब पोस्टिंग। जैसे ही मैं कर चुका हूं, मैं आपको इसे लिंक कर दूंगा – Curious

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