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

标签 c++ templates c++11 variadic

例如,

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 特征将匹配几乎所有模板,只要它没有非类型参数,这是一个相当糟糕的主意。

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 .

关于c++ - 删除从嵌套包中找到的第一个指定类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28247541/

相关文章:

c++ - 生成的复制和 move 运算符?

python - Django {% blocktrans %} : How to handle pluralization inside a for loop?

c++ - 在构建 dll 时,我需要在客户端的 header 中提供多少 parent 作为 __declspec(export)?

templates - 使用多个模板的运算符重载

c++ - 我需要在 autoexp.dat 中输入什么才能检查 vector 中包含的类的数据成员?

templates - 期望无限递归模板实例化?

C++递归函数,调用当前深度

c++ - 如何将 unique_ptr 参数传递给构造函数或函数?

c++ - FindNextPrinterChangeNotification 为 ppPrinterNotifyInfo 返回 NULL

c++ - 用 C++ 捕获音频