Passing std::array as arguments of template variadic function

前端 未结 2 1120
旧时难觅i
旧时难觅i 2020-12-16 20:29

I am trying to learn about variadic templates in C++11. I have a class which is basically a wrapper around a std::array. I want to be able to pass function obje

相关标签:
2条回答
  • 2020-12-16 20:52

    You can use this utility template to create a sequence of indices at compile time:

    template< std::size_t... Ns >
    struct indices {
        typedef indices< Ns..., sizeof...( Ns ) > next;
    };
    
    template< std::size_t N >
    struct make_indices {
        typedef typename make_indices< N - 1 >::type::next type;
    };
    
    template<>
    struct make_indices< 0 > {
        typedef indices<> type;
    };
    

    Then make a caller function that takes indices as a parameter so you got a way of deducing the indices sequence:

    template<typename... Ts, size_t...Is>
    void call(std::function<void(Ts...)>&& func, indices<Is...>)
    {
        func( data[Is]... );
    }
    

    And then you can call it like this:

    template< typename... Ts>
    void doOperation( std::function<void(Ts...)>&& func )
    {
        static_assert(sizeof...(Ts)==N,"Size of variadic template args does not match array length");
        call( std::forward<std::function<void(Ts...)>>(func), typename  make_indices<N>::type() );
    }
    
    0 讨论(0)
  • 2020-12-16 21:10

    Given the well-known indices infrastructure:

    namespace detail
    {
        template<int... Is>
        struct seq { };
    
        template<int N, int... Is>
        struct gen_seq : gen_seq<N - 1, N - 1, Is...> { };
    
        template<int... Is>
        struct gen_seq<0, Is...> : seq<Is...> { };
    }
    

    You could redefine your class template this way:

    template<int N, typename T>
    struct Container {
        template<typename... Ts>
        Container(Ts&&... vs) : data{{std::forward<Ts>(vs)...}} {
            static_assert(sizeof...(Ts)==N,"Not enough args supplied!");
        }
    
        template<typename F>
        void doOperation(F&& func)
        {
            doOperation(std::forward<F>(func), detail::gen_seq<N>());
        }
    
        template<typename F, int... Is>
        void doOperation(F&& func, detail::seq<Is...>)
        {
            (std::forward<F>(func))(data[Is]...);
        }
    
        std::array<T,N> data;
    };
    

    Here is a live example.

    Notice, that you do not need to construct an std::function object in main(): the std::function can be implicitly constructed from the lambda. However, you do not even need to use std::function at all here, possibly incurring in an unnecessary run-time overhead.

    In the solution above, I just let the type of the callable object to be a template parameter that can be deduced by the compiler.

    0 讨论(0)
提交回复
热议问题