Call function with part of variadic arguments

前端 未结 4 751
傲寒
傲寒 2021-01-22 10:42

Consider I have the following:

void bar(int a, int b)
{
}   

template
void foo(F function, Args... args>
{
    function(a         


        
相关标签:
4条回答
  • 2021-01-22 11:12

    Here is a solution that will work with anything std::invoke accepts, that invokes the overload with the fewest possible arguments.

    template <typename F, typename Args, std::size_t... In>
    decltype(auto) invoke_front_impl(F&& f, Args&& args, std::index_sequence<In...>)
    {
        if constexpr (std::is_invocable_v<F&&, std::tuple_element_t<In, Args>...>) {
            return std::invoke(std::forward<F>(f), std::get<In>(std::move(args))...);
        } else {
            return invoke_front_impl(
                std::forward<F>(f),
                std::move(args),
                std::make_index_sequence<sizeof...(In) + 1>());
        }
    }
    
    template <typename F, typename... Args>
    decltype(auto) invoke_front(F&& f, Args&&... args)
    {
        return invoke_front_impl(
            std::forward<F>(f),
            std::forward_as_tuple(std::forward<Args>(args)...),
            std::make_index_sequence<0>());
    }
    

    Demo on Wandbox

    0 讨论(0)
  • 2021-01-22 11:15

    First, use the following code that lets you find the arity of a lambda or function reference:

    template <typename T>
    struct function_traits : public function_traits<decltype(&T::operator())>
    {};
    
    template <typename ClassType, typename ReturnType, typename... Args>
    struct function_traits<ReturnType(ClassType::*)(Args...) const>
    {
        using result_type = ReturnType;
        using arg_tuple = std::tuple<Args...>;
        static constexpr auto arity = sizeof...(Args);
    };
    
    template <typename R, typename ... Args>
    struct function_traits<R(&)(Args...)>
    {
        using result_type = R;
        using arg_tuple = std::tuple<Args...>;
        static constexpr auto arity = sizeof...(Args);
    };
    

    Next, you forward the variadic arguments along using a tuple pack, and you only expand out to the arity of the function:

    template<typename F, std::size_t... Is, class T>
    void foo_impl(F && f, std::index_sequence<Is...>, T && tuple) {
        std::forward<F>(f)(std::get<Is>(tuple)...);
    }
    
    template<typename F, typename... Args>
    void foo(F && f, Args&&... args) {
        foo_impl(std::forward<F>(f),
                 std::make_index_sequence<function_traits<F>::arity>{},
                 std::forward_as_tuple(args...) );
    }
    

    Live example: http://coliru.stacked-crooked.com/a/3ca5df7b55c427b8.

    0 讨论(0)
  • 2021-01-22 11:25

    First, we need a function to retrieve the number or arguments the function requires. This is done using function_traits:

    template <class F>
    constexpr std::size_t nb_args() {
       return utils::function_traits<F>::arity;
    }
    

    And with the help of std::index_sequence, we only dispatch the nb_args<F>() first arguments:

    template<typename F, std::size_t... Is, class Tup>
    void foo_impl(F && f, std::index_sequence<Is...>, Tup && tup) {
        std::forward<F>(f)( std::get<Is>(tup)... );
    }
    
    template<typename F, typename... Args>
    void foo(F && f, Args&&... args) {
        foo_impl(std::forward<F>(f),
                 std::make_index_sequence<nb_args<F>()>{},
                 std::forward_as_tuple(args...) );
    }
    

    Demo

    0 讨论(0)
  • 2021-01-22 11:37

    Trivial and hardly extensible solution would be to create a wrapper, that will be called with all arguments, but will use only first few of them.

    template<typename F, typename... Args>
    void foo(F function, Args... args)
    {
        // with proper forwarding if needed
        auto lambda = [](auto fnc, auto first, auto second, auto...)
        {
            fnc(first, second);
        };
        lambda(function, args...);
    }
    
    0 讨论(0)
提交回复
热议问题