2011-03-31 13 views
6

समझ C++ 0x में एक अभ्यास के रूप में decltype का उपयोग करता है, मैं एक सी बनाने के लिए कोशिश कर रहा हूँ ++ वर्ग है कि कुछ टेम्पलेट ized प्रकार का एक सूचक लपेटता:instantiating एक टेम्पलेट में एक समारोह परिभाषा केवल कुछ निश्चित परिस्थितियों

template <typename T> 
class Wrapper { 
    T *t; 
    /* ... */ 
}; 

रैपर वर्ग के अंदर, मैं किसी भी ओवरलोडेड ऑपरेटरों का खुलासा करना चाहता हूं जो टी रैपर वर्ग के माध्यम से लागू हो सकती हैं। रैपर स्वयं अंतर्निहित टी ऑब्जेक्ट को फ़ंक्शन कॉल को आगे बढ़ाता है।

template <typename U> 
auto operator+(U &u) -> decltype (*t + u) { 
    return *t + u; 
} 

पकड़ है कि मैं आवरण उजागर ऑपरेटरों कि टी लागू नहीं कर सकें नहीं करना चाहती है। उदाहरण के लिए, यदि टी ऑपरेटर को लागू नहीं करता है तो फिर रैपर को ऑपरेटर + का पर्दाफाश नहीं करना चाहिए।

ऑपरेटर + (और किसी भी बाइनरी ऑपरेशन) के मामले में, सब कुछ काम करता है क्योंकि ऑपरेटर अनिवार्य रूप से टेम्पलेट फ़ंक्शन बन जाता है और इस प्रकार हम केवल तभी प्रयास करते हैं जब हम इनकार करने का प्रयास करते हैं, उदाहरण के लिए, रैपर :: ऑपरेटर +।

हालांकि, यूनरी ऑपरेटरों (उदाहरण के लिए, ++) के मामले में, ऑपरेटर की रक्षा करने का कोई स्पष्ट तरीका नहीं है ताकि यह तत्काल है अगर iff टी ऑपरेटर ++ लागू करता है। उदाहरण के लिए, इस वर्ग के

auto operator++() -> decltype(++(*t)) { 
    return ++(*t); 
} 

में ऑपरेटर ++ के अनुभवहीन कार्यान्वयन एक टी कि ऑपरेटर का समर्थन नहीं करता ++ (के लिए संकलित करने के लिए विफल रहता है)।

मानक की मेरी समझ से

, हम निम्नलिखित कोड आवरण का उपयोग करता है अगर

class X { }; 
Wrapper<X> w; 

हम आवरण और घोषणा आवरण :: ऑपरेटर की ++() करती है लेकिन उसके परिभाषा जब तक का दृष्टांत होगा हम इसे आमंत्रित करते हैं (या स्पष्ट रूप से इसे तुरंत चालू करते हैं)। आम तौर पर यह ठीक होगा, क्योंकि एक्स :: ऑपरेटर ++ का उपयोग केवल रैपर :: ऑपरेटर ++() की परिभाषा में होता है। हालांकि, decltype की वजह से, हम घोषणा में एक्स :: ऑपरेटर ++ का उपयोग करते हैं ताकि टाइपशेकर एक्स :: ऑपरेटर ++ के अस्तित्व के लिए जांच सके और इस प्रकार विफल हो जाता है।

हम ऑपरेटर परिभाषित कर सकता हूँ ++() (और सामान्य में किसी भी तरह के अग्रेषण समारोह decltype का उपयोग करता है) गुण है कि यह अंतर्निहित वस्तु iff instantiated है के साथ भी ऑपरेटर का समर्थन करता है ++()? या गिरावट के साथ टेम्पलेट तत्काल के अर्थशास्त्र दिया, क्या यह पूरा करना असंभव है?

+0

संबंधित प्रश्न के रूप में: क्या यह पिछली वापसी 'decltype' में' this' को संदर्भित करना कानूनी है? विज़ुअल सी ++ 2010 और जी ++ 4.5.1 इसे पसंद नहीं करते हैं। –

+0

