2017-10-14 21 views
7

मेरे पास कक्षा C है जिसमें किसी भी चीज़ का कास्टिंग ऑपरेटर है। उदाहरण में मैंने std::string पर तीन अलग-अलग तरीकों से इसका उदाहरण डालने की कोशिश की: static_cast, std::string का कन्स्ट्रक्टर और std::string को असाइन करना। हालांकि, केवल अंतिम एक संकलन करता है, जबकि अन्य संदिग्ध कन्स्ट्रक्टर की त्रुटि उठाते हैं।स्पष्ट कलाकारों, प्रत्यक्ष प्रारंभिकरण और प्रति प्रारंभिकरण के बीच अलग-अलग व्यवहार

त्रुटि का कारण पर्याप्त स्पष्ट है: C को std::string के निर्माता को स्वीकार करने के कई तरीके हैं। लेकिन इन मामलों के बीच क्या अंतर है? क्यों कास्ट ऑपरेटर यहां इरादे के रूप में काम करता है लेकिन वहां नहीं?

struct C { 
    template<typename T> 
    operator T() const { 
     return T{}; 
    } 
}; 

int main() { 
    C c; 

    cout << static_cast<string>(c) << endl; // compile error 
    string bad(c); // compile error 
    string ok = c; // compiles successfully 
} 

युपीडी: टिप्पणी में उल्लेख किया bolov के रूप में, इस मुद्दे के साथ सी ++ 17 पुन: पेश नहीं करता है। मैंने इसे g ++ - 5 और clang-3.8 के साथ -std = C++ 11 और -std = C++ 14 के साथ परीक्षण किया, और यह वर्णित त्रुटियों को दिखाता है।

+0

पुन: पेश नहीं कर सकते: https://godbolt.org/g/ESR8cw – bolov

+0

@bolov अजीब पर्याप्त है, लेकिन यह सी ++ 17 में पुन: पेश नहीं करता है। यह godbolt पर -std = C++ 11 के साथ पुनरुत्पादित करता है। मैं इसे पोस्ट में जोड़ दूंगा, धन्यवाद। –

+0

हम्म .. दिलचस्प – bolov

उत्तर

6

सी ++ 17

static_cast<string>(c) और string bad(c) प्रदर्शन direct initialization, तो

पहले T की कंस्ट्रक्टर्स जांच की जाती है और सबसे अच्छा मैच अधिभार संकल्प द्वारा चुना जाता है। तब कन्स्ट्रक्टर को ऑब्जेक्ट को प्रारंभ करने के लिए बुलाया जाता है।

जैसा कि आपने कहा, सभी std::string के संभावित कंस्ट्रक्टर्स जांच की जाती है और C आवश्यक कुछ भी करने के लिए परिवर्तित किया जा सकता है, तो अस्पष्टता का कारण बनता है।

string ok = c करता copy initialization (ध्यान दें यह काम नहीं है), तो

तो T एक वर्ग प्रकार है, और other के प्रकार के सीवी-अयोग्य संस्करण T नहीं है या T से ली गई है, या यदि T गैर-वर्ग प्रकार है, लेकिन other का प्रकार एक वर्ग प्रकार, उपयोगकर्ता परिभाषित रूपांतरण अनुक्रम है जो other से T (या T से व्युत्पन्न एक प्रकार से परिवर्तित हो सकता है यदि T एक वर्ग प्रकार है और एक रूपांतरण फ़ंक्शन है उपलब्ध) की जांच की जाती है और सबसे अच्छा अधिभार संकल्प के माध्यम से चुना जाता है।

std::string करने के लिए C से रूपांतरण इसका मतलब है कि जांच की, और प्रारंभ यहाँ के लिए इस्तेमाल किया जाता है।

के बाद सी ++ 17

सी के बाद से ++ direct initlizatioin के लिए 17,

अगर प्रारंभकर्ता एक prvalue अभिव्यक्ति जिसका सीवी-अयोग्य प्रकार T के रूप में एक ही कक्षा में है, प्रारंभकर्ता अभिव्यक्ति स्वयं, इसके बजाय एक अस्थायी भौतिककृत, गंतव्य ऑब्जेक्ट को आरंभ करने के लिए उपयोग किया जाता है: copy elision देखें (सी ++ 17)

इसका मतलब है कि std::string करने के लिए C से रूपांतरण perferred और आरंभीकरण के लिए प्रयोग किया जाता है, तो अस्पष्टता गायब हो जाता है और कोड अच्छी तरह से काम करता है।

LIVE

+1

प्रतिलिपि प्रारंभ पर विस्तार करने के लिए ([over.ics.user]/3): * उपयोगकर्ता परिभाषित रूपांतरण एक रूपांतरण समारोह टेम्पलेट की एक विशेषज्ञता द्वारा निर्दिष्ट किया जाता है, तो दूसरा मानक रूपांतरण अनुक्रम सटीक मिलान रैंक होगा *। मैं नहीं कहूंगा कि इसे जितना आवश्यक हो उतना पसंद किया जाता है। – chris

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