2010-12-05 10 views
6

निम्न कोड एक SFINAE कार्यान्वयन को यह दिखाने के लिए दिखाता है कि एक प्रकार (मूल रूप से एक वर्ग) में सदस्य कार्य member_func संकलन समय पर है।SFINAE दृष्टिकोण तुलना

#define CHECKER(func_name,class_name) sizeof(class_name<T>::template func_name<T>(0)) == 1 
#include <iostream> 
struct A 
{ 
    void member_func(); 
}; 
struct B {}; 
template<typename T>struct Check_If_T_Is_Class_Type 
{ 
    template<typename C> static char func (char C::*p); 
    template<typename C> static long func (...); 
    enum{val = CHECKER(func,Check_If_T_Is_Class_Type)}; 
}; 

//APPROACH 1 
template <typename T>struct TypeHasMemberFunc 
{ 
    template <typename C, C> struct TypeCheck; 
    template <typename C> struct Prototype_Holder {typedef void (C::*fptr)();}; 
    template <typename C> static char func(TypeCheck 
              < 
               typename Prototype_Holder<C>::fptr, 
               &C::member_func 
              >*); 
    template <typename C> static long func(...); 
    enum {value = CHECKER(func,TypeHasMemberFunc)}; 
}; 

//APPROACH 2 
template <typename T>struct has_member_func 
{ 
    template<class C> static char func(char (*)[sizeof(&C::member_func)]); 
    template<class C> static long func(...); 
    enum{value = CHECKER(func,has_member_func)}; 
}; 
int main(){ 
if(Check_If_T_Is_Class_Type<A>::val) 
    std::cout<<TypeHasMemberFunc<A>::value; //using APPROACH 1 

if(Check_If_T_Is_Class_Type<B>::val) 
    std::cout<<has_member_func<B>::value; //using APPROACH 2 
} 

हालांकि मेरा प्रश्न यह है कि आप कौन सा दृष्टिकोण पसंद करेंगे (एप्रोच 1 या एप्रोच 2) और क्यों?
क्या आपको दिए गए दृष्टिकोणों में कोई असंगतता मिलती है? यदि हां कृपया मुझे बताएं।

पी.एस: मान लीजिए sizeof(char)!= sizeof(long)

+0

परामर्श भी http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence/3627243#3627243। इसमें कुछ बहुत अच्छे जवाब हैं। – FireAphis

उत्तर

-1

संपादित: पूरा और सही।

एक और दृष्टिकोण, विरासत से अस्पष्टता, शायद कार्यात्मक रूप से बराबर का उपयोग कर अपने दृष्टिकोण 2. करने के लिए मैं दृष्टिकोण 1 (यह जी ++ 4.4.5 हालांकि साथ संकलित) क्योंकि नाम संकल्प एक त्रुटि शुरू हो रहा है और एक प्रतिस्थापन विफलता के साथ परेशानी हो रही याद है। मैं का सहारा लेना पड़ा:

template <class T> 
struct has_foo 
{ 
    struct fallback { void foo(...); }; 
    struct D : T, fallback { }; 

    template <typename U, U> struct K; 

    // Will be ambiguous for U = D iff T has a foo member function.                           
    // It doesn't trigger an error, since D will always have at least one                         
    // foo member function.                                     
    template <class U> static char (&test(K<void (fallback::*)(...), &U::foo>*))[1]; 
    template <class U> static char (&test(...))[2]; 

    static const bool value = sizeof(test<D>(0)) == 2; 
}; 

यह काम करता है जब टी, एक वर्ग है ताकि आप देखना हो टी एक वर्ग प्रकार है के लिए अपने परत जोड़ने के लिए चाहते हो सकता है।

ध्यान दें कि foo सदस्य फ़ंक्शन का पता लगाया जाएगा। आप जांच करने के लिए पता लगाया foo समारोह दिए गए तर्कों के साथ कहा जा सकता है कि क्या चाहते हैं, आप SFINAE की एक और परत क्या करना है:

// Check whether foo can be called with an argument of type Arg 
// and yields an element of type Res. 
// If you need Res = void, this code does not work. 
template <class T, typename Arg, typename Res> 
struct check_foo 
{ 
    struct flag {}; 
    struct D : T { using T::foo; flag foo(...); }; 

    template <typename U> 
    static char (&test(U))[1]; 

    template <typename> static char (&test(...))[2]; 

    static Arg f(); 

    static const bool value = sizeof(test<Arg>(((D*)0)->foo(f()))) == 1; 
}; 
+0

'ताकि आप यह जांचने के लिए एक और परत जोड़ना चाहें कि टी एक वर्ग प्रकार है' पहले से ही देखभाल की गई है। मेरा कोड नमूना देखें। 'Check_If_T_Is_Class_Type' जांचता है कि कोई प्रकार' T' क्लास प्रकार है या नहीं। –

+0

@P्रासून: हाँ, मैंने देखा। –

+0

@Alexandre सी ..... 'gcc-4.3.4' के साथ संकलन त्रुटि। – Nawaz

1

दूसरा दृष्टिकोण की जांच नहीं करता समारोह प्रकार (वापसी प्रकार या तर्क प्रकार) और करता है सभी प्रकार के साथ काम करें, न केवल कक्षा के प्रकार।

+2

पर एक और पाया जा सकता है: दूसरा एक अधिभारित कार्यों के साथ विफल रहता है। –

0

मैं व्यक्तिगत रूप से खेलने के लिए दूसरा दृष्टिकोण पसंद करूंगा क्योंकि यह समझने के लिए छोटा और आसान है। लेकिन जीसीसी यह संकलन नहीं है, तो आप जीसीसी के लिए ऐसा ही कुछ का उपयोग करने के:

namespace detail 
{ 
    template<class C> char func(char (*)[sizeof(&C::member_func)]); 
    template<class C> long func(...); 
} 

template <typename T>struct has_member_func 
{ 
    enum{value = (sizeof(detail::func<T>(0)) == 1)}; 
}; 

इसके अलावा, यह चेकर मैक्रो से छुटकारा पाने के लिए अच्छा होगा। यह आपके कोड को बहुत कम पठनीय बनाता है।

वैसे भी, मैं (उत्पादन कोड में इस तरह के सी ++ हैक्स का उपयोग कर को छोड़कर आप एक बूस्ट टीम के सदस्य :-)

इस तरह के सामान हैं त्रुटियां उत्पन्न हो सकती से बचना होगा, कड़ी समर्थन करने के लिए, शायद ही compilers लेकिन प्रिंसिपल के बीच पोर्टेबल मुद्दा यह है कि मुझे याद नहीं है कि किसी भी वास्तविक जीवन कार्य को ऐसे हार्ड-कोड C++ की मांग की गई है।

+0

मैंने चेक किया और नहीं, जीसीसी में दूसरा दृष्टिकोण संकलित किया जा सकता है: - | –