@ जेम्स - एक महीने पहले से इस चर्चा को देखें [http://stackoverflow.com/questions/5147492/member-function-call-in-decltype ](http://stackoverflow.com/questions/5147492/member- कार्यक्षमता -call-इन-decltype)। –

+0

@ बोपरसन: धन्यवाद! मुझे लगता है कि हम कुछ हफ्तों में पता लगाएंगे कि क्या उस बदलाव ने इसे सी ++ 0x में बनाया है। –

उत्तर

5

आप एक गैर सदस्य टेम्पलेट के रूप में ऑपरेटर की घोषणा कर सकते हैं:

template <typename T> 
auto operator++(Wrapper<T>& arg) -> decltype(++*arg.t) { 
    return ++*arg.t; 
} 
+2

@ जेम्स-मैकनेलिस अच्छा सुझाव! हालांकि, ऑपरेटरों के बारे में क्या है जिन्हें सदस्य कार्यों के रूप में घोषित किया जाना चाहिए, लेकिन एक टेम्पलेट प्रकार को पिगबैक करने के लिए कोई तर्क नहीं है? (जिनमें से, मुझे लगता है कि केवल एक ही ऑपरेटर है ->())। – psosera

+0

यह एक दिलचस्प सवाल है, जिस पर मेरे पास इस समय कोई जवाब नहीं है। –

+0

@ user686170: यदि आप जीसीसी का उपयोग कर रहे हैं और 'std :: enable_if' के साथ थोड़ा सा रचनात्मकता प्राप्त करना चाहते हैं, तो मैंने एक उत्तर पोस्ट किया जो उदा। 'ऑपरेटर>'। – ildjarn

4

तुम भी कर सकता है डिफ़ॉल्ट टेम्पलेट तर्क के साथ चाल, बस ऑपरेटर के संकार्य बनाने के लिए निर्भर हो

template<typename Trick = T> 
auto operator++() -> decltype(++(static_cast<Trick&>(*t))) { 
    return ++(*t); 
} 

शायद

template<typename /* Ignored */, typename T> T &&id(T &&t) { 
    return std::forward<T>(t); 
} 

template<typename Void = void> 
auto operator++() -> decltype(++(*id<Void>(t))) { 
    return ++(*t); 
} 
2

के बीच एक सहायक समारोह के साथ यदि आप यह समझ सकते हैं कि कैसे w ऑपरेटर हस्ताक्षर में ओर्क std::enable_if, यहां एक मेटाफंक्शन है जो उदाहरण के अस्तित्व की जांच करता है।operator->:

#include <type_traits> 

template<typename T, typename R> 
inline R* has_deref_opr_sfinae_impl_helper(R (T::*)()) { return 0; } 

template<typename T, typename R> 
inline R* has_deref_opr_sfinae_impl_helper(R (T::*)() const) { return 0; } 

template< 
    typename T, 
    bool IsPointer = 
     std::is_pointer<T>::value && 
     !std::is_same< 
      typename std::remove_cv< 
       typename std::remove_pointer< 
        typename std::remove_cv<T>::type 
       >::type 
      >::type, 
      void 
     >::value 
> 
class has_deref_opr 
{ 
    template< 
     typename U, 
     typename R = decltype(has_deref_opr_sfinae_impl_helper(&U::operator->)) 
    > 
    struct sfinae_impl { }; 

    typedef char true_t; 
    struct false_t { true_t f[2]; }; 

    template<typename U> 
    static true_t check(U*, sfinae_impl<U>* = 0); 
    template<typename U> 
    static false_t check(...); 

public: 
    static bool const value = sizeof(check<T>(0)) == sizeof(true_t); 
}; 

template<typename T> 
class has_deref_opr<T, true> 
{ 
public: 
    static bool const value = true; 
}; 

कुछ नोट:

  • मैं जीसी 4.4.1 के साथ परीक्षण किया है, यह has_deref_opr_sfinae_impl_helperhas_deref_opr के अंदर जा रहा है, यकीन नहीं क्यों पसंद नहीं आया। हो सकता है कि यह जीसीसी के नवीनतम संस्करण में परिवर्तित हो जाता है
  • कुलपति ++ 2010 SP1 के एक टेम्पलेट इन्स्टेन्शियशन बग है कि मैं के लिए एक समाधान नहीं मिल सका करने के लिए इस वजह से संकलन करने में विफल रहता है: - [

आशा इस मदद करता है।

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