Get argument type of template callable object

后端 未结 4 1536
不知归路
不知归路 2020-12-09 04:33

Consider the following function:

template
void register_handler( F& f ) // any callable object
{
   // find out T - the argument type of f         


        
相关标签:
4条回答
  • 2020-12-09 04:52

    Assuming F is any callable type, you cannot get its argument type. Consider this:

    struct callable
    {
        void operator() (int);
        void operator() (float *);
        void operator() (std::string const &);
        void operator() (std::list<int> &);
    };
    

    the type of argument is an ambiguity here.

    0 讨论(0)
  • 2020-12-09 04:52

    This blogpost shows how to implement some function type traits. These should work with everything callable (exception: polymorphic functors :P). You could iterate over the arguments, and use their type to do some sfinae or as a additional template argument.

    Function traits as copied from blogpost:

    #include <tuple>
    
    // as seen on http://functionalcpp.wordpress.com/2013/08/05/function-traits/
    template<class F>
    struct function_traits;
    
    // function pointer
    template<class R, class... Args>
    struct function_traits<R(*)(Args...)> : public function_traits<R(Args...)>
    {};
    
    template<class R, class... Args>
    struct function_traits<R(Args...)>
    {
        using return_type = R;
    
        static constexpr std::size_t arity = sizeof...(Args);
    
        template <std::size_t N>
        struct argument
        {
            static_assert(N < arity, "error: invalid parameter index.");
            using type = typename std::tuple_element<N,std::tuple<Args...>>::type;
        };
    };
    
    // member function pointer
    template<class C, class R, class... Args>
    struct function_traits<R(C::*)(Args...)> : public function_traits<R(C&,Args...)>
    {};
    
    // const member function pointer
    template<class C, class R, class... Args>
    struct function_traits<R(C::*)(Args...) const> : public function_traits<R(C&,Args...)>
    {};
    
    // member object pointer
    template<class C, class R>
    struct function_traits<R(C::*)> : public function_traits<R(C&)>
    {};
    
    // functor
    template<class F>
    struct function_traits
    {
        private:
            using call_type = function_traits<decltype(&F::operator())>;
        public:
            using return_type = typename call_type::return_type;
    
            static constexpr std::size_t arity = call_type::arity - 1;
    
            template <std::size_t N>
            struct argument
            {
                static_assert(N < arity, "error: invalid parameter index.");
                using type = typename call_type::template argument<N+1>::type;
            };
    };
    
    template<class F>
    struct function_traits<F&> : public function_traits<F>
    {};
    
    template<class F>
    struct function_traits<F&&> : public function_traits<F>
    {};
    

    Testcode:

    #include <iostream>
    
    class A
    {
    };
    
    template <class T>
    struct Functor
    {
      void operator()(const T& t)
      {}
    };
    
    struct Register
    {
      //int parameters
      template <class T>
      static void RegisterFunctor(const T& /*functor*/, typename std::enable_if<std::is_same<typename function_traits<T>::template argument<0>::type, const int&>::value>::type* = 0)
      {
        std::cout << "Register int func" << std::endl;
      }
    
      //A parameters
      template <class T>
      static void RegisterFunctor(const T& /*functor*/, typename std::enable_if<std::is_same<typename function_traits<T>::template argument<0>::type, const A&>::value>::type* = 0)
      {
        std::cout << "Register int func" << std::endl;
      }
    };
    
    void intFunc(const int&) {}
    void aFunc(const A&){}
    
    int main(int /*argc*/, char */*argv*/[])
    {
      Functor<int> intFunctor;
      Functor<A> aFunctor;
    
      Register::RegisterFunctor(intFunctor);
      Register::RegisterFunctor(&intFunc);
      Register::RegisterFunctor(aFunctor);
      Register::RegisterFunctor(&aFunc);
      return 0;
    }
    
    0 讨论(0)
  • 2020-12-09 04:54

    if F is a std::functionyou should be able to use the its member type and check with `std::is_same':

    template<class F>
    void register_handler( F& f ) // any callable object
    {
       // find out T - the argument type of f
       if(std::is_same<int, F::argument_type>::value)
       { .... }
       //etc .....
    
    }
    

    An up and running example here

    but that kind of code can quickly become a mess to maintain.

    0 讨论(0)
  • 2020-12-09 05:01

    You could use sfinae and test if your argument is convertible to a std::function with the required arguments:

    #include <type_traits>
    #include <functional>
    #include <iostream>
    
    class A
    {
    };
    
    template <class T>
    struct Functor
    {
      void operator()(const T& t)
      {}
    };
    
    struct Register
    {
      //int parameters
      template <class T>
      static void RegisterFunctor(const T& /*functor*/, typename std::enable_if<std::is_constructible<typename std::function<void (int)>, T>::value >::type* = 0)
      {
        std::cout << "Register int func" << std::endl;
      }
    
      //A parameters
      template <class T>
      static void RegisterFunctor(const T& /*functor*/, typename std::enable_if<std::is_constructible<typename std::function<void (A)>, T>::value >::type* = 0)
      {
        std::cout << "Register a func" << std::endl;
      }
    };
    
    void intFunc(int) {}
    void aFunc(A){}
    
    int main(int /*argc*/, char */*argv*/[])
    {
      Functor<int> intFunctor;
      Functor<A> aFunctor;
    
      Register::RegisterFunctor(intFunctor);
      Register::RegisterFunctor(&intFunc);
      Register::RegisterFunctor(aFunctor);
      Register::RegisterFunctor(&aFunc);
      return 0;
    }
    
    0 讨论(0)
提交回复
热议问题