2013-09-06 1 views
9

사용자가 함수 포인터을 매개 변수로 전달한 경우 특정 템플릿을 사용하려면 SFINAE를 사용하고 싶습니다.`std :: enable_if`는 함수 포인터입니다 - 어떻게?

나는 봤지만 아무 것도 발견하지 못했습니다. 또한 <type_traits> 설명서를 보았지만 is_function_ptr<T>과 비슷한 것을 찾을 수 없었습니다.

함수 포인터는 TReturn(*)(TArgs...)과 같은 전역 함수 포인터를 의미합니다.

+0

is_function과 is_pointer를 모두 확인할 수 있습니까? –

+0

왜 SFINAE인가? 여기에는 과도한 행동이 있습니다. –

+0

왜 간단한 f (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' 함수 템플릿과 nm의 대답 에서처럼 쉽게 특성을 만들 수 있습니까? 그리고 그것은 훨씬 더 강력합니다 (매개 변수의 최소 수 또는 특정 반환 유형을 요구할 수 있음). –

+0

@BenVoigt : 예. 그러나 질문은 "n.m. 솔루션에 기반한 함수 포인터가있는 경우 어떻게 감지 할 수 있습니까?"또는 최소 인수 수 또는 특정 반환 유형에 대한 질문이 없었습니다. –

+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()); 
}