从嵌套包中删除找到的第一个指定类型
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.
例如,
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.