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
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() );
}
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.