2013-04-02 8 views
5

मैं एक एसटीएल कंटेनर को सुंदर प्रिंट करने की कोशिश कर रहा हूं। मैं जो कोशिश कर रहा हूं वह एक डिलीमीटर से अलग कंटेनर के elemets मुद्रित करने के लिए है। हालांकि मैं कुछ समस्याओं में आया हूं।टेम्पलेट ओवरलोडिंग ओस्ट्रीम ऑपरेटर

1. जी ++ बनाम कुलपति ++

ostream& operator<<(ostream& o, const vector<string>& v) { 
    copy(v.begin(), v.end(), std::ostream_iterator<string>(o,",")); 
} 

int main() 
{ 

    vector<string> s_v; 
    s_v.push_back("one"); 
    s_v.push_back("two"); 

    cout << s_v; 

} 

जी ++ (mingw32 पर जीसीसी संस्करण 4.4.0) संकलन कर सकते हैं यह एक ठीक काम करता है। वीसी ++ (विजुअल स्टूडियो 9) इस कोड को संकलित नहीं कर सकता है।

error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'const std::string' (or there is no acceptable conversion) 
1>  c:\program files (x86)\microsoft visual studio 9.0\vc\include\ostream(653): could be 'std::basic_ostream<_Elem,_Traits> &std::operator <<<char,std::char_traits<char>>(std::basic_ostream<_Elem,_Traits> &,const char *)' 
1>  with 
1>  [ 

यह क्यों है? क्या यह कोड अवैध है? या यह सिर्फ वीसी ++ बीसीएन वीसी ++ है?


2. अप्रयुक्त टेम्पलेट चर टूटता संकलन।

अगर अब मैं एक टेम्पलेट इस तरह ostream करने के लिए (यह नहीं किया जाता है तो बस वहाँ बैठे,) जोड़ने

template <typename T> // <----- Here 
ostream& operator<<(ostream& o, const vector<string>& v) { 
    copy(v.begin(), v.end(), std::ostream_iterator<string>(o,",")); 
} 

int main() 
{ 

    vector<string> s_v; 
    s_v.push_back("one"); 
    s_v.push_back("two"); 

    cout << s_v; 

} 

जीसीसी अब और ऑपरेटर से मेल नहीं कर सकते हैं।

error: no match for 'operator<<' in 'std::cout << s_v' 

and a lot more candidates... 

क्यों? टेम्पलेट अप्रयुक्त है। क्या इससे कोई फर्क पड़ता है?


संपादित करें: यह समाधान हो जाता है। मुझे ओ वापस करना पड़ा;

3. प्रयुक्त टेम्पलेट

template <typename T> 
ostream& operator<<(ostream& o, const vector<T>& v) { 
    copy(v.begin(), v.end(), std::ostream_iterator<T>(o,",")); 

    return o; // Edited 
} 

int main() 
{ 

    vector<string> s_v; 
    s_v.push_back("one"); 
    s_v.push_back("two"); 

    vector<int> i_v; 
    i_v.push_back(1); 
    i_v.push_back(2); 

    cout << s_v; 
    cout << i_v; 
} 

मैं टेम्पलेट प्रकार का उपयोग पता है। g ++ इसे संकलित कर सकता है लेकिन फिर अपवाद के साथ समाप्त हो जाता है।

terminate called after throwing an instance of 'std::bad_cast' 
    what(): std::bad_cast 

कुलपति ++ बस बैठे और जीसीसी यह सब करने के देख रहा है। उनमें से किसी को संकलित नहीं करता है।

क्या कोई मेरे लिए इस चीज को स्पष्ट कर सकता है? धन्यवाद।

+0

अपने ऑपरेटर को std namespace में परिभाषित करें। आप – PiotrNycz

+0

अंतर देखेंगे यदि संकलक टेम्पलेट तर्क के प्रकार का अनुमान नहीं लगा सकता है, तो आपको इसे स्वयं प्रदान करना होगा। तो यदि आपके पास 'टेम्पलेट शून्य Foo() {...}' है, तो आपको 'Foo () 'का उपयोग करने की आवश्यकता है। जाहिर है, जब आप ऑपरेटर को अधिभारित करते हैं तो आप ऐसा नहीं कर सकते हैं। जब आप 't' का उपयोग करते हैं, तो कंपाइलर इसके प्रकार का अनुमान लगाने में सक्षम होता है, और यही कारण है कि यह काम करता है। – zneak

+0

इसके अलावा, आपका अंतिम उदाहरण [ठीक चलाता है] (http://ideone.com/mLJcTI) विचारधारा पर। आप अपने 'ऑपरेटर <<' हालांकि 'वापसी ओ;' जोड़ना चाहेंगे। यदि आपने 'cout << s_v << i_v' किया है तो यह संभवतः आपके प्रोग्राम को क्रैश करेगा। – zneak

उत्तर

5

आधार:

सबसे पहले, कोड गैर कानूनी है, क्योंकि यह एक return बयान याद करते हैं (जो की संभावना क्या अपवाद है कि तीसरे संस्करण में उठाया जाता है खड़ी कर रहा है है):

ostream& operator<<(ostream& o, const vector<string>& v) { 
    copy(v.begin(), v.end(), std::ostream_iterator<string>(o,",")); 
    return o; // <== THIS ONE WAS MISSING 
} 

यह आपके प्रोग्राम के लिए अपरिभाषित व्यवहार इंजेक्ट करता है। सी ++ 11 मानक के अनुच्छेद 6.6.3/1, वास्तव में:

[...] किसी फ़ंक्शन के अंत में बहने से कोई मूल्य नहीं होता है; इस परिणाम को मान-वापसी समारोह में अपरिभाषित व्यवहार में परिणाम।

एक बार है कि तय हो गई है, अपने कोड ठीक है, और कहा कि VC9 के साथ भेज दिया है स्टैंडर्ड लाइब्रेरी के कार्यान्वयन शायद एक बग है:

अपने पहले प्रश्न के संबंध में

वास्तव में, संकलक operator << के तर्कों के नामस्थान (std) और नामस्थान में जहां कॉल किया जा रहा है (वैश्विक नामस्थान) में योग्य अधिभार के लिए देखना चाहिए। जब तक आपका ऑपरेटर वैश्विक नामस्थान और में परिभाषित किया गया है, तो cout << s_v वैश्विक नामस्थान में है, ओवरलोड रिज़ॉल्यूशन सफलतापूर्वक आपके अधिभार को चुनना चाहिए।

अपने दूसरे प्रश्न के संबंध में:

क्यों? टेम्पलेट अप्रयुक्त है। क्या इससे कोई फर्क पड़ता है?

कि सरल है: संकलक समारोह तर्क से T बात का अनुमान लगाना है, तो जब तक आप इसे स्पष्ट रूप से निर्दिष्ट है, यह एक संकलन त्रुटि का परिणाम देगा का कोई रास्ता नहीं है।

::operator << <void>(std::cout, s_v); 

सी ++ 11 में आप T के लिए एक डिफ़ॉल्ट तर्क निर्दिष्ट कर सकते हैं, जो समारोह फोन करना होगा: हालांकि, टेम्पलेट तर्क को स्पष्ट रूप से निर्दिष्ट करने निम्नलिखित, जो गैर भावना के करीब है की तरह कुछ करने का मतलब होगा कानूनी, बग फिर, किस उद्देश्य के लिए?

अपने तीसरे प्रश्न के संबंध में:

जब T एक निष्कर्ष निकाला संदर्भ में एक फ़ंक्शन पैरामीटर कम से कम एक के प्रकार में प्रयोग किया जाता है, संकलक (समारोह तर्क से यह अनुमान इस मामले में की अनुमति देगा , यह T = std::string निकालना होगा, और आप इसे स्पष्ट रूप से निर्दिष्ट करने की जरूरत नहीं

निष्कर्ष:।

तो यह योग करने के लिए ऊपर: आवश्यकजोड़ने के बादकथन, आपके प्रोग्राम के पहले और तीसरे संस्करण कानूनी हैं और समझ में हैं, जबकि दूसरा नहीं है और नहीं।

+0

कोड के बारे में उन्होंने वास्तव में पहले प्रश्न के लिए पोस्ट किया: यह किसी भी कंपाइलर के साथ संकलित नहीं होगा, क्योंकि इसमें शामिल हैं। मैंने वीसी ++ के साथ अजीब ओवरलोड रिज़ॉल्यूशन देखा है जिसमें शामिल हैं: '' 'के कुछ (लेकिन सभी नहीं) प्रदान कर सकते हैं, इसलिए कुछ चीजें काम करती हैं, लेकिन अन्य नहीं। –

+0

@JamesKanze: ठीक है, मैंने माना है कि ओपी ने सही हेडर और सभी आवश्यक लोगों को आयात किया है, लेकिन यह सच है कि यह सुनिश्चित करने के लिए नहीं कहा जा सकता है क्योंकि प्रारंभिक भाग प्रश्न के पाठ –

+0

से गायब है, मैं std का उपयोग कर रहा हूं; और मेरे पास उचित शामिल है। –

1
  1. पोस्ट के रूप में, आपका कोड किसी भी कंपाइलर के साथ संकलित नहीं होना चाहिए। आप गायब हैं, और std:: के बहुत सारे शामिल हैं। मैं संदिग्ध ऐसा हो रहा है कि आपके पास सभी आवश्यक शामिल नहीं हैं; विशेष रूप से, #include <string> गुम है, और वह g ++ इसे अप्रत्यक्ष रूप से चुनता है। जो उत्सुक है। समस्या आमतौर पर उलटा होता है: VC++ बहुत सारे अतिरिक्त चुनता है। कभी-कभी, हालांकि, केवल आंशिक रूप से (इसलिए आप std::string के बारे में जानकर समाप्त हो सकते हैं, लेकिन operator<< जैसे गैर-सदस्य कार्यों से संबंधित नहीं हैं)। के बिना आपके वास्तविक में शामिल होने के बावजूद, यह कहना मुश्किल है।

  2. कंपाइलर केवल फ़ंक्शंस पर ओवरलोड रिज़ॉल्यूशन निष्पादित कर सकता है, फ़ंक्शन टेम्पलेट्स पर नहीं। अधिभार रिज़ॉल्यूशन शुरू करने से पहले, यह सही नाम के साथ फ़ंक्शन टेम्पलेट्स को तुरंत चालू करने का प्रयास करता है। में एक सफल फ़ंक्शन का परिणाम, जो यह अधिभार सेट में जोड़ता है। लेकिन यह आपके फ़ंक्शन टेम्पलेट को तुरंत चालू करने वाला है। T के लिए उपयोग करने के लिए इसका कोई तरीका नहीं है । इसलिए यह (टेम्पलेट तर्क कटौती विफल रहता है) को तुरंत चालू नहीं करता है, और इसका कोई उदाहरण ओवरलोड लोड में नहीं मिलता है।

  3. मुझे यहां कुछ भी नहीं दिखाई देता है। operator<< में अनुपलब्ध रिटर्न जोड़ने के बाद, यह को वीसी ++ पर सही ढंग से संकलित करता है और चलाता है।

+0

मैं std का उपयोग कर रहा हूँ; और मेरे पास उचित शामिल है। हालांकि यह अजीब बात है कि यह आपके लिए वीसी के साथ काम करता है। यह अभी भी मेरे लिए नहीं है। तीसरा उचित संस्करण। –

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