2012-04-26 19 views
5

के साथ सदस्य फ़ंक्शन है SFINAE के साथ समस्या हो रही है। मुझे यह निर्धारित करने में सक्षम होना चाहिए कि किसी प्रकार का सदस्य फ़ंक्शन ऑपरेटर है-> इसके रिटर्न प्रकार के बावजूद परिभाषित किया गया है। उदाहरण निम्नानुसार है।SFINAE - यह निर्धारित करने का प्रयास कर रहा है कि टेम्पलेट प्रकार में 'चर' रिटर्न प्रकार

परीक्षक में यह कक्षा। यह एक्स * के रिटर्न प्रकार के साथ ऑपरेटर ->() को परिभाषित करता है। इस प्रकार मैं नहीं जानता कि 'एक्स' हर जगह इसे हार्डकोड करना है।

template <class X> 
class PointerX 
{ 
    ... 

    X* operator->() const; 
    ... 
} 

यह कक्षा निर्धारित करने की कोशिश करती है कि पास में टी में एक विधि ऑपरेटर-> परिभाषित है; चाहे ऑपरेटर-> वापसी प्रकार क्या है।

template<typename T> 
struct HasOperatorMemberAccessor 
{ 
    template <typename R, typename C> static R GetReturnType(R (C::*)()const); 

    template<typename U, typename R, R(U::*)()const> struct SFINAE{}; 
    template<typename U> static char Test(SFINAE<U,  decltype(GetReturnType(&U::operator->)), &U::operator-> >*); 
    template<typename U> static uint Test(...); 
    static const bool value = sizeof(Test<T>(0)) == sizeof(char); 
}; 

यह कक्षा उपरोक्त के समान सटीक है- ऑपरेटर-> वापसी प्रकार 'ऑब्जेक्ट' होना चाहिए।

template<typename T> 
struct HasOperatorMemberAccessorOBJECT 
{ 
    template <typename R, typename C> static R GetReturnType(R (C::*)()const); 

    template<typename U, typename R, R(U::*)()const> struct SFINAE{}; 
    template<typename U> static char Test(SFINAE<U,  Object*,    &U::operator-> >*); // only change is we hardcoded Object as return type. 
    template<typename U> static uint Test(...); 
    static const bool value = sizeof(Test<T>(0)) == sizeof(char); 
}; 

परिणाम:

void main() 
{ 
    HasOperatorMemberAccessor<PointerX<Object>>::Test<PointerX<Object>>(0);   // fails ::value is false; Test => Test(...) 

    HasOperatorMemberAccessorOBJECT<PointerX<Object>>::Test<PointerX<Object>>(0);  // works! ::value is true; Test => Test(SFINAE<>*) 
} 

HasOperatorMemberAccessor PointX के सदस्य समारोह "->() स्थिरांक वस्तु ऑपरेटर" खोजने में असमर्थ था। तो यह टेस्ट के जेनेरिक संस्करण टेस्ट (...) का उपयोग करता है।

हालांकि, हैस्परेटरमम्बरएसेसर ओबीजेईसीटी पॉइंटएक्स के "ऑब्जेक्ट ऑपरेटर ->() कॉन्स" को खोजने में सक्षम था। इस प्रकार यह टेस्ट विशेष संस्करण टेस्ट (SFINAE *) का उपयोग करता है।

दोनों "ऑब्जेक्ट ऑपरेटर ->() कॉन्स्ट" विधि खोजने में सक्षम होना चाहिए; और इस प्रकार दोनों को टेस्ट के विशेष संस्करण टेस्ट (SFINAE *) का उपयोग करना चाहिए; और इस प्रकार HasOperatorMemberAccessor> :: मान दोनों के लिए सच होना चाहिए।

HasOperatorMemberAccessor और HasOperatorMemberAccessorOBJECT के बीच फर्क सिर्फ इतना है कि HasOperatorMemberAccessorOBJECT typename आर आपत्ति उठाने hardcoded है,

तो मुद्दा यह है कि "decltype (GetReturnType (& यू :: ऑपरेटर>))" नहीं लौटा रहा है वस्तु है सही ढंग से। मैंने रिटर्न प्रकार की खोज करने के कई अलग-अलग परमिट की कोशिश की है। वे निम्नानुसार जाते हैं:

decltype(GetReturnType(&U::operator->)) 
    typename decltype(GetReturnType(&U::operator->)) 
    decltype(((U*)nullptr)->operator->()) 
    typename decltype(((U*)nullptr)->operator->()) 

कोई काम नहीं, क्यों? मैं एमएसवीसी ++ 10.0 का उपयोग कर रहा हूँ।

+0

एक बात है कि आंख हमलों कि 'PointerX :: ऑपरेटर>' 'रिटर्न bool *', नहीं 'bool' है। –

