typename FindPacksToMerge<P<Packs...>, P<Ts...>>::typeP<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...>>::headPack匹配,则使用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/

10-11 04:19