2014-11-04 5 views
6

मैंने SFINAE पर कुछ लेख पढ़े हैं, लेकिन मेरे मामले के लिए समाधान नहीं मिल रहा है। यहाँ मैं क्या करना चाहते है:उसी विधि के 2 अलग-अलग कार्यान्वयन बनाने के लिए SFINAE का उपयोग कैसे करें

#include <type_traits> 

struct CByteArray {}; 
struct HLVariant { 
    HLVariant() {} 
    HLVariant(const HLVariant&) {} 
    HLVariant(const CByteArray&) {} 

    }; 

template <typename T> 
struct Serializer 
{ 
    static inline typename std::enable_if<std::is_pod<T>::value, CByteArray>::type serialize(const T& value) 
    { 
     static_assert(std::is_pod<T>::value, "Not a POD type"); 
     return CByteArray(); 
    } 

    static inline typename std::enable_if<!std::is_pod<T>::value, CByteArray>::type serialize(const T& value) 
    { 
     return Serializer<HLVariant>::serialize(HLVariant(value)); 
    } 
}; 

template <> 
struct Serializer<HLVariant> 
{ 
    static inline CByteArray serialize(const HLVariant& value) 
    { 
     return CByteArray(); 
    } 
}; 

int main() 
{ 
    int i = 0; 
    Serializer<int>::serialize(i); 
    Serializer<CByteArray>::serialize(CByteArray()); 
    Serializer<HLVariant>::serialize(HLVariant()); 

    return 0; 
} 

लेकिन, ज़ाहिर है, मैं error C2039: 'type' : is not a member of 'std::enable_if<false,CByteArray>'

कैसे प्राप्त करने के लिए मैं क्या चाहते हो रही है?

साथ ही, Serializer किसी भी तरह से पुनर्गठित करना संभव होगा, ताकि टेम्पलेट पैरामीटर को Serializer<int>::serialize(i); के बजाय Serializer::serialize(i); को स्पष्ट रूप से घटाया जा सके?

+1

@ नवाज वोटिंग आपके उत्तर को हटाने के लिए, क्योंकि यह समस्या के लिए बेहतर विकल्प प्रस्तावित करता है। –

+0

@ नवाज़: वही। मैंने पहले ही संकलित और उस दृष्टिकोण के साथ अपने कोड का परीक्षण किया है। इसके बारे में भी एक सवाल है। –

उत्तर

2

std::enable_if<condition> का उपयोग करने के लिए, आपको इस स्थिति में एक टेम्पलेट में होना चाहिए। एक विकल्प आप वर्ग टेम्पलेट के दायरे में सीधे SFINAE आवेदन कर सकते हैं, एक सहायक सदस्य समारोह टेम्पलेट घोषित करने के लिए serialize_t

template <typename T> 
struct Serializer 
{ 
    template<bool is_pod> // template over condition 
    static typename std::enable_if< is_pod, CByteArray>::type serialize_t(const T& value) 
    { return CByteArray(); } 

    template<bool is_pod> 
    static typename std::enable_if<!is_pod, CByteArray>::type serialize_t(const T& value) 
    { return Serializer<HLVariant>::serialize(HLVariant(value)); } 

    static CByteArray serialize(const T& value) 
    { return serialize_t<std::is_pod<T>::value>(value); } 
}; 

template<> 
struct Serializer<HLVariant> 
{ 
    static CByteArray serialize(const HLVariant&) 
    { return CByteArray(); } 
}; 

वैकल्पिक रूप से है:

template<typename T, typename = void> struct Serializer; 

template<> 
struct Serializer<HLVariant> 
{ 
    static CByteArray serialize(const HLVariant&) 
    { return CByteArray(); } 
}; 

template<typename T> 
struct Serializer<T,typename std::enable_if<is_pod<T>::type> 
{ 
    static CByteArray serialize(const T&) 
    { return CByteArray(); } 
}; 

template<typename T> 
struct Serializer<T,typename std::enable_if<!is_pod<T>::type> 
{ 
    static CByteArray serialize(const T&value) 
    { return Serializer<HLVariant>::serialize(HLVariant(value)); 
}; 

या आप वर्ग से छुटकारा पाने सकता है Serializer और टेम्पलेट कार्यों के माध्यम से सीधे इस की घोषणा:

inline CByteArray 
serialize(const HLVariant&) 
{ return CByteArray(); } 

template<typename T> 
inline typename enable_if<std::is_pod<T>::value, CByteArray>::type 
serialize(const T&) 
{ return CByteArray(); } 

template<typename T> 
inline typename enable_if<!std::is_pod<T>::value, CByteArray>::type 
serialize(const T&value) 
{ return serialize(HLVariant(value)); } 

Btw, सी ++ 14 बहुत उपयोगी उर्फ ​​परिभाषित करता है

template<bool C, typename T> 
using enable_if_t = typename enable_if<C,T>::type; 

लेकिन आप निश्चित रूप से ऐसा भी कर सकते हैं। यह हर समय थकाऊ typename और ::type से बचाता है।

+0

आपका आखिरी सुझाव वह है जो मैंने शुरू किया था।यह काम करता है, लेकिन मैं बहुत जटिल हो जाता हूं क्योंकि मैं "विशेषज्ञता" जोड़ता हूं (बेहतर शब्द की कमी के लिए; ये निश्चित रूप से सी ++ शर्तों में विशेषज्ञता नहीं हैं)। –

+0

मुझे डर है, विभिन्न इनपुट प्रकार व्यवहार के लिए विभिन्न कार्यान्वयन के साथ एक सामान्य इनपुट प्रकार के लिए सामान्य कार्यक्षमता लिखना जटिल हो जाएगा ... – Walter

+0

यदि विशेषज्ञ उचित तरीके से काम नहीं करते हैं! ऐसा लगता है कि इसके लिए हमें वास्तव में कुछ स्थिर 'स्थिर' की आवश्यकता है। –

3

एसएफआईएनएई "प्रतिस्थापन विफलता एक त्रुटि नहीं है" के लिए एक संक्षिप्त शब्द है। परिभाषा के अनुसार, इसका मतलब है कि यह केवल तभी लागू होता है जब टेम्पलेट की परिभाषा में पैरामीटर के लिए टेम्पलेट तर्कों को प्रतिस्थापित किया जाता है। आपके serialize फ़ंक्शंस क्लास टेम्पलेट के सदस्य फ़ंक्शन हैं, वे स्वयं टेम्पलेट्स फ़ंक्शन नहीं हैं। सीधा जवाब समारोह टेम्पलेट्स में कार्यों कन्वर्ट करने के लिए होगा (Live code):

template <typename> struct Serializer; 

template <> 
struct Serializer<HLVariant> 
{ 
    static CByteArray serialize(const HLVariant& /* value */) 
    { 
     return CByteArray(); 
    } 
}; 

template <typename T> 
struct Serializer 
{ 
    template <typename U = T> 
    static typename std::enable_if<std::is_pod<U>::value, CByteArray>::type 
    serialize(const U& /* value*/) 
    { 
     static_assert(std::is_pod<U>::value, "Not a POD type"); 
     return CByteArray(); 
    } 

