2012-10-15 21 views
7

भिन्न हैं मैंने इस बारे में SO पर अन्य प्रश्नों को देखा है, लेकिन कोई भी जो इसे पूरी तरह से समझाता है। सही कंपेलरों के लिए नीचे दी गई दो स्थितियों को संभालने के तरीके क्या हैं? मैं जीसीसी 4.7.1 (साथ -std = C++ 0x), VS2010 और VS2012 के साथ यह कोशिश की है एक सब पर अलग अलग परिणाम प्राप्त:रूपांतरण ऑपरेटर अतिसंवेदनशीलता अधिभार, कंपाइलर

उदाहरण 1:

struct BB 
{ 
// generic cast 
template<typename T> 
operator T() const 
{ 
    return 0; 
} 

// string cast 
operator std::string() const 
{ 
    return string("hello"); 
} 
}; 

int main() 
{ 
    BB b; 
    string s = b; 
} 

आउटपुट:

  • जीसीसी 4.7.1: ठीक है
  • VS2010: ठीक है
  • VS2012: विफल: " स्ट्रिंग के लिए बी बी से कनवर्ट नहीं कर सकता"

उदाहरण 2:

struct BB 
{ 
// generic cast 
template<typename T> 
operator T() const 
{ 
    return 0; 
} 

// string cast 
operator std::string() const 
{ 
    return string("hello"); 
} 
}; 

