2011-05-18 8 views
5

सभी,सभी सी ++ आईओएसट्रीम मैनिपुलेटर्स के लिए सामान्य रूप से सम्मिलन ऑपरेटर को कैसे परिभाषित किया जाए?

निम्नलिखित कोड 'std :: endl' के लिए संकलित करने में विफल क्यों होता है, लेकिन यह अन्य सभी डालने वाले प्रकारों के लिए ठीक है?

willo:~/test_cpp$ g++ -Wall test_overloaded_insertion_manipulators.cpp test_overloaded_insertion_manipulators.cpp: In function ‘int main(int, char**)’: test_overloaded_insertion_manipulators.cpp:60: error: no match for ‘operator<<’ in ‘my_stream << std::endl’

मैं कोड एक std :: endl के लिए 'ऑपरेटर < <' का दृष्टांत की उम्मीद, जैसे यह पुरातन के लिए किया था, एसटीडी:

#include <sstream> // ostringstream 

/// @brief A class that does streamed, formatted output via 'operator<<'. 
class My_Stream 
{ 
public: 
    /// @brief A member method that manipulates the underlying stream. 
    void foo() 
    { 
     m_oss << "foo_was_here; "; 
    } 

private: 
    /// @brief The underlying stream. 
    std::ostringstream m_oss; 

    /// @brief 'operator<<' is a friend. 
    template< typename T > 
    friend My_Stream& operator<<(My_Stream& a_r_my_stream, 
            const T& a_r_value); 
}; 

/// @brief A manipulator that calls a class method. 
My_Stream& manipulator_foo(My_Stream& a_r_my_stream) 
{ 
    a_r_my_stream.foo(); 
    return a_r_my_stream; 
} 

/// @brief The generic insertion operator. 
template< typename T > 
My_Stream& operator<<(My_Stream& a_r_my_stream, 
         const T& a_r_value) 
{ 
    a_r_my_stream.m_oss << a_r_value; 
    return a_r_my_stream; 
} 

/// @brief Define an iostream-like manipulator for my-stream. 
typedef My_Stream& (* my_stream_manipulator) (My_Stream&); 

/// @brief The specialized 'my_stream_manipulator' insertion operator. 
template<> 
My_Stream& operator<<(My_Stream& a_r_my_stream, 
         const my_stream_manipulator& a_r_manipulator) 
{ 
    return a_r_manipulator(a_r_my_stream); 
} 

int main(int argc, char* argv[]) 
{ 
    My_Stream my_stream; 

    my_stream << 'c'; // char 
    my_stream << "string"; // c-string 
    my_stream << 1u; // unsigned int 
    my_stream << -1; // signed int 
    my_stream << 5.3f; // float 
    my_stream << -23.345; // double 
    my_stream << std::boolalpha; // std::ios_base manipulator 
    my_stream << std::endl; // std::ostream manipulator 
    my_stream << manipulator_foo; // my_stream manipulator 

    return 0; 
} 

मैं निम्नलिखित जी ++ 4.5 त्रुटि मिलती है: : ios_base और मेरे कस्टम मैनिपुलेटर।

संदर्भ के लिए, मैं एक प्रकाश-एपीआई आईओएसट्रीम-जैसी कक्षा बनाने की कोशिश कर रहा हूं जो मौजूदा आईओएसट्रीम मैनिपुलेटर्स के साथ-साथ एक या दो कस्टम मैनिपुलेटर्स के साथ काम करता है।

template <class charT, class traits> 
basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os); 

तो पहचानकर्ता अपने आप में एक मान नहीं है:

+0

आप यकीन है कि यह सिर्फ सार्वजनिक रूप से 'ostringstream' से प्राप्त करना अधिक व्यावहारिक नहीं होगा रहे हैं:

// Note: Untested (don't have a compiler here). template <class charT, class Traits> friend My_Stream& operator<<(My_Stream&, std::basic_ostream<charT, Traits>& (*)(std::basic_ostream<charT, Traits>&)); 

