Sure. Wrote this:
template<int...> struct seq {};
template<typename seq> struct seq_len;
template<int s0,int...s>
struct seq_len<seq<s0,s...>>:
std::integral_constant<std::size_t,seq_len<seq<s...>>::value> {};
template<>
struct seq_len<seq<>>:std::integral_constant<std::size_t,0> {};
template<int Min, int Max, int... s>
struct make_seq: make_seq<Min, Max-1, Max-1, s...> {};
template<int Min, int... s>
struct make_seq<Min, Min, s...> {
typedef seq<s...> type;
};
template<int Max, int Min=0>
using MakeSeq = typename make_seq<Min,Max>::type;
template<std::size_t src, typename T, int... indexes>
std::array<T, sizeof...(indexes)> get_elements( seq<indexes...>, std::array<T, src > const& inp ) {
return { inp[indexes]... };
}
template<int len, typename T, std::size_t src>
auto first_elements( std::array<T, src > const& inp )
-> decltype( get_elements( MakeSeq<len>{}, inp ) )
{
return get_elements( MakeSeq<len>{}, inp );
}
Where the compile time indexes...
does the remapping, and MakeSeq makes a seq from 0 to n-1.
Live example.
Updated to more recent versions of C++:
template<class Seq, std::size_t N>
struct add_to_seq;
template<class Seq, std::size_t N>
using add_to_seq_t = typename add_to_seq<Seq, N>::type;
template<std::size_t...Is, std::size_t N>
struct add_to_seq<std::index_sequence<Is...>, N>
{
using type=std::index_sequence<(Is+N)...>;
};
template<std::size_t Min, std::size_t Max>
struct make_seq {
using type=add_to_seq_t< std::make_index_sequence<Max-Min>, Min >;
};
template<std::size_t Min, std::size_t Max>
using make_seq_t = typename make_seq<Min,Max>::type;
template<std::size_t src, typename T, std::size_t... indexes>
std::array<T, sizeof...(indexes)> get_elements( std::index_sequence<indexes...>, std::array<T, src> const& inp ) {
return { inp[indexes]... };
}
template<std::size_t len, typename T, std::size_t src>
auto first_elements( std::array<T, src> const& inp )
{
return get_elements( std::make_index_sequence<len>{}, inp );
}
Live example.
(The more modern version generates O(n) total compile time template types - the older version was O(n^2) in compile time template generation. This means a faster compile and less likely to hit compiler resource limits.)
This supports both an arbitrary set of indexes (via get_elements
) and the first n (via first_elements
).
Use:
std::array< int, 10 > arr = {0,1,2,3,4,5,6,7,8,9};
std::array< int, 6 > slice = get_elements(arr, seq<2,0,7,3,1,0>() );
std::array< int, 5 > start = first_elements<5>(arr);
which avoids all loops, either explicit or implicit.