从嵌套包中删除找到的第一个指定类型

Removing the first specified type found from a nested pack

例如,

using NestedPack = Pack<long, char, double, Pack<long, int, short, int>, char, int>;

然后

RemoveFirstFoundFromNestedPack<int, NestedPack>::type

应该给

Pack<long, char, double, Pack<long, short, int>, char, int>

首先,我处理了非嵌套包的情况:

template <typename T> struct Identity { using type = T; };

template <typename, typename, typename...> struct RemoveFirstFoundFromPackHelper;

template <typename RemoveMe, template<typename...> class P, typename... Types>
struct RemoveFirstFoundFromPackHelper<RemoveMe, P<>, Types...> {
    using type = P<Types...>;
};

template <typename RemoveMe, template<typename...> class P, typename First, typename... Rest, typename... Types>
struct RemoveFirstFoundFromPackHelper<RemoveMe, P<First, Rest...>, Types...> : 
    std::conditional<std::is_same<RemoveMe, First>::value,
        Identity <P<Types..., Rest...>>,
        RemoveFirstFoundFromPackHelper<RemoveMe, P<Rest...>, Types..., First>
    >::type {};

template <typename, typename> struct RemoveFirstFoundFromPack;

template <typename RemoveMe, template<typename...> class P, typename... Types>
struct RemoveFirstFoundFromPack<RemoveMe, P<Types...>> : RemoveFirstFoundFromPackHelper<RemoveMe, P<Types...>> {};

这已经过测试可以正常工作(使用 std::is_same)。但我坚持使用嵌套案例。这是我最近的尝试,给出了错误的结果(虽然我无法追踪原因):

template <typename>
struct IsPack : std::false_type {};

template <template<typename...> class P, typename... Types>
struct IsPack<P<Types...>> : std::true_type {};

template <typename...> struct MergePacks;

template <typename Pack>
struct MergePacks<Pack> : Identity<Pack> {};

template <template <typename...> class P, typename... Types1, typename... Types2, typename... Packs>
struct MergePacks<P<Types1...>, P<Types2...>, Packs...> : MergePacks<P<Types1..., Types2...>, Packs...> {};

template <typename, typename, typename> struct RemoveFirstFoundFromNestedPackHelper;

template <typename RemoveMe, template<typename...> class P, typename... Types>
struct RemoveFirstFoundFromNestedPackHelper<RemoveMe, P<>, P<Types...>> {
    using type = P<Types...>;
};

template <typename RemoveMe, template<typename...> class P, typename First, typename... Rest, typename... Types>
struct RemoveFirstFoundFromNestedPackHelper<RemoveMe, P<First, Rest...>, P<Types...>> :
    std::conditional<std::is_same<RemoveMe, First>::value,
        Identity <P<Types..., Rest...>>,
        typename std::conditional<IsPack<First>::value,
            RemoveFirstFoundFromNestedPackHelper<RemoveMe, P<Rest...>, typename MergePacks<P<Types...>,
                typename RemoveFirstFoundFromPack<RemoveMe, First>::type>::type>,
            RemoveFirstFoundFromNestedPackHelper<RemoveMe, P<Rest...>, P<Types..., First>>
        >::type
    >::type {};

template <typename, typename> struct RemoveFirstFoundFromNestedPack;

template <typename RemoveMe, template<typename...> class P, typename... Types>
struct RemoveFirstFoundFromNestedPack<RemoveMe, P<Types...>> :
    RemoveFirstFoundFromNestedPackHelper<RemoveMe, P<Types...>, P<>> {};

我知道一定有比这更好的方法。

当然,一旦解决了这个问题,然后从嵌套包中删除指定类型的 所有 个实例应该只是解决方案的一个简单变体(我已经已经为非嵌套案例完成了)。

你的 IsPack trait 几乎可以匹配所有模板,只要它没有非类型参数,这是一个相当糟糕的主意。

template <class...> struct Pack {};

template <class, class, class = Pack<>> struct Remove_First;

// First one isn't a pack, and isn't what we are looking for.
template <class R, class F, class...Args1, class...Args2>
struct Remove_First<R, Pack<F, Args1...>, Pack<Args2...>> : Remove_First<R, Pack<Args1...>, Pack<Args2..., F>> {};

// First one is the type we are looking for.
template <class R, class...Args1, class...Args2>
struct Remove_First<R, Pack<R, Args1...>, Pack<Args2...>>  { using type = Pack<Args2..., Args1...>; };

// Didn't find the type
template <class R, class...Args>
struct Remove_First<R, Pack<>, Pack<Args...>>  { using type = Pack<Args...>; };

// Nested pack: Attempt to remove R from the nested pack
// Use is_same to check if a removal occurred and proceed accordingly
template <class R, class...Args1, class...Args2, class...ArgsNested>
struct Remove_First<R, Pack<Pack<ArgsNested...>, Args1...>, Pack<Args2...>> {
    using type = typename std::conditional<
                 std::is_same<typename Remove_First<R, Pack<ArgsNested...>>::type, Pack<ArgsNested...>>::value,
                 typename Remove_First<R, Pack<Args1...>, Pack<Args2..., Pack<ArgsNested...>>>::type,
                 Pack<Args2..., typename Remove_First<R, Pack<ArgsNested...>>::type, Args1...>>::type;
};

// if the type to remove is a Pack, and the first type in the list is a Pack,
// and they are the same pack, then remove it and we are done.
// if they are not the same Pack, then this specialization won't match,
// and we go into the recursion case as normal.
template <class...Args1, class...Args2, class...ArgsNested>
struct Remove_First<Pack<ArgsNested...>, Pack<Pack<ArgsNested...>, Args1...>, Pack<Args2...>> {
    using type = Pack<Args2..., Args1...>;
};

template<class R, class Pack>
using remove_first_t = typename Remove_First<R, Pack>::type;

前三个部分特化处理从非嵌套包中移除。嵌套包由第四部分专业化处理。它递归地对嵌套包执行删除。如果删除了一个类型(因此生成的类型与原始嵌套包类型不同),那么我们就完成了。否则,我们将照常继续处理其余的外包装。最后的特化处理要删除的类型是 Pack 本身的情况,否则当类型存在时,第二个和第四个部分特化都将匹配,并且两者都不比另一个更特化,从而导致歧义错误。

Demo.