    template <typename U = T> 
    static typename std::enable_if<!std::is_pod<U>::value, CByteArray>::type 
    serialize(const U& value) 
    { 
     return Serializer<HLVariant>::serialize(HLVariant(value)); 
    } 
}; 

मैं अनावश्यक inline रों हटा दिया है के बाद से सभी कार्यों एक वर्ग शरीर में परिभाषित परोक्ष इनलाइन हैं, और मैं करने के लिए Serializer<HLVariant> विशेषज्ञता जगह बदली सुनिश्चित करें कि संदर्भित होने से पहले इसे ठीक से घोषित किया गया है। यह केवल स्थिर सदस्य कार्यों के साथ कक्षा रखने के लिए थोड़ा मूर्ख है;

inline CByteArray serialize(const HLVariant& /* value */) 
{ 
    return CByteArray(); 
} 

template <typename T> 
inline typename std::enable_if<std::is_pod<T>::value, CByteArray>::type 
serialize(const T& /* value*/) 
{ 
    static_assert(std::is_pod<T>::value, "Not a POD type"); 
    return CByteArray(); 
} 

template <typename T> 
inline typename std::enable_if<!std::is_pod<T>::value, CByteArray>::type 
serialize(const T& value) 
{ 
    return serialize(HLVariant(value)); 
} 

int main() 
{ 
    int i = 0; 
    serialize(i); 
    serialize(CByteArray()); 
    serialize(HLVariant()); 
} 

यह देखते हुए कि SFINAE उपयोग कोड पठनीयता बाधित, मैं इस उदाहरण में भेजने टैग का उपयोग करना पसंद करेंगे: आप और अधिक यथोचित अतिभारित कार्यों का एक सेट (Live code) के रूप में यह लागू हो सकता है।

inline CByteArray serialize(const HLVariant& /* value */) 
{ 
    return CByteArray(); 
} 

template <typename T> 
inline CByteArray serialize(std::true_type, const T& /* value*/) 
{ 
    static_assert(std::is_pod<T>::value, "Not a POD type"); 
    return CByteArray(); 
} 

template <typename T> 
inline CByteArray serialize(std::false_type, const T& value) 
{ 
    return serialize(HLVariant(value)); 
} 

template <typename T> 
inline CByteArray serialize(const T& value) 
{ 
    return serialize(std::is_pod<T>{}, value); 
} 

SFINAE शक्तिशाली है, लेकिन पर्याप्त खतरनाक नहीं छोड़ा जा सकता सुरक्षित रूप से दूर बंद कर दिया करने के लिए: इसके बजाय SFINAE के साथ दो कार्यों का अधिभार संकल्प के प्रबंधन के लिए, एक तिहाई समारोह पॉड या गैर पॉड के लिए उपयुक्त कार्यान्वयन (Yet more live code) कहता है कि है उन समस्याओं के लिए जिन्हें आप सरल उपकरण के साथ हल कर सकते हैं।

+0

कूल चाल, पहला वाला। अब मैं अपनी गलती को समझता हूं। मैंने शुरुआत में कक्षा टेम्पलेट के बजाय मुफ्त टेम्पलेट फ़ंक्शंस के साथ शुरू किया था, लेकिन एमएसवीसी में एक बग है जो मेरे मामले में टेम्पलेट फ़ंक्शन विशेषज्ञता को अनुपयोगी बनाता है: http://stackoverflow.com/questions/26716609/using-stdenable-if-on-template -फंक्शन-रिटर्न-टाइप-टूएक्सप्लोइट-एसफिना-कंपिला –

+0

* एसएफआईएनएई सुरक्षित रूप से बंद होने के लिए पर्याप्त खतरनाक है * इसके बारे में खतरनाक क्या है? और उन खतरों को टैग-प्रेषण से कैसे बचाया जाता है? मैं मानता हूं कि SFINAE कोड पठनीयता को प्रभावित करता है, लेकिन टैग प्रेषण बहुत बेहतर नहीं है, वास्तव में यह खतरनाक है, क्योंकि इस बात की कोई गारंटी नहीं है कि 'serialize (std :: false_type, const t और value) को गलत दूसरे तर्क के साथ नहीं कहा जाता है (क्योंकि यह 'निजी 'या' संरक्षित 'नहीं है) – Walter

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

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