Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swap two parameters in variadic template

I'm trying to swap two items of a parameter pack.

Ideally, I would like to do something like this:

template<int i1, int i2, class... Args>
void swapped_copy(some_class a, some_class b, Args... args) {
    a(args...) = b(/* 'args...' where parameters with indices i1 and i2 are swapped */);
}

Any idea?

Many thanks.

like image 565
Limmershin Avatar asked Sep 07 '17 23:09

Limmershin


1 Answers

You can use a std::tuple to pack the args and unpack by index, and a std::index_sequence to generate the indexes to use. Then it's just a matter of doing the swap on indices. Something like this:

namespace swapped_copy_detail {
    constexpr std::size_t swap_one_index(
        std::size_t i1, std::size_t i2, std::size_t index) {
        return index==i1 ? i2 : (index==i2 ? i1 : index);
    }

    template <std::size_t i1, std::size_t i2, class Tuple, std::size_t... Inds>
    void do_swapped_copy(
        some_class& a, some_class& b,
        Tuple&& args,
        std::index_sequence<Inds...> inds ) {
        a(std::get<Inds>(args)...) =
            b(std::get<swap_one_index(i1, i2, Inds)>(args)...);
    }
}

template <std::size_t i1, std::size_t i2, class ...Args>
void swapped_copy(some_class a, some_class b, const Args& ...args) {
    static_assert(i1 < sizeof...(Args) && i2 < sizeof...(Args),
                  "Index too large for swapped_copy");
    swapped_copy_detail::do_swapped_copy<i1, i2>(
        a, b, std::tie(args...),
        std::index_sequence_for<Args...>());
}

index_sequence and index_sequence_for are in the C++14 Standard, but your question is tagged [c++11]. If you need to stick with C++11, implementations of these utilities can be found in this answer, for one place.

like image 54
aschepler Avatar answered Oct 20 '22 04:10

aschepler