Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swapping two types in a type list

For simplicity, let's use std::tuple as our type list.

What is the best (concise, least recursive, etc.) way to swap two types in a std::tuple?

Illustration of the functionality through the use of indices:

#include <tuple>

int main()
{
    using tuple_t = std::tuple<int, void, double>;          // int, void, double
    using swapped_tuple_t = std::tuple<double, void, int>;  // double, void, int
    static_assert( std::is_same<swap<0, 2, tuple_t>::type, swapped_tuple_t>::value, "!" );
}
like image 424
user2296177 Avatar asked Nov 22 '15 20:11

user2296177


People also ask

How do you switch two values in a list in Python?

To swap two list elements x and y by value, get the index of their first occurrences using the list. index(x) and list. index(y) methods and assign the result to variables i and j , respectively. Then apply the multiple assignment expression lst[i], lst[j] = lst[j], lst[i] to swap the elements.

Can you swap items in a list Python?

Given a list in Python and provided the positions of the elements, write a program to swap the two elements in the list. Since the positions of the elements are known, we can simply swap the positions of the elements.

How do you swap two elements in an array?

A far better method you can use to swap array elements is destructuring, as it does the job in only one line of code. You just create a new array containing both elements in a particular order, then assign it to a new array that contains both elements in the reversed order.


2 Answers

#include <tuple>
#include <utility>
#include <cstddef>

template <std::size_t I
        , std::size_t J
        , typename T
        , typename = std::make_index_sequence<I>
        , typename = std::make_index_sequence<J - I - 1>
        , 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
        , std::size_t... Bs
        , std::size_t... 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...>;
};

DEMO


For cases where J can be lower than or equal to I, use the below trait:

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;
};

DEMO 2

like image 96
Piotr Skotnicki Avatar answered Oct 24 '22 09:10

Piotr Skotnicki


There's no reason to use three sequences. One is enough:

template <std::size_t I
        , std::size_t J
        , typename T
        , typename = std::make_index_sequence<std::tuple_size<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> {};

And now there's also no need to special-case the I >= J case.

Demo.

like image 26
T.C. Avatar answered Oct 24 '22 09:10

T.C.