2011-04-24 14 views
11

मैं कई अधिभारित करना चाहता हूं, वैश्विक to_string() फ़ंक्शंस जो कुछ प्रकार T लेते हैं और इसे अपने स्ट्रिंग प्रस्तुति में परिवर्तित करते हैं। सामान्य मामले के लिए, मैं लिखने के लिए सक्षम होना चाहते हैं:वैश्विक ऑपरेटर की जांच के लिए SFINAE का उपयोग <<?

template<typename T,class OutputStringType> inline 
typename enable_if<!std::is_pointer<T>::value 
       && has_insertion_operator<T>::value, 
        void>::type 
to_string(T const &t, OutputStringType *out) { 
    std::ostringstream o; 
    o << t; 
    *out = o.str(); 
} 

has_insertion_operator मेरे कार्यान्वयन अब तक है:

struct sfinae_base { 
    typedef char yes[1]; 
    typedef char no[2]; 
}; 

template<typename T> 
struct has_insertion_operator : sfinae_base { 
    template<typename U> static yes& test(U&); 
    template<typename U> static no& test(...); 

    static std::ostream &s; 
    static T const &t; 

    static bool const value = sizeof(test(s << t)) == sizeof(yes); // line 48 
}; 

(यह this और this से उधार लेता है।) काम करने के लिए लगता है कि । लेकिन अब मैं ऐसा नहींoperator<< लेकिन करना अपने स्वयं के to_string()सदस्य कार्य हो है प्रकार, अर्थात् के लिए to_string का एक अतिभारित संस्करण करना चाहते हैं:

template<class T,class OutputStringType> inline 
typename enable_if<!has_insertion_operator<T>::value 
       && has_to_string<T,std::string (T::*)() const>::value, 
        void>::type 
to_string(T const &t, OutputStringType *out) { 
    *out = t.to_string(); 
} 

has_to_string के कार्यान्वयन है:

#define DECL_HAS_MEM_FN(FN_NAME)          \ 
    template<typename T,typename S>          \ 
    struct has_##FN_NAME : sfinae_base {        \ 
    template<typename SignatureType,SignatureType> struct type_check; \ 
    template<class U> static yes& test(type_check<S,&U::FN_NAME>*); \ 
    template<class U> static no& test(...);       \ 
    static bool const value = sizeof(test<T>(0)) == sizeof(yes); \ 
    } 

DECL_HAS_MEM_FN(to_string); 

(यह हिस्सा ठीक काम करता प्रतीत होता है। इसे this से अनुकूलित किया गया है।) हालांकि, मैं जब:

struct S { 
    string to_string() const { 
    return "42"; 
    } 
}; 

int main() { 
    string buf; 
    S s; 
    to_string(s, &buf); // line 104 
} 

मैं:

foo.cpp: In instantiation of ‘const bool has_insertion_operator<S>::value’: 
foo.cpp:104: instantiated from here 
foo.cpp:48: error: no match for ‘operator<<’ in ‘has_insertion_operator<S>::s << has_insertion_operator<S>::t’ 

ऐसा लगता है SFINAE की तरह हो रहा है। मैं has_insertion_operator को सही तरीके से कैसे लिखूं जैसे यह निर्धारित करता है कि वैश्विक operator<< उपलब्ध है या नहीं?

एफवाईआई: मैं जी ++ 4.2.1 (जो कि मैक ओएस एक्स पर एक्सकोड के हिस्से के रूप में जहाजों का उपयोग कर रहा है) का उपयोग कर रहा हूं। इसके अलावा, मैं कोड को केवल तृतीय-पक्ष पुस्तकालयों के बिना मानक सी ++ 03 होना चाहता हूं, उदाहरण के लिए, बूस्ट।

धन्यवाद!

+1

यह सब निश्चित रूप से करने योग्य है, लेकिन * क्यों *? – Potatoswatter

+2

@ पोटाटोस्वाटर: क्यों महत्वपूर्ण नहीं है। कृपया मान लें कि मेरे बाकी प्रोजेक्ट के लिए मुझे पता है कि मैं क्या कर रहा हूं। यदि आपको पता होना चाहिए, तो यह स्थानीयकृत त्रुटि संदेश का हिस्सा बनाने के लिए किसी भी प्रकार के पैरामीटर पास करने के लिए ढांचे का हिस्सा है।इस प्रश्न के लिए अनावश्यक सभी का विवरण। यदि आप जानते हैं कि इसे कैसे करें, तो कृपया प्रश्न का उत्तर दें। यह बहुत सराहनीय होगा। –

+2

हमेशा महत्वपूर्ण क्यों है। – GManNickG

उत्तर

10

मुझे this उत्तर के लिए बस अधिक वफादार होना चाहिए था। एक काम कर दिया गया है:

namespace has_insertion_operator_impl { 
    typedef char no; 
    typedef char yes[2]; 

    struct any_t { 
    template<typename T> any_t(T const&); 
    }; 

    no operator<<(std::ostream const&, any_t const&); 

    yes& test(std::ostream&); 
    no test(no); 

    template<typename T> 
    struct has_insertion_operator { 
    static std::ostream &s; 
    static T const &t; 
    static bool const value = sizeof(test(s << t)) == sizeof(yes); 
    }; 
} 

template<typename T> 
struct has_insertion_operator : 
    has_insertion_operator_impl::has_insertion_operator<T> { 
}; 

मेरा मानना ​​है कि यह नहीं वास्तव में SFINAE पर भरोसा करता है।

+0

अद्भुत: क्या यह सी ++ 03 कंपाइलर्स में काम करता है? –

+0

इसे आज़माएं और पता लगाएं। –

+0

वैसे भी कोड के लिए धन्यवाद :) –

1

लाइन 48 पर value का प्रारंभकर्ता एक संदर्भ में नहीं है जहां SFINAE काम करता है। अभिव्यक्ति को फ़ंक्शन घोषणा में ले जाने का प्रयास करें।

#include <iostream> 

struct sfinae_base { 
    typedef char yes[1]; 
    typedef char no[2]; 
}; 

template<typename T> 
struct has_insertion_operator : sfinae_base { 

    // this may quietly fail: 
    template<typename U> static yes& test(
     size_t (*n)[ sizeof(std::cout << * static_cast<U*>(0)) ]); 

    // "..." provides fallback in case above fails 
    template<typename U> static no& test(...); 

    static bool const value = sizeof(test<T>(NULL)) == sizeof(yes); 
}; 

हालांकि, मुझे इसमें परिष्कार की मात्रा पर सवाल उठाना है। मैं गैर-ऑर्थोगोनल तंत्र देखता हूं जो एक दूसरे के खिलाफ पीसेंगे (to_string बनाम operator<<) और मुझे लगता है कि खराब धारणाएं फेंक रही हैं (उदाहरण के लिए operator<< वैश्विक बनाम सदस्य है, हालांकि लागू कोड को उस संबंध में ठीक दिखता है)।

+1

यह कई त्रुटियों के साथ संकलित नहीं करता है। पहली त्रुटि यह है: टेम्पलेट पैरामीटर पर निर्भर 'परीक्षण' के लिए कोई तर्क नहीं है, इसलिए 'परीक्षण' की घोषणा उपलब्ध होनी चाहिए। –

+0

बीटीडब्ल्यू: ऑपरेटर << वैश्विक होना चाहिए यदि यह एक प्रविष्टि ऑपरेटर होना है क्योंकि पहला तर्क एक ओस्ट्रीम होना चाहिए और। –

+0

बीटीडब्ल्यू # 2: ओस्ट्रीम :: ओस्ट्रीम() संरक्षित है। –

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