`std::enable_if` is function pointer - how?

前端 未结 2 1470
误落风尘
误落风尘 2020-12-31 11:58

I want to use SFINAE to enable a particular template if the user passes a function pointer as a parameter.

I have googled around but found nothing - I also

相关标签:
2条回答
  • 2020-12-31 12:12

    Below is a type trait determining if something is a function pointer and a couple of test cases. Note, that to test if something is a function pointer, you need to test if std::is_pointer<P>::value is true and if std::is_function<T>::value is true where T is P with the pointer removed. The code below just does that:

    #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 讨论(0)
  • 2020-12-31 12:21

    No SFINAE is needed to accept a function pointer or a member function pointer. To distinguish function objects from non-callable stuff SFINAE is needed, there's probably no way around this.

    #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());
    }
    
    0 讨论(0)
提交回复
热议问题