Passing (partially) templated template function as std::function(or function pointer)

后端 未结 1 1782
悲&欢浪女
悲&欢浪女 2020-12-20 16:54
#include 
#include 

template
class Foo
{
public:
    template          


        
相关标签:
1条回答
  • 2020-12-20 17:17

    For error 1, what's happening is that the compiler is attempting to substitute for T in std::function, but it cannot because ultimately a function pointer and a std::function are different types, and there's no conversion defined for a function pointer to std::function

    This worked:

    std::function<double(std::vector<int>)> barz = bar<int, double>
    

    Because std::function was cleverly written with type-erasure to have a constructor that can accept any callable that is convertible to the type it needs. Note that this isn't the same as type-deduction in the above error because here we are already specifying the template arguments for std::function.

    Note that we can do a little work to get Foo::std_function to work properly. First change its signature to take a forwarding reference:

    template <class T>
    void std_function(T&& functor){/*I'll talk about this in a bit*\}
    

    Then we can construct our std::function internally (What you're looking to pass into it, I don't know) by using some helper structs to determine its type. For a function pointer we can do the following:

    // base
    template<class... T>
    struct function_type_impl;
    
    // specialization for function ptrs and static class fns
    template<class Ret, class... Args>
    struct function_type_impl<Ret(*)(Args...)>
    {
       using type = std::function<Ret(Args...)>;
    };
    
    // type alias so we don't need to keep typing typename ... ::type
    template<class... T>
    using function_type = typename function_type_impl<std::decay_t<T>...>::type;
    

    and then we can modify our std_function signature:

    template <class T>
    void std_function(T&& functor)
    {
        function_type<T> myFunction = std::forward<T>(functor);
        // do something with our std::function
    }
    

    Then you can call it as

    test.std_function(&::bar<int, double>);
    

    However, if we want to be more complete, and accept functors, lambdas, and even other std::functions, we can add more specializations:

    namespace detail
    {
    template<class... T>
    struct function_type_impl;
    
    template<class Callable>
    struct function_type_impl<Callable>
    {
        using type = typename function_type_impl<decltype(&Callable::operator())>::type;
    };
    
    template<class C, class Ret, class... Args>
    struct function_type_impl<Ret(C::*)(Args...) const>
    {
        using type = std::function<Ret(Args...)>;
    };
    
    template<class Ret, class... Args>
    struct function_type_impl<Ret(*)(Args...)>
    {
        using type = std::function<Ret(Args...)>;
    };
    
    template<class... T>
    using function_type = typename function_type_impl<std::decay_t<T>...>::type;
    }// detail namespace
    

    And now the following will work, too:

    struct MyFunctor
    {
        double operator()(std::vector<int>) const
        {
            return 42;
        }
    };
    
    struct MyFunctor2
    {
        static double foo(std::vector<int>)
        {
            return 42;
        }
    };
    
    int main()
    {
        Foo<double> test;
        std::function<double(std::vector<int>)> barz = bar<int, double>;
        test.std_function(&::bar<int, double>);
        test.std_function(barz);
        test.std_function([](std::vector<int>)->double{return 42;});
        test.std_function(MyFunctor{});
        test.std_function(MyFunctor2::foo);
    }
    

    Live Demo

    For errors 2::1 and 2::2, the issue is simpler; functions do not exist at all until they're completely instantiated. That is, you cannot create a function pointer to a partially templated function. You have to specify all the template arguments when trying to get a function pointer. Since you have already specified the return type, you can allow the compiler to instantiate the rest of the pointer for you if you explicitly tell func_ptr what to deduce for T:

    test.func_ptr<int>(bar); 
    
    0 讨论(0)
提交回复
热议问题