2017-12-25 84 views
5

std::optional इस तारीख के रूप में 8 कंस्ट्रक्टर्स है, (यह भी यहाँ http://en.cppreference.com/w/cpp/utility/optional/optional) नीचे सूचीबद्धबाधा :: के वैकल्पिक अग्रेषण संदर्भ निर्माता

/* (1) */ constexpr optional() noexcept; 
/* (1) */ constexpr optional(std::nullopt_t) noexcept; 

/* (2) */ constexpr optional(const optional& other); 

/* (3) */ constexpr optional(optional&& other) noexcept(/* see below */); 

template < class U > 
/* (4) */ /* EXPLICIT */ optional(const optional<U>& other); 

template < class U > 
/* (5) */ /* EXPLICIT */ optional(optional<U>&& other); 

template< class... Args > 
/* (6) */ constexpr explicit optional(std::in_place_t, Args&&... args); 

template< class U, class... Args > 
/* (7) */ constexpr explicit optional(std::in_place_t, 
             std::initializer_list<U> ilist, 
             Args&&... args); 

template < class U = value_type > 
/* (8) */ /* EXPLICIT */ constexpr optional(U&& value); 

मैं पिछले निर्माता की तरह। यह Type टाइप करने के लिए सीवी-रेफ योग्य संदर्भों से निर्मित होने के लिए std::optional की सहायता करता है। जो सुपर सुविधाजनक है।

इसके अलावा, अंतिम निर्माता भी मदद करता है क्योंकि यह का उपयोग किए बिना std::optional इंस्टेंस को प्रारंभ करने के लिए सूची प्रारंभिकरण का उपयोग करने का एक सुविधाजनक तरीका है। ऐसा इसलिए होता है क्योंकि जब एक घुंघराले ब्रेस संलग्नक को कन्स्ट्रक्टर को पास किया जाता है, तो डिफ़ॉल्ट प्रकार का उपयोग किया जाता है क्योंकि फ़ंक्शन टेम्पलेट {} से कम से कम एक प्रकार को कम नहीं कर सकता है (कम से कम यह मेरी स्थिति की समझ है और मैंने एक साफ चाल उठाई है हाल ही में) (यह भी ध्यान दें कि यह केवल अंतर्निहित प्रकार के गैर स्पष्ट कंस्ट्रक्टर्स कॉल करने के लिए, यहां इस्तेमाल किया जा सकता है कि नियमों के अनुसार http://en.cppreference.com/w/cpp/language/list_initialization)

auto optional = std::optional<std::vector<int>>{{1, 2, 3, 4}}; 

कि मैं

समझ सकते हैं पिछले निर्माता पर दो की कमी कर रहे हैं
  • std::decay_t<U> न तो std::in_place_t है और न ही std::optional<T>
  • यह निर्माता स्पष्ट है यदि और केवल यदि std::is_convertible_v<U&&, T> गलत है

पहले समझने में आसान है, यह कंस्ट्रक्टर्स साथ अस्पष्टता के खिलाफ रोकने में मदद करता है (2), (3), (4), (5), (6) और (7)। यदि प्रकार है तो यह (6) और (7) के साथ संघर्ष कर सकता है। यदि प्रकार std::optional का तत्काल है तो यह (2), (3), (4) और (5) के साथ संघर्ष कर सकता है।

दूसरी बस "आगे" optional प्रकार

लेकिन तीसरे प्रतिबंध करने के लिए अंतर्निहित प्रकार के निर्माता की मुखरता

  • यह निर्माता अधिभार संकल्प में भाग नहीं लेता, जब तक std::is_constructible_v<T, U&&> है उत्सुक है सच

इसकी आवश्यकता क्यों है? (8) खाली कन्स्ट्रक्टर के साथ कभी भी संघर्ष नहीं कर सकता क्योंकि इसे कम से कम एक तर्क की आवश्यकता है। यही कारण है कि केवल एक ही छोड़ दिया कारण छोड़ देता है - जब std::nullopt पारित कर यह std::nullopt_t के प्रतिकूल हो सकती है, लेकिन यह नहीं होगा nullopt संस्करण कोई बात नहीं क्या सीवी-रेफरी std::nullopt_t के योग्य संस्करण पारित हो जाता है हमेशा एक बेहतर मुकाबला नहीं है क्योंकि (जैसा कि नीचे बताया)

void func(int) { 
    cout << __PRETTY_FUNCTION__ << endl; 
} 

template <typename U> 
void func(U&&) { 
    cout << __PRETTY_FUNCTION__ << endl; 
} 

int main() { 
    auto i = int{1}; 
    func(1); 
    func(i); 
    func(std::move(i)); 
    func(std::as_const(i)); 
    func(std::move(std::as_const(i))); 
} 

अंतिम प्रतिबंध के पीछे क्या कारण है?

क्यों न केवल निर्माता को सामान्य रूप से त्रुटि दें? क्या यह पता लगाने में मदद करने के लिए आवश्यक है कि क्या प्रकार बाद में हार्ड त्रुटि के बिना SFINAE के माध्यम से पारित तर्क के माध्यम से रचनात्मक है?

+1

"* यह इसलिए होता है क्योंकि एक घुंघराले ब्रेस संलग्न तर्क सूची निर्माता को पारित कर दिया है जब, डिफ़ॉल्ट प्रकार क्योंकि समारोह टेम्पलेट से एक प्रकार अनुमान नहीं कर सकते हैं प्रयोग किया जाता है {} (कम से कम की मेरी समझ यह है कि स्थिति और एक साफ चाल है जिसे मैंने हाल ही में उठाया) * "यह सच नहीं है। एक ब्रेट-इनिट-सूची सीधे पारित होने पर एक टेम्पलेट तर्क 'प्रारंभकर्ता_सूची' को कम नहीं कर सकता है। कम से कम, 'startizer_list ' जैसी कुछ स्पष्ट रूप से नहीं किए बिना। –

+0

@ निकोलबोलस ठीक उसी मामले में (जब उपयोगकर्ता प्रारंभकर्ता सूची पास करता है), तो प्रकार डिफ़ॉल्ट प्रकार पर वापस आ जाता है (क्योंकि फ़ंक्शन टेम्पलेट 'प्रारंभकर्ता_सूची' को कम नहीं कर सकता), और उसके बाद घुंघराले ब्रेसिज़ में अभिव्यक्ति मिलान की जाती है अंतर्निहित प्रकार के निर्माता यह देखने के लिए कि कोई मैच है या नहीं। – Curious

+0

... वास्तव में? क्या आपको पता है कि विनिर्देश इस व्यवहार को निर्दिष्ट करता है? ऐसा लगता है कि काउंटर-सहज ज्ञान युक्त है। –

उत्तर

5

झूठ बोलना लक्षण ungood हैं दिखाता है।

मौलिक शब्दावली प्रकार के लिए झूठ बोलना प्लसंगूड है।

एक मौलिक शब्दावली प्रकार के लिए झूठ बोलने वाले लक्षण जो ओवरलोड रिज़ॉल्यूशन में आसानी से हस्तक्षेप कर सकते हैं, डबलप्लसंगूड हैं।

void f(std::optional<int>); 
void f(std::optional<const char*>); 
f({""}); // ambiguous without the constraint 
1

मैं जितनी जल्दी इस का उत्तर मिल गया के रूप में मैं सवाल (यह एक संपादन के रूप में मेरे सवाल के अंतिम भाग में शामिल किया गया है)

पुस्तकालय उपयोगकर्ताओं है कि क्या पता लगाने के लिए सक्षम होने के लिए एक सुविधाजनक तरीका देना चाहता तैनात एसएफआईएनएई स्थितियों में उस कन्स्ट्रक्टर के माध्यम से बाद में हार्ड त्रुटियों के बिना एक वैकल्पिक बनाया जा सकता है। यदि उस बाधा को शामिल नहीं किया गया था तो पुस्तकालयों को लगता है कि वैकल्पिक किसी अन्य प्रकार से बनाया जा सकता है लेकिन बाद में पता चला कि इसका परिणाम एक कठिन त्रुटि में है।

उदाहरण के लिए निम्न उदाहरण एक ऐसी ही समस्या (https://wandbox.org/permlink/XGgWgJcNJ99BBycu)

#include <iostream> 
#include <string> 
#include <vector> 
#include <tuple> 

using std::cout; 
using std::endl; 

class Something { 
public: 
    Something() = default; 
    template <typename U> 
    Something(U&& u) : vec(std::forward<U>(u)) {} 
private: 
    std::vector<int> vec; 
}; 

template <typename U, typename = std::void_t<>> 
class SomethingConstructibleFrom 
    : public std::false_type {}; 
template <typename U> 
class SomethingConstructibleFrom< 
     U, 
     std::void_t<decltype(Something{std::declval<U>()})>> 
    : public std::true_type {}; 

int main() { 
    if constexpr (SomethingConstructibleFrom<std::string>::value) { 
     // this must be constructible because the above returned true 
     // but SURPRISE! 
     auto something = Something{std::string{"qwerty"}}; 
     std::ignore = something; 
    } 
} 
संबंधित मुद्दे