typename FindPacksToMerge<P<Packs...>, P<Ts...>>::type
是P<As...>
,因此As...
是来自Packs...
的包装序列(可能带有重复),并且
std::is_same< typename concat<As...>::type, P<Ts...> >::value == true
例如,
std::cout << std::is_same<
FindPacksToMerge< P< P<int, char, long>, P<int>, P<double, bool>, P<bool, char, int> >, P<int, bool, char, int, int, double, bool> >::type,
P< P<int>, P<bool, char, int>, P<int>, P<double, bool> >
>::value << '\n';
应该输出true。现在,让我们满足于在有多个答案的情况下获得任何答案。
我已经写了相关的帮助器结构(
concat
合并任意数量的包,split<N, Pack>
拆分一个包,以便可以得到N个类型的头部和尾部,pack_size
给出该包中类型的数量):template <typename T> struct Identity { using type = T; };
template <typename...> struct concat;
template <template <typename...> class P, typename... Ts, typename... Us>
struct concat<P<Ts...>, P<Us...>> {
using type = P<Ts..., Us...>;
};
template <typename Pack>
struct concat<Pack> : Identity<Pack> {};
template <typename Pack1, typename Pack2, typename... Packs>
struct concat<Pack1, Pack2, Packs...> {
using type = typename concat<Pack1, typename concat<Pack2, Packs...>::type>::type;
};
template <std::size_t N, typename Intput, typename... Output> struct split;
template <std::size_t N, template <typename...> class P, typename First, typename... Rest, typename... Output>
struct split<N, P<First, Rest...>, Output...> : split<N-1, P<Rest...>, Output..., First> {};
template <template <typename...> class P, typename First, typename... Rest, typename... Output>
struct split<0, P<First, Rest...>, Output...> {
using head = P<Output...>;
using tail = P<First, Rest...>;
};
template <template <typename...> class P, typename... Output>
struct split<0, P<>, Output...> {
using head = P<Output...>;
using tail = P<>;
};
template <typename Pack> struct pack_size;
template <template <typename...> class P, typename... Ts>
struct pack_size<P<Ts...>> : std::integral_constant<std::size_t, sizeof...(Ts)> {};
但是问题是递归。假设在
P<Packs...>
中的类型中,我们正在测试Pack
类型。如果split<pack_size<Pack>::value, P<Ts...>>::head
与Pack
匹配,则使用split<pack_size<Pack>::value, P<Ts...>>::tail
重复搜索(以P<Packs...>
的第一包开始搜索)。我们将所有找到的包一路存储在输出包中。当我们到达P<Ts...>
的末尾附近时,发现其余的尾部的长度短于或等于P<Packs...>
中的最短包装,且与P<Packs...>
中的任何包装都不匹配,则沿着这条线的搜索失败。因此,我们必须再次开始搜索。但是从哪里来的?从最后一个尝试过的包开始(我们现在必须在此之后尝试该包)。而且,如果此后的所有任务包也都没有给出答案,那么我们必须再退一步,但是那在哪里呢?这是一个遍历树的行为,但是如何记住我们是经过几代人之后才离开的呢?还是完全有更好的方法?尝试合并P<Packs...>
中的所有可能组合直到匹配P<Ts...>
都不是可行的解决方案。这是我当前正在处理的模板专业化,需要修复。我觉得我无法解决的问题很简短。
template <typename PackOfPacks, typename Untried, typename Output, typename Match> struct FindPacksToMergeHelper;
template <typename PackOfPacks, template <typename...> class P, typename First, typename... Rest, typename... Output, typename Match>
struct FindPacksToMergeHelper<PackOfPacks, P<First, Rest...>, P<Output...>, Match> : std::conditional_t<
pack_size<Match>::value < pack_size<First>::value,
FindPacksToMergeHelper<PackOfPacks, P<Rest...>, P<Output...>, Match>, // Move on to the next of the untried packs.
std::conditional_t<
std::is_same<First, Match>::value,
Identity<P<Output..., First>>, // Answer found.
std::conditional_t<
std::is_same<First, typename split<pack_size<First>::value, Match>::head>::value, // Check if the head of Match is the same as First.
FindPacksToMergeHelper<PackOfPacks, PackOfPacks, P<Output..., First>, typename split<pack_size<First>::value, Match>::tail>, // Try with the tail now, starting back at the first type in PackOfPacks.
FindPacksToMergeHelper<PackOfPacks, P<Rest...>, P<Output...>, Match> // Move on to the next of the untried packs.
>
>
> {};
最佳答案
一包:
template<class... > class pack {};
通过谓词过滤一堆类型:
template<class, class Pred> struct filter;
template<class... Ts, class F>
struct filter<pack<Ts...>, F>
{
using type = typename concat<std::conditional_t<F::template apply<Ts>::value,
pack<Ts>,
pack<>>...>::type;
};
“ U是T的前缀”的谓词:
template<class T>
struct is_prefix_of
{
template<class U, bool = pack_size<T>::value >= pack_size<U>::value>
struct apply;
template<class U>
struct apply<U, true>
: std::is_same<U, typename split<pack_size<U>::value, T>::head> { };
template<class U>
struct apply<U, false> : std::false_type {};
};
指示失败的标签类型:
struct fail;
野兽:
template<class Packs, class Pack,
class Current = typename filter<Packs, is_prefix_of<Pack>>::type>
struct find_packs_to_merge;
template<class Packs, class Pack, class First, class... Rest>
struct find_packs_to_merge<Packs, Pack, pack<First, Rest...>>
{
// Get the remainder of the pack we still need to work on
using Remaining = typename split<pack_size<First>::value, Pack>::tail;
// search for the packs needed for the tail
using PR = typename find_packs_to_merge<Packs, Remaining>::type;
// on failure, try the next pack
// on success, concat First to PR and we are done.
// Note the short circuiting.
using type = typename std::conditional_t<std::is_same<fail, PR>::value,
find_packs_to_merge<Packs, Pack, pack<Rest...>>,
concat<pack<First>, PR>>::type;
};
template<class Packs, class Pack>
struct find_packs_to_merge<Packs, Pack, pack<>>
{
// we tried everything and nothing works.
using type = fail;
};
template<class Packs>
struct find_packs_to_merge<Packs, pack<>, pack<>>
{
// Success - we've used up the pack.
using type = pack<>;
};
关于c++ - 查找一组要合并为给定包装的包装,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36535061/