Переключение двух типов в список типов

Для простоты используйте std::tuple как наш список типов.

Каков наилучший (сжатый, наименее рекурсивный и т.д.) способ замены двух типов в std::tuple?

Иллюстрация функциональности с использованием индексов:

#include <tuple>
int main()
{
 using tuple_t = std::tuple<int, void,="" ******="">; // int, void, ******
 using swapped_tuple_t = std::tuple<******, void,="" int="">; // ******, void, int
 static_assert( std::is_same<swap<0, 2,="" tuple_t="">::type, swapped_tuple_t>::value, "!" );
}
</swap<0,></******,></int,></tuple>
3 ответа

#include <tuple>
#include <utility>
#include <cstddef>
template <std::size_t i="" ,="" std::size_t="" j="" typename="" t="">
 , typename = std::make_index_sequence<j 1="" -="" i="">
 , typename = std::make_index_sequence<std::tuple_size<t>::value - J - 1>>
struct swap;
template <std::size_t i="" ,="" std::size_t="" j="" typename="" t="" std::size_t...="" as="" bs="" cs="">
struct swap<i, j,="" t="" ,="" std::index_sequence<as...="">
 , std::index_sequence<bs...>
 , std::index_sequence<cs...>
 >
{
 using type = std::tuple<typename std::tuple_element<as,="" t="">::type...
 , typename std::tuple_element<j, t="">::type
 , typename std::tuple_element<bs +="" i="" 1,="" t="">::type...
 , typename std::tuple_element<i, t="">::type
 , typename std::tuple_element<cs +="" j="" 1,="" t="">::type...>;
};
</cs></i,></bs></j,></typename></cs...></bs...></i,></std::size_t></std::tuple_size<t></j></std::size_t></cstddef></utility></tuple>

DEMO

В случаях, когда J может быть ниже или равно I, используйте следующую характеристику:

template <std::size_t i,="" std::size_t="" j,="" typename="" t="">
struct swap : swap_impl<i<j?i:j, i<j?j:i,="" t=""> {};
template <std::size_t i,="" typename="" t="">
struct swap<i,i,t>
{
 using type = T;
};
</i,i,t></std::size_t></i<j?i:j,></std::size_t>

DEMO 2


Нет причин использовать три последовательности. Одного достаточно:

template <std::size_t i="" ,="" std::size_t="" j="" typename="" t="">::value>>
struct swap_impl;
template <std::size_t i="" ,="" std::size_t="" j="" typename="" t="" std::size_t...="" as="">
struct swap_impl<i, j,="" t="" ,="" std::index_sequence<as...="">
 >
{
 using type = std::tuple<std::tuple_element_t<as =="I" ?="" j="" :="" as="=" j?="" i="" as,="" t="">... >;
};
template <std::size_t i,="" std::size_t="" j,="" typename="" t="">
struct swap : swap_impl<i, j,="" t=""> {};
</i,></std::size_t></std::tuple_element_t<as></i,></std::size_t></std::size_t>

И теперь также нет необходимости в специальном случае я >= J.

Демо.


Я выбрасываю альтернативу (но я думаю, что решение @Piotr будет более элегантным).

template <size_t ...="">
struct seq { };
// X, Y are the indeces we want to swap
template <size_t n,="" size_t="" x,="" y,="" ...s="">
struct gen : gen<n-1, x,="" y,="" (n-1="=" x="" ?="" y="" :="" n="" -="" 1)),="" s...=""> { };
template <size_t x,="" size_t="" y,="" ...s="">
struct gen<0, X, Y, S...> {
 typedef seq<s...> type;
};
// X and Y are the index we want to swap, T is the tuple
template <size_t x,="" size_t="" y,="" t,="" s="">
struct swapImpl;
template <size_t x,="" size_t="" y,="" t,="" size_t...="" s="">
struct swapImpl<x, y,="" t,="" seq<s...="">>{
 using type = std::tuple<typename std::tuple_element<s,="" t="">::type...>;
};
template <size_t x,="" size_t="" y,="" t="">
struct swap {
 using type = typename swapImpl<x, y,="" t,="" typename="" gen<std::tuple_size<t="">::value, X, Y>::type>::type;
};
int main() {
 using tuple_t = std::tuple<int, unsigned,="" void,="" char,="" ******="">; // int, void, ******
 using swapped_tuple_a_t = std::tuple<unsigned, int,="" void,="" char,="" ******="">; // ******, void, int
 static_assert( std::is_same<swap<0, 1,="" tuple_t="">::type, swapped_tuple_a_t>::value, "!" );
 static_assert( std::is_same<swap<1, 0,="" tuple_t="">::type, swapped_tuple_a_t>::value, "!" );
 using swapped_tuple_b_t = std::tuple<int, char,="" void,="" unsigned,="" ******="">; // ******, void, int
 static_assert( std::is_same<swap<1, 3,="" tuple_t="">::type, swapped_tuple_b_t>::value, "!" );
 static_assert( std::is_same<swap<3, 1,="" tuple_t="">::type, swapped_tuple_b_t>::value, "!" );
}
</swap<3,></swap<1,></int,></swap<1,></swap<0,></unsigned,></int,></x,></size_t></typename></x,></size_t></size_t></s...></size_t></n-1,></size_t></size_t>

licensed under cc by-sa 3.0 with attribution.