Using std::tuple<>
as my type list, I would like to be able to have a template:
template<std::size_t i_src, std::size_t i_dst, class Tuple>
struct tuple_shift
{
// implementation
};
A contained type
alias would return the shifted type list so that the following example compiles:
// move type at i_src to i_dst and shift the types
// i_src = 1, i_dst = 3 : right to left shift
using tuple_t = std::tuple<int, char, long, double, float>; // before
using expected_tuple_t = std::tuple<int, long, double, char, float>; // after
using result_tuple_t = tuple_shift<1, 3, tuple_t>::type; // actual result
static_assert( std::is_same<expected_tuple_t, result_tuple_t>::value, "!" );
Sample use case: stable sort of a type list.
Here's my solution, which is in another galaxy in terms of conciseness when compared to TC's solution, but it avoids having to make comparisons for every index; it depends on template deduction to work.
This is actually a partial solution; the full solution is specialized to expand the sequence correctly when i_src == i_dst
or i_dst < i_src
. It works by generating the index sequences and then merging it all into one.
For i_src = 1, i_dst = 3
, where the sequence is <0, 1, 2, 3, 4>
, the following is generated (in pseudo-code):
left_index_seq = <0>
shifted_index_seq = <2, 3>
right_index_seq = <4>
Which is then expanded to:
sequence = <left_index_seq, shifted_index_seq, i_src, right_index_seq>
= <<0>, <2, 3>, 1, <4>>
= <0, 2, 3, 1, 4>
Implementation
#include <tuple>
#include <utility>
template<std::size_t offset, class IndexSequence>
struct index_sequence_offset;
template<std::size_t offset, std::size_t... Is>
struct index_sequence_offset<offset, std::index_sequence<Is...>>
{
using type = std::index_sequence<( offset + Is )...>;
};
template<std::size_t offset, class IndexSequence>
using make_index_sequence_offset = typename index_sequence_offset
<
offset, IndexSequence
>::type;
template<class IndexSequence>
struct index_sequence_size;
template<std::size_t... Is>
struct index_sequence_size<std::index_sequence<Is...>>
: std::integral_constant<std::size_t, sizeof...( Is )>
{};
template<std::size_t i_src, std::size_t i_dst, class Tuple>
struct tuple_shift_indices
{
private:
template<class LIPack, class SIPack, class RIPack>
struct tuple_shift_indices_impl;
template<std::size_t... l_is, std::size_t... s_is, std::size_t... r_is>
struct tuple_shift_indices_impl
<
std::index_sequence<l_is...>,
std::index_sequence<s_is...>,
std::index_sequence<r_is...>
>
{
using type = std::index_sequence<l_is..., s_is..., i_src, r_is...>;
};
public:
using type = typename tuple_shift_indices_impl
<
std::make_index_sequence<i_src>,
make_index_sequence_offset<i_src + 1, std::make_index_sequence<i_dst - i_src>>,
make_index_sequence_offset<std::tuple_size<Tuple>::value - 1, std::make_index_sequence<i_dst - i_src - 1>>
>::type;
};
template<std::size_t i_src, std::size_t i_dst, class Tuple>
struct tuple_shift
{
private:
template<class IndexSequence>
struct tuple_shift_impl;
template<std::size_t... is>
struct tuple_shift_impl<std::index_sequence<is...>>
{
using type = std::tuple<std::tuple_element_t<is, Tuple>...>;
};
public:
using type = typename tuple_shift_impl
<
typename tuple_shift_indices<i_src, i_dst, Tuple>::type
>::type;
};
Aucun commentaire:
Enregistrer un commentaire