Sometimes I want to reverse the values in an index_sequence
and use the result to reverse the values in something tuple-like, like in this illustration which reverses the values in a constexpr
std::array
at compile time.
#include <array>
#include <cstdint>
#include <utility>
namespace detail {
template <class T, std::size_t N, std::size_t... I>
constexpr std::array<T, N> rev_arr_helper(const std::array<T, N>& arr,
std::index_sequence<I...>) {
return {arr[sizeof...(I) - I - 1]...};
// {arr[4-0-1], arr[4-1-1], arr[4-2-1], arr[4-3-1]}
// =>
// {arr[3], arr[2], arr[1], arr[0]}
}
} // namespace detail
template <class T, std::size_t N>
constexpr std::array<T, N> rev_arr(const std::array<T, N>& arr) {
return detail::rev_arr_helper(arr, std::make_index_sequence<N>{});
}
int main() {
constexpr std::array<int, 4> arr{11, 22, 33, 44};
constexpr auto rev = rev_arr(arr);
static_assert(rev[0] == 44 && rev[1] == 33 && rev[2] == 22 && rev[3] == 11, "");
}
Now, this approach does not work for any integer_sequence
, like the one in the title. It only works for those ordered 0, 1, 2, ..., N-1
and I would like to be able to make this compile using C 14:
#include <type_traits>
#include <utility>
int main() {
std::integer_sequence<int, 4, -5, 7, -3> iseq;
std::integer_sequence<int, -3, 7, -5, 4> itarget;
auto irev = reverse_sequence(iseq);
static_assert(std::is_same<decltype(irev), decltype(itarget)>::value, "");
}
How can that be done?
Here's somewhat related Q&A collected from the comments:
How do I reverse the order of element types in a tuple type?
CodePudding user response:
One solution is to create a std::index_sequence
to be able to simulate using the subscript operator to access the values in your integer_sequence
. By putting the sequence of integers, I...
, in a std::tuple
one can use std::get<>
to extract the value at a certain position in the tuple
. We want something similar to I[pos]...
(had it worked) which is what we get with:
std::get<pos>( std::tuple<decltype(I)...>{I...} )...
- Sidenote:
<decltype(I)...>
above is needed to make it work in C 14. In C 17 and later, one can simply do:std::get<pos>( std::tuple{I...} )...
Putting that in place makes it very similar to reversing the elements in an array:
#include <cstddef>
#include <tuple>
#include <utility>
namespace detail {
template <class T, T... I, std::size_t... J>
constexpr auto rev_helper(std::integer_sequence<T, I...>, std::index_sequence<J...>)
{
return
std::integer_sequence<T,
std::get<sizeof...(J) - J - 1>(std::tuple<decltype(I)...>{I...})...>{};
//