2013-09-06 8 views
9

मैं एक विशेष टेम्पलेट को सक्षम करने के लिए SFINAE का उपयोग करना चाहता हूं यदि उपयोगकर्ता पैरामीटर के रूप में फ़ंक्शन पॉइंटर पास करता है।`std :: enable_if` फ़ंक्शन पॉइंटर है - कैसे?

मैंने चारों ओर गुगल किया है लेकिन कुछ भी नहीं मिला - मैंने <type_traits> दस्तावेज़ीकरण को देखने का भी प्रयास किया लेकिन is_function_ptr<T> जैसा कुछ भी नहीं मिला।

फ़ंक्शन पॉइंटर द्वारा, मेरा मतलब है वैश्विक फ़ंक्शन पॉइंटर्स, जैसे TReturn(*)(TArgs...)

+0

क्या आप दोनों is_function और is_pointer देख सकते हैं? –

+0

क्यों SFINAE? यह यहाँ एक overkill है। –

+0

क्यों कोई साधारण एफ (std :: function)? –

उत्तर

5

नीचे एक प्रकार का गुण निर्धारित करना है कि कुछ फ़ंक्शन पॉइंटर और कुछ परीक्षण मामले हैं या नहीं। नोट, यह जांचने के लिए कि क्या कोई फ़ंक्शन पॉइंटर है, आपको std::is_pointer<P>::valuetrue और std::is_function<T>::valuetrue है जहां TP पॉइंटर हटा दिए जाने पर परीक्षण करने की आवश्यकता है। नीचे दिया गया कोड केवल यह करता है:

#include <type_traits> 
#include <iostream> 
#include <utility> 

template <typename Fun> 
struct is_fun_ptr 
    : std::integral_constant<bool, std::is_pointer<Fun>::value 
          && std::is_function< 
            typename std::remove_pointer<Fun>::type 
           >::value> 
{ 
}; 

template <typename Fun> 
typename std::enable_if<is_fun_ptr<Fun>::value>::type 
test(Fun) { 
    std::cout << "is a function pointer\n"; 
} 

template <typename Fun> 
typename std::enable_if<!is_fun_ptr<Fun>::value>::type 
test(Fun) { 
    std::cout << "is not a function pointer\n"; 
} 

void f0() {} 
void f1(int) {} 
void f2(int, double) {} 

struct s0 { void operator()() {} }; 
struct s1 { void operator()(int) {} }; 
struct s2 { void operator()(int, double) {} }; 

int main() 
{ 
    int v0(0); 
    int* p0(&v0); 
    void (*p1)() = &f0; 
    void (**p2)() = &p1; 
    std::cout << "v0="; test(v0); 
    std::cout << "p0="; test(p0); 
    std::cout << "p1="; test(p1); 
    std::cout << "p2="; test(p2); 

    std::cout << "f0="; test(&f0); 
    std::cout << "f1="; test(&f1); 
    std::cout << "f2="; test(&f2); 

    std::cout << "s0="; test(s0()); 
    std::cout << "s1="; test(s1()); 
    std::cout << "s2="; test(s2()); 

    std::cout << "l0="; test([](){}); 
    std::cout << "l1="; test([](int){}); 
    std::cout << "l2="; test([](int, double){}); 
} 
+0

आप आसानी से 'constexpr' फ़ंक्शन टेम्पलेट और एनएम के उत्तर से बाहर एक विशेषता बना सकते हैं, नहीं? और यह कहीं अधिक शक्तिशाली होगा (आपको कम से कम पैरामीटर, या एक विशेष रिटर्न प्रकार की आवश्यकता हो सकती है)। –

+0

@BenVoigt: निश्चित रूप से। हालांकि, सवाल यह नहीं था कि "एनएम के समाधान के आधार पर कोई फ़ंक्शन पॉइंटर क्या है, तो आप कैसे पता लगा सकते हैं" और न ही न्यूनतम संख्या में तर्क या एक विशेष रिटर्न प्रकार के बारे में कोई सवाल था। –

+0

हां, लेकिन 'enable_if' परवाह नहीं है कि क्या विशेषता 'remove_pointer' से बाहर या सीधे लागू की गई है या नहीं। –

4

फ़ंक्शन पॉइंटर या सदस्य फ़ंक्शन पॉइंटर को स्वीकार करने के लिए कोई SFINAE की आवश्यकता नहीं है। गैर-कॉल करने योग्य सामानों से फ़ंक्शन ऑब्जेक्ट्स को अलग करने के लिए SFINAE की आवश्यकता है, इसके आसपास शायद कोई रास्ता नहीं है।

#include <utility> 
#include <iostream> 

template <typename Ret, typename... Parm> 
void moo (Ret (*fp)(Parm...)) 
{ 
    std::cout << "funptr" << std::endl; 
} 

template <typename Ret, typename Owner, typename... Parm> 
void moo (Ret (Owner::*fp1)(Parm...)) 
{ 
    std::cout << "memfunptr" << std::endl; 
} 

template <typename Funobj, typename... Parm, 
      typename Ret = 
        decltype((std::declval<Funobj>()) 
          (std::forward(std::declval<Parm>())...))> 
void moo (Funobj functor) 
{ 
    std::cout << "funobj" << std::endl; 
} 

void x1() {} 
struct X2 { void x2() {} }; 
struct X3 { void operator()(){} }; 


int main() 
{ 
    moo(x1); 
    moo(&X2::x2); 
    moo(X3()); 
} 
संबंधित मुद्दे