InsertTypes<Pack, P<Ts...>, Is...>::type
— это Pack с типами Ts...
, вставленными в позиции Is...
соответственно. Например,
InsertTypes<Pack<int, double, char, long, int>, Pack<short, float, std::string>, 2,4,1>::type,
is
Pack<int, std::string, double, short, char, long, float, int
(short вставляется между double и char, float вставляется между long и int, а std::string вставляется между int и double).
Мой метод: сначала отсортируйте Is...
в обратном порядке (от большего к меньшему) и примените Insert для каждого типа в Ts...
и каждого int в Is...
Зачем сортировать в обратном порядке Is...
? Потому что, если они не в таком порядке, вставка типа сдвинет позиции на одну и испортит другие вставки. Но в моем плане есть изъян, который я вскоре объясню. Сначала позвольте мне предоставить написанные мной вспомогательные функции, которые я проверил на корректную работу самостоятельно:
Insert<T, P<Types...>, N>::type
— это упаковка P<Types...>
, в которой T вставлена в позицию N.
template <typename, typename, typename, int> struct InsertHelper;
template <typename T, template <typename...> class P, typename First, typename... Rest, typename... Accumulated>
struct InsertHelper<T, P<First, Rest...>, P<Accumulated...>, 0> {
using type = P<Accumulated..., T, First, Rest...>;
};
template <typename T, template <typename...> class P, typename First, typename... Rest, typename... Accumulated, int N>
struct InsertHelper<T, P<First, Rest...>, P<Accumulated...>, N> : InsertHelper<T, P<Rest...>, P<Accumulated..., First>, N-1> {};
template <typename, typename, int> struct Insert;
template <typename T, template <typename...> class P, typename... Types, int N>
struct Insert<T, P<Types...>, N> : InsertHelper<T, P<Types...>, P<>, N> {};
Теперь ReverseSortIntSequence (с использованием быстрой сортировки):
template <int, typename> struct PrependInt;
template <int N, template <int...> class Z, int... Is>
struct PrependInt<N, Z<Is...>> {
using type = Z<N, Is...>;
};
template <template<int> class, typename> struct FilterInts;
template <template<int> class F, template <int...> class Z, int I, int... Is>
struct FilterInts<F, Z<I, Is...>> {
using type = typename std::conditional<F<I>::value,
typename PrependInt<I, typename FilterInts<F, Z<Is...>>::type>::type,
typename FilterInts<F, Z<Is...>>::type
>::type;
};
template <template<int> class F, template <int...> class Z>
struct FilterInts<F, Z<>> {
using type = Z<>;
};
template <typename, typename> struct MergeIntSequences;
template <template <int...> class Z, int... Is, int... Js>
struct MergeIntSequences<Z<Is...>, Z<Js...>> {
using type = Z<Is..., Js...>;
};
template <typename> struct ReverseSortIntSequence;
template <template <int...> class Z, int N, int... Is>
struct ReverseSortIntSequence<Z<N, Is...>> {
template<int I> struct less_than : std::integral_constant<bool, (I >= N)> {};
template <int I> struct more_than : std::integral_constant<bool, (I < N)> {};
using subsequence_less_than_N = typename FilterInts<less_than, Z<Is...>>::type;
using subsequence_more_than_N = typename FilterInts<more_than, Z<Is...>>::type;
using type = typename MergeIntSequences<typename ReverseSortIntSequence<subsequence_less_than_N>::type,
typename PrependInt<N, typename ReverseSortIntSequence<subsequence_more_than_N>::type>::type
>::type;
};
template<template <int...> class Z>
struct ReverseSortIntSequence<Z<>> {
using type = Z<>;
};
Теперь сам InsertTypes
:
template <typename, typename, typename> struct InsertTypesHelper;
template <typename Pack, template <typename...> class P, template <int...> class Z>
struct InsertTypesHelper<Pack, P<>, Z<>> {
using type = Pack;
};
template <typename Pack, template <typename...> class P, typename First, typename... Rest, template <int...> class Z, int N, int... Ns>
struct InsertTypesHelper<Pack, P<First, Rest...>, Z<N, Ns...>> : InsertTypesHelper<typename Insert<First, Pack, N>::type, P<Rest...>, Z<Ns...>> {};
template <typename, typename, int...> struct InsertTypes;
template <typename Pack, template <typename...> class P, typename... Types, int... Is>
struct InsertTypes<Pack, P<Types...>, Is...> : InsertTypesHelper<Pack, P<Types...>, typename ReverseSortIntSequence<index_sequence<Is...>>::type> {};
Теперь мои тесты:
int main() {
std::cout << std::is_same<
typename ReverseSortIntSequence<index_sequence<5,10,8,4,0,2,1,2,7,8,3>>::type,
index_sequence<10,8,8,7,5,4,3,2,2,1,0>
>::value << std::endl; // true
std::cout << std::is_same<
InsertTypesHelper<Pack<int, double, char, long, int>, Pack<float, short, std::string>, index_sequence<4,2,1>>::type,
Pack<int, std::string, double, short, char, long, float, int>
>::value << std::endl; // true (*)
std::cout << std::is_same<
typename ReverseSortIntSequence<index_sequence<2,4,1>>::type,
index_sequence<4,2,1>
>::value << std::endl; // true (**)
std::cout << std::is_same<
InsertTypes<Pack<int, double, char, long, int>, Pack<short, float, std::string>, 2,4,1>::type,
Pack<int, std::string, double, short, char, long, float, int>
>::value << std::endl; // false (rats!)
}
Я получаю false выше, потому что, несмотря на то, что (*) и (**) верны выше, мы должны переставить Pack<short, float, std::string>
таким же образом, как переставлены 2,4,1, чтобы получить это в обратном порядке сортировки. Я мог бы продолжить это исправление, но теперь оно становится за бортом. Я все равно продолжу это, но я серьезно подозреваю, что есть лучший метод, возможно, тоже довольно короткий.
Любые хорошие идеи здесь? Я подумал об извлечении пар типов, определяемых индексами (вставленные типы будут располагаться между парами), но это не сработает, если в исходном пакете есть повторяющиеся типы (а также из-за вставляемых типов).
Обновление: я закончил хелпер по перестановке, рассмотренный выше, и теперь все работает правильно. Но должно быть лучшее и более короткое решение, чем весь этот бардак.
template <int, typename> struct NthType;
template <int N, template <typename...> class P, typename First, typename... Rest>
struct NthType<N, P<First, Rest...>> : NthType<N-1, P<Rest...>> {};
template <template <typename...> class P, typename First, typename... Rest>
struct NthType<0, P<First, Rest...>> {
using type = First;
};
template <int, int, typename> struct FindIndexOfIntHelper;
template <int N, int FindMe, template <int...> class Z, int... Rest>
struct FindIndexOfIntHelper<N, FindMe, Z<FindMe, Rest...>> : std::integral_constant<int, N> {};
template <int N, int FindMe, template <int...> class Z>
struct FindIndexOfIntHelper<N, FindMe, Z<>> : std::integral_constant<int, -1> {}; // Not found.
template <int N, int FindMe, template <int...> class Z, int First, int... Rest>
struct FindIndexOfIntHelper<N, FindMe, Z<First, Rest...>> : FindIndexOfIntHelper<N+1, FindMe, Z<Rest...>> {};
template <int FindMe, typename Pack>
using FindIndexOfInt = FindIndexOfIntHelper<0, FindMe, Pack>;
template <typename, typename, typename, typename> struct PermutePackHelper;
template <typename Pack, template <typename...> class P, typename... Accumulated, typename IndicesPack, template <int...> class Z>
struct PermutePackHelper<Pack, P<Accumulated...>, IndicesPack, Z<>> {
using type = P<Accumulated...>;
};
template <typename Pack, template <typename...> class P, typename... Accumulated, typename IndicesPack, template <int...> class Z, int I, int... Is>
struct PermutePackHelper<Pack, P<Accumulated...>, IndicesPack, Z<I, Is...>> :
PermutePackHelper<Pack, P<Accumulated..., typename NthType<FindIndexOfInt<I, IndicesPack>::value, Pack>::type>,
IndicesPack, Z<Is...>> {};
template <typename, typename, typename> struct PermutePack;
template <template <typename...> class P, typename... Types, template <int...> class Z, int... Is, int... Js>
struct PermutePack<P<Types...>, Z<Is...>, Z<Js...>> : PermutePackHelper<P<Types...>, P<>, Z<Is...>, Z<Js...>> {};
1, 2, 4
вместо2, 4, 1
. - person jrok   schedule 27.02.2015types<Ts...>
сtypes<types<Ts>...>
. Затем вставьте, не беспокоясь о ударах. Затем расплющите. - person Yakk - Adam Nevraumont   schedule 28.02.2015