+0

पॉइंटरएक्स में एक्स का प्रकार कोई फर्क नहीं पड़ता है जहां तक ​​हैस्परेटर मेम्बरएस्कर का संबंध है। मैंने उदाहरण के लिए कई अपरिपक्व वस्तुओं को जोड़कर मेरी समस्या को सामान्य करने की कोशिश की। यदि यह बहुत भ्रमित है, तो मैं स्ट्रिंग में बूल बदल दूंगा। –

+0

मुझे दोबारा प्रयास करने दो। 'पॉइंटरएक्स :: ऑपरेटर->' ऑब्जेक्ट * रिटर्न ''। 'decltype (...)' 'ऑब्जेक्ट * होगा। 'HasOperatorMemberAccessorOBJECT' प्रतीत होता है, हालांकि यह' ऑब्जेक्ट' के साथ 'decltype (...)' को प्रतिस्थापित करता है। ऐसा लगता है कि यहां कुछ गड़बड़ है। मैं 'HasOperatorMemberAccessor' के बारे में बात नहीं कर रहा हूं। –

उत्तर

4

आप कैसे इस तरह के एक विशेषता लागू करने के लिए पूछ रहे हैं, या क्यों decltype व्यवहार नहीं कर रहा है के रूप में आप उम्मीद करते हैं?

#include <type_traits> 

template<typename T, bool DisableB = std::is_fundamental<T>::value> 
struct HasOperatorMemberAccessor 
{ 
private: 
    typedef char no; 
    struct yes { no m[2]; }; 

    struct ambiguator { char* operator ->() { return nullptr; } }; 
    struct combined : T, ambiguator { }; 
    static combined* make(); 

    template<typename U, U> struct check_impl; 
    template<typename U> 
    static no check(
     U*, 
     check_impl<char* (ambiguator::*)(), &U::operator ->>* = nullptr 
    ); 
    static yes check(...); 

public: 
    static bool const value=std::is_same<decltype(check(make())), yes>::value; 
}; 

// false for fundamental types, else the definition of combined will fail 
template<typename T> 
struct HasOperatorMemberAccessor<T, true> : std::false_type { }; 

// true for non-void pointers 
template<typename T> 
struct HasOperatorMemberAccessor<T*, false> : 
    std::integral_constant< 
     bool, 
     !std::is_same<typename std::remove_cv<T>::type, void>::value 
    > 
{ }; 

template<typename X> 
struct PointerX 
{ 
    X* operator ->() const { return nullptr; } 
}; 

struct X { }; 

int main() 
{ 
    static_assert(
     HasOperatorMemberAccessor<PointerX<bool>>::value, 
     "PointerX<> has operator->" 
    ); 
    static_assert(
     !HasOperatorMemberAccessor<X>::value, 
     "X has no operator->" 
    ); 
    static_assert(
     HasOperatorMemberAccessor<int*>::value, 
     "int* is dereferencable" 
    ); 
    static_assert(
     !HasOperatorMemberAccessor<int>::value, 
     "int is not dereferencable" 
    ); 
    static_assert(
     !HasOperatorMemberAccessor<void*>::value, 
     "void* is not dereferencable" 
    ); 
} 

कुलपति ++ 2010 का अभाव आवश्यक सी ++ 11 सुविधाएं (जैसे अभिव्यक्ति SFINAE) इस अधिक स्वच्छ बनाने के लिए आवश्यक: पूर्व, तो यहां एक तरीका है।

+0

खैर, यह काफी को छोड़कर इसे अस्वीकार करती है कि टी एक सूचक प्रकार होना मेरे लिए काम किया।मैंने आधार बदल दिया: संरचना आधार: सशर्त :: मान, टी, नहीं> :: प्रकार, base_mixin {}; उसने कहा, मुझे यह जानना अच्छा लगेगा कि क्यों गिरावट काम नहीं कर रही थी। –

+0

@MichaelG: 'HasOperatorMemberAccessor <> 'पॉइंटर्स के लिए त्रिकोणीय रूप से विशिष्ट हो सकता है:' टेम्पलेट कक्षा हैसोपरेटर मेम्बरएसेसर : सार्वजनिक std :: true_type {}; '। जैसा कि आप उम्मीद करते हैं 'decltype' काम नहीं कर रहा है, मैंने आपके कोड की अधिक जांच नहीं की है, लेकिन वीसी ++ 2010 का' decltype' कार्यान्वयन पूर्व-मानक और इसके शीर्ष पर छोटी गाड़ी है। – ildjarn

+0

@ माइकल: उचित पॉइंटर-प्रकार का पता लगाने के साथ संपादित ('शून्य *' एक गोचा था)। – ildjarn

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