I've written a working code for computing P(N,R) for packs when the pack has all different types, e.g.
PermutationN<2, P<int, char, bool>>
is to be
P< P<int, char>, P<int, bool>, P<char, int>, P<char, bool>, P<bool, int>, P<bool, char> >
But when there are repeat elements, I'm getting the wrong results. For example,
PermutationN<2, P<int, int, char>>
should be
P< P<int, int>, P<int, char>, P<char, int> >
Here is my working code for when all the types are different. I'm stuck on how to adapt it so that it gives correct results when there are repeated types in the pack. Any help would be appreciated.
#include <iostream>
#include <type_traits>
template <typename, typename> struct Merge;
template <template <typename...> class P, typename... Ts, typename... Us>
struct Merge<P<Ts...>, P<Us...>> {
using type = P<Ts..., Us...>;
};
template <std::size_t N, typename Pack, typename Previous, typename... Output> struct PermutationNHelper;
template <std::size_t N, template <typename...> class P, typename First, typename... Rest, typename... Prev, typename... Output>
struct PermutationNHelper<N, P<First, Rest...>, P<Prev...>, Output...> : Merge<
// P<Prev..., Rest...> are the remaining elements, thus ensuring that the next
// element chosen will not be First. The new Prev... is empty since we now start
// at the first element of P<Prev..., Rest...>.
typename PermutationNHelper<N-1, P<Prev..., Rest...>, P<>, Output..., First>::type,
// Using P<Rest...> ensures that the next set of permutations will begin with the
// type after First, and thus the new Prev... is Prev..., First.
typename PermutationNHelper<N, P<Rest...>, P<Prev..., First>, Output...>::type
> {};
template <std::size_t N, template <typename...> class P, typename Previous, typename... Output>
struct PermutationNHelper<N, P<>, Previous, Output...> {
using type = P<>;
};
template <template <typename...> class P, typename First, typename... Rest, typename... Prev, typename... Output>
struct PermutationNHelper<0, P<First, Rest...>, P<Prev...>, Output...> {
using type = P<P<Output...>>;
};
template <template <typename...> class P, typename Previous, typename... Output>
struct PermutationNHelper<0, P<>, Previous, Output...> {
using type = P<P<Output...>>;
};
template <typename Pack> struct EmptyPack;
template <template <typename...> class P, typename... Ts>
struct EmptyPack<P<Ts...>> { using type = P<>; };
template <std::size_t N, typename Pack>
using PermutationN = typename PermutationNHelper<N, Pack, typename EmptyPack<Pack>::type>::type;
// Testing
template <typename...> struct P;
int main() {
std::cout << std::is_same<
PermutationN<2, P<int, char, bool>>,
P< P<int, char>, P<int, bool>, P<char, int>, P<char, bool>, P<bool, int>, P<bool, char> >
>::value << '\n'; // true
std::cout << std::is_same<
PermutationN<2, P<int, int, int>>,
P< P<int, int>, P<int, int>, P<int, int>, P<int, int>, P<int, int>, P<int, int> >
>::value << '\n'; // true (but the answer should be P< P<int, int> >.
}
N.B. I'm looking for an elegant (and efficient) solution that does not simply carry out the above and then merely remove all repeat packs from the output (I can already do that but refuse to write up such an ugly, inefficient solution that does not tackle the heart of the problem), but rather get the correct output directly. That's where I'm stuck.