2013-09-06 15 views
9

ユーザーが関数ポインタをパラメータとして渡した場合、特定のテンプレートを有効にするにはSFINAEを使用します。`std :: enable_if`は関数ポインタです - どうですか?

Google検索でも何も見つかりませんでした。また、<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()); 
} 
関連する問題