在模板类型列表中交换两个元素。寻求最有效的算法

时间:2015-04-14 22:46:03

标签: c++ templates c++11

Swap<T, Position1, Position2, Pack>::type,其中Pack由T类型的元素组成,是返回包含Position1和Position2中的元素的包。我的解决方案不是最有效的。应该有一种方法可以非常干净地实现这一点,无需访问任何元素。有人能想到吗?

// ReplaceElement replaces the element of a pack with a specified position (0 being the first position) with a specified value.
template <typename T, std::size_t, std::size_t, T, typename, typename> struct ReplaceElementHelper;

template <typename T, std::size_t Position, std::size_t CurrentPosition, T NewValue, template <T...> class Z, T First, T... Rest, T... Accumulated>
struct ReplaceElementHelper<T, Position, CurrentPosition, NewValue, Z<First, Rest...>, Z<Accumulated...>>
    : ReplaceElementHelper<T, Position, CurrentPosition + 1, NewValue, Z<Rest...>, Z<Accumulated..., First>> {};

template <typename T, std::size_t Position, T NewValue, template <T...> class Z, T First, T... Rest, T... Accumulated>
struct ReplaceElementHelper<T, Position, Position, NewValue, Z<First, Rest...>, Z<Accumulated...>> {
    using type = Z<Accumulated..., NewValue, Rest...>;
};

template <typename T, std::size_t, T, typename> struct ReplaceElement;

template <typename T, std::size_t Position, T NewValue, template <T...> class Z, T... Ts>
struct ReplaceElement<T, Position, NewValue, Z<Ts...>> : ReplaceElementHelper<T, Position, 0, NewValue, Z<Ts...>, Z<>> {
    static_assert (Position < sizeof...(Ts), "Error!  Invalid position for ReplaceElement.");
};

// Swapping two elements of specified positions in a pack.
template <typename, std::size_t, std::size_t, typename> struct Swap;

template <typename T, std::size_t Position1, std::size_t Position2, template <T...> class Z, T... Ts>
struct Swap<T, Position1, Position2, Z<Ts...>> {
    static constexpr T a[sizeof...(Ts)] = {Ts...};
    using type = typename ReplaceElement<T, Position2, a[Position1], typename ReplaceElement<T, Position1, a[Position2], Z<Ts...>>::type>::type;
};

您可以告诉我的解决方案在Position1(或Position2)之前访问all两个元素。应该没有必要。我知道必须有一个避免这种情况的解决方案,但我无法想到它。

2 个答案:

答案 0 :(得分:6)

如果value_pack的定义有点像

template <typename T, T... v>
struct value_pack {
    static constexpr T array[] {v...};
    static constexpr std::size_t len = sizeof...(v);
    using type = value_pack;
};
template <typename T, T... v>
constexpr T value_pack<T, v...>::array[];

然后C ++ 14中的解决方案如下所示:

template <typename T, std::size_t p1, std::size_t p2,
          typename pack,
          typename=std::make_index_sequence<pack::len>>
struct Swap;
template <typename T, std::size_t p1, std::size_t p2,
          typename pack, std::size_t...indices>
struct Swap<T, p1, p2, pack, std::index_sequence<indices...>> :
    value_pack<T,  pack::array[indices==p1? p2 : indices==p2? p1 : indices]...> {};

Demo。如果C ++ 14标准库不可用,您可以自己实现make_index_sequence - 许多示例分散在SO中。

答案 1 :(得分:0)

我不确定,但是这个解决方案可能比Columbo的解决方案更快,因为它从包的前面开始并向右移动并在Position2处停止而不访问Position2之后的任何元素(我认为这是它可以采取的最短路线):

#include <iostream>
#include <type_traits>

template <typename, std::size_t, std::size_t, typename> struct Swap;
template <typename, std::size_t, std::size_t, typename, typename, typename> struct SwapHelper;

template <typename T, std::size_t Position1, std::size_t Position2, template <T...> class Z, T First, T... Rest, T... Head, T... Middle>
struct SwapHelper<T, Position1, Position2, Z<First, Rest...>, Z<Head...>, Z<Middle...>> :
    SwapHelper<T, Position1 - 1, Position2 - 1, Z<Rest...>, Z<Head..., First>, Z<Middle...>> {};

template <typename T, std::size_t Position2, template <T...> class Z, T First, T... Rest, T... Head, T... Middle>
struct SwapHelper<T, 0, Position2, Z<First, Rest...>, Z<Head...>, Z<Middle...>> :
    SwapHelper<T, 0, Position2 - 1, Z<Rest...>, Z<Head...>, Z<Middle..., First>> {};

template <typename T, template <T...> class Z, T First, T... Rest, T... Head, T FirstOfMiddle, T... Middle>
struct SwapHelper<T, 0, 0, Z<First, Rest...>, Z<Head...>, Z<FirstOfMiddle, Middle...>> {
    using type = Z<Head..., First, Middle..., FirstOfMiddle, Rest...>;
};

template <typename T, std::size_t Position1, std::size_t Position2, template <T...> class Z, T... Ts>
struct Swap<T, Position1, Position2, Z<Ts...>> : std::conditional<(Position1 < Position2),
        SwapHelper<T, Position1, Position2, Z<Ts...>, Z<>, Z<>>,
        SwapHelper<T, Position2, Position1, Z<Ts...>, Z<>, Z<>>
    >::type {};

// Testing
template <int...> struct Sequence;

int main() {
    std::cout << std::boolalpha << std::is_same<
        typename Swap<int, 2, 5, Sequence<0,2,4,6,8,10,12>>::type,
        Sequence<0,2,10,6,8,4,12>
    >::value << std::endl;  // true

    std::cout << std::boolalpha << std::is_same<
        typename Swap<int, 5, 2, Sequence<0,2,4,6,8,10,12>>::type,
        Sequence<0,2,10,6,8,4,12>
    >::value << std::endl;  // true
}

如何对两个编译时进程进行基准测试?