तो फिर तुम समारोह को परिभाषित करने की आवश्यकता है? आप अभी भी कस्टम कार्यक्षमता जोड़ सकते हैं, लेकिन स्ट्रिंगस्ट्रीम स्वयं पहले से ही क्या कर सकता है यह जानने के लिए परेशान करने की आवश्यकता नहीं होगी। – leftaroundabout

+0

@ बाएंअराउंडबाउट: अधिकांश एसटीएल ऑब्जेक्ट्स वास्तव में से प्राप्त किए जाने के लिए डिज़ाइन नहीं किए गए हैं, लेकिन 'std :: ostringstream' में कम से कम आभासी विनाशक लगता है ताकि यह काम कर सके। – AJG85

+0

@ बाएंअराउंडबाउट हां, मुझे यकीन है। यह मेरी वर्तमान समस्या डीबग करने के लिए एक खिलौना उदाहरण है। मेरा इच्छित कोड प्रत्येक सम्मिलन संचालन को रोकना चाहिए, और सशर्त रूप से चीजें करना चाहिए; तो मुझे अपनी नई कक्षा के खिलाफ 'ऑपरेटर <<' को फिर से कार्यान्वित करना होगा। –

उत्तर

7

क्योंकि endl एक समारोह टेम्पलेट है। यह तत्काल होने पर केवल एक मान (फ़ंक्शन पॉइंटर) बन जाता है। लेकिन आपके operator<< स्वयं एक टेम्पलेट है, और संकलक के लिए endl को तुरंत चालू करने के लिए कोई प्रकार की जानकारी उपलब्ध नहीं है।

इसके विपरीत, उदा। boolalpha है:

ios_base& boolalpha(ios_base& str); 

इसलिए यह क्यों काम करता है।

endlbasic_ostream के लिए काम करता है, क्योंकि यह operator<< ओवरलोड को परिभाषित करता है क्योंकि सदस्य फ़ंक्शन फ़ंक्शन पॉइंटर्स लेते हैं; विशेष रूप से:

basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&)); 

तो stream << endl की तरह एक कॉल में, यह charT और this के प्रकार से traits (ऑपरेटर की यानी बाईं ओर) पता होगा, और कहा कि यह समारोह सूचक का सही प्रकार सही पर उम्मीद करने देना होगा पक्ष - जिसका उपयोग तब endl के संबंधित संस्करण को तुरंत चालू करने के लिए किया जाएगा। आप अपनी कक्षा के लिए भी ऐसा ही कर सकते हैं।

+0

यह बिल्कुल है; मैंने इस तथ्य को नहीं जोड़ा था कि 'एंडल' एक टेम्पलेट-फ़ंक्शन है, कोई फ़ंक्शन नहीं है। धन्यवाद। –

2

आपको स्ट्रीम मैनिपुलेटर्स को एक अलग मित्र के रूप में परिभाषित करने की आवश्यकता है।

इस दोस्त जोड़ें:

template <class charT, class Traits> 
My_Stream& operator<<(My_Stream& stream, std::basic_ostream<charT, Traits>& (*manip)(std::basic_ostream<charT, Traits>&)) 
{ 
    (*manip)(stream.m_oss); 
    return stream; 
} 
+0

क्या यह वास्तव में templated होना चाहिए?चूंकि 'stream.m_oss' एक विशिष्ट प्रकार है, केवल' std :: ostream & (*) (std :: ostream &) 'वास्तव में यहां काम करेगा। – aschepler

+0

टेम्पलेट My_Stream के लिए नहीं है, लेकिन std :: endl के लिए जो टेम्पलेट है जिसके बारे में हम चिंतित हैं (यही कारण है कि हमें पहली जगह में समस्या है (इसलिए हाँ आपको टेम्पलेट चाहिए))। –

+0

+1 यह मेरे टेम्पलेट विशेषज्ञता पर मेरे एक्सटेंशन से बेहतर है क्योंकि यह 'std :: endl' के सभी टेम्पलेट प्रकारों के लिए काम करता है जिसे परिभाषित किया जा सकता है। – AJG85

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