パックにすべての異なる型がある場合、パックのP(N、R)を計算するための作業コードを書いた。コンパイル時の型の順列P(N、R)
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> >
になることです。しかし、繰り返し要素があるとき、私は間違った結果を取得しています。例えば、
PermutationN<2, P<int, int, char>>
は
P< P<int, int>, P<int, char>, P<char, int> >
はここですべての種類が異なる場合のための私の作業コードであるべきです。私はパックに繰り返しタイプがあるときに正しい結果を出すようにそれを適応させる方法に固執しています。どんな助けもありがとう。
#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<
typename PermutationNHelper<N-1, P<Prev..., Rest...>, P<>, Output..., First>::type, // 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, P<Rest...>, P<Prev..., First>, Output...>::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.
> {};
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.私は単純に上記を実行していないだけで出力からすべてのリピートパックを削除するエレガントな(そして効率的な)ソリューションを探しています(私はすでにそれを行うことができますが、そうでない醜い非効率的な解決策むしろ正しい出力を直接得ることができます。それは私が立ち往生している場所です。
@ T.C.私が今まで見た中で最も美しい解決策をありがとう。私はそれが正しく動作することを確認しました。 GCC 5.3では、N> 0とN == 0の場合を 'std :: enable_if 'で区切っている限り、2つの部分的な特殊化を持つただ1つのテンプレートでコンパイルできます。ここに作業コード全体があります:http://ideone.com/hqL11N – prestokeys
@prestokeysそうですが、私は 'enable_if'がさらに醜いと感じます。 –