int main() 
{ 
    BB b; 
    string s = (string)b; 

आउटपुट:

  • जीसीसी 4.7.1: विफल: (बी बी &) अतिभारित स्ट्रिंग की कॉल ambigious
  • VS2010 है: ठीक है
  • वीएस2012: विफल: "बीबी से स्ट्रिंग में कनवर्ट नहीं किया जा सकता"

उत्तर

4

सी-स्टाइल कास्ट के साथ आपका दूसरा संस्करण संदिग्ध है। समस्या यह है कि static_cast<std::string> दो तरीके हैं जो एक स्ट्रिंग में कक्षा BB के उदाहरण को परिवर्तित कर सकते हैं। स्पष्ट पथ सीधे एक स्ट्रिंग में कनवर्ट करने के लिए अपने गैर-टेम्पलेट std :: स्ट्रिंग कास्ट ऑपरेटर का उपयोग करके है। एक और अधिक भयावह रास्ता है, और वीएस -2010 के अलावा सभी ने इसे पाया है। यह अन्य पथ एक स्ट्रिंग के लिए आवंटक में BB को कनवर्ट करने के लिए अपने टेम्पलेट कास्ट ऑपरेटर का उपयोग करना है और फिर इस आवंटक का उपयोग करके खाली स्ट्रिंग का निर्माण करना है।

टेम्पलेट कास्ट ऑपरेटर संभावित रूप से खतरनाक जानवर हैं। आपने संकलक को BB से को में कनवर्ट करने के लिए टूल दिए हैं।

आपका पहला संस्करण इस समस्या से बच निकला क्योंकि std::basic_string(const _Alloc& __a) एक स्पष्ट निर्माता है। स्पष्ट रचनाकारों का स्पष्ट रूपांतरणों द्वारा उपयोग किया जा सकता है लेकिन निहित लोगों द्वारा नहीं। यह कन्स्ट्रक्टर प्लस एक आवंटक में रूपांतरण है जो अस्पष्टता बनाता है, और इस पथ का उपयोग एक अंतर्निहित रूपांतरण के साथ नहीं किया जा सकता है।

क्यों VS1012 निहित रूपांतरण पर विफल रहता है, यह VS2012 में एक बग हो सकता है, या यह हो सकता है कि सी ++ 11 एक BB से एक std::string को पाने के लिए और भी अधिक अवसर पैदा करता है। मैं एक सी ++ 11 विशेषज्ञ नहीं हूँ। मैं भी एक नौसिखिया नहीं हूँ।

एक और आइटम: अपने कोड और भी अधिक बुरी तरह विफल रही है | आप टेम्पलेट रूपांतरण ऑपरेटर के साथ संयोजन के रूप में असाइनमेंट ऑपरेटर b से s को पाने के लिए और अधिक तरीके बनाता

std::string s; 
s = b; 

इस्तेमाल किया था। क्या सिस्टम b को std::string पर char, या char* में परिवर्तित करना चाहिए?

नीचे पंक्ति: आपको वास्तव में टेम्पलेट रूपांतरण ऑपरेटरों के उपयोग पर पुनर्विचार करना चाहिए।

+0

मैं सामान्य रूपांतरण का उपयोग करता हूं क्योंकि मैं कुछ समान रूप से बढ़ावा देता हूं :: किसी भी, लेकिन शायद एक बेहतर तरीका है। इसे उत्तर के रूप में चिह्नित किया जाएगा mksvetkov काफी समान था – Rolle

2

कारण कुछ संकलकों के तहत विफल रहता है क्योंकि वे यह जानने के लिए अलग-अलग लंबाई में जाते हैं कि आप क्या कर रहे हैं। अपराधी टेम्पलेट ऑपरेटर कॉल है।

this SO question बताते हैं, टेम्प्लेट की गई ऑपरेटरों को स्पष्ट रूप से कहा जा (b.operator()<std::string> अगर आप template<typename T> operator(); फोन करना चाहता था), लेकिन, वहाँ कोई तरीका है अपने टेम्प्लेटेड ऑपरेटर कॉल करने के लिए है:

b.operator std::string()<std::string>; //invalid 
b.operator std::string <std::string>(); //also invalid, string takes no template arguments 
// a bunch more weird syntax constructions... 

मुद्दा इस तथ्य से आता कि operator के बाद नाम टेम्पलेट तर्क पर निर्भर करता है, इसलिए इसे निर्दिष्ट करने का कोई तरीका नहीं है। जीसीसी और वीएस2012 ने यह पता लगाया कि आप क्या कर रहे थे और देखा कि वे टेम्पलेट या स्पष्ट रूप से परिभाषित एक => संदिग्ध कॉल में रूपांतरण को फिट कर सकते हैं। वीएस -2010 ने ऐसा नहीं किया और उनमें से एक को बुला रहा है, आप डिबगिंग के माध्यम से कौन सा पता लगा सकते हैं।

खाका विशेषज्ञता इस तरह के मामले में मदद की है हो सकता है, तथापि,

// string cast 
template<> 
operator std::string() const 
{ 
    return string("hello"); 
} 

असफल हो जायेगी परिभाषित करने के लिए, के बाद से संकलक कि समारोह और एक नियमित रूप से एक के बीच अंतर के बिना template<> नहीं बता सकता की कोशिश कर रहा । अगर प्रोटोटाइप में कुछ तर्क थे तो यह काम करेगा, लेकिन operator typename में कोई है ...

लंबी कहानी छोटी - टेम्पलेटेड रूपांतरण ऑपरेटरों से बचें।

+0

मुझे अभी भी उदाहरण 1 और 2 से अंतर दिखाई नहीं देता है। दोनों मामलों में स्ट्रिंग को एक कास्ट किया जाना चाहिए, सही, स्ट्रिंग असाइनमेंट ऑपरेटर के पास बीबी जानने का कोई तरीका नहीं है? इसके अलावा, केवल gcc उदाहरणों का इलाज अलग-अलग – Rolle

+0

पहले मामले में ('b.operator std :: string() ;') आप फ़ंक्शन 'टेम्पलेट ऑपरेटर std :: string(); को कॉल करने का प्रयास कर रहे हैं; ' तर्क 'std :: string' के साथ और दूसरे मामले में आप' ऑपरेटर std :: string () 'को कॉल करने का प्रयास कर रहे हैं, लेकिन std :: string टेम्पलेट तर्क नहीं लेता है। – mtsvetkov

+1

@mtsvetkov - यह अंतर का कारण नहीं है। अंतर यह है कि स्पष्ट रूपांतरण कन्स्ट्रक्टर अंतर्निहित रूपांतरणों के लिए ऑफ-सीमा हैं। पहला उदाहरण एक अंतर्निहित रूपांतरण है, दूसरा, स्पष्ट। –

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