从一包嵌套包中提取每个 "leaf-pack"
Extract every "leaf-pack" from a pack of nested packs
ExtractEveryPack<Pack>::type
是 Pack
中所有 "leaf-packs" 的集合。
例如,ExtractEveryPack< Pack<double, Pack<int, char>, int, Pack<long, short>> >::type
是 Pack< Pack<int, char>, Pack<long, short> >
。
但是 "outer packs" 没有返回。仅提取最内部的包(我称之为 "leaf packs")。所以
ExtractEveryPack<Pack<Pack<int, double>, char, Pack<long, Pack<Pack<int, char>, Pack<char, Pack<double, int>>>, char>, int, Pack<short, int>>>::type,
是
Pack< Pack<int, double>, Pack<int, char>, Pack<double, int>, Pack<short, int>.
我的想法:ExtractEveryPack<T>::type
默认是T
。然后递归地,将 ExtractEveryPack
应用于每个类型并删除所有不是包的类型:
#include <iostream>
template <typename, typename> struct RemoveNonPacksHelper;
template <template <typename...> class P, typename... Accumulated>
struct RemoveNonPacksHelper<P<>, P<Accumulated...>> {
using type = P<Accumulated...>;
};
template <template <typename...> class P, typename First, typename... Rest, typename... Accumulated>
struct RemoveNonPacksHelper<P<First, Rest...>, P<Accumulated...>> : RemoveNonPacksHelper<P<Rest...>, P<Accumulated...>> {};
template <template <typename...> class P, typename... Types, typename... Rest, typename... Accumulated>
struct RemoveNonPacksHelper<P<P<Types...>, Rest...>, P<Accumulated...>> : RemoveNonPacksHelper<P<Rest...>, P<Accumulated..., P<Types...>>> {};
template <typename> struct RemoveNonPacks;
template <template <typename...> class P, typename... Types>
struct RemoveNonPacks<P<Types...>> : RemoveNonPacksHelper<P<Types...>, P<>> {};
template <typename T> struct Identity { using type = T; };
template <typename T>
struct ExtractEveryPack : Identity<T> {}; // Do nothing for non-packs.
// The key idea here, but apparently not correct:
template <template <typename...> class P, typename... Types>
struct ExtractEveryPack<P<Types...>> :
RemoveNonPacks<P<typename ExtractEveryPack<Types>::type...>> {};
// Testing
template <typename...> struct Pack {};
int main() {
std::cout << std::boolalpha << std::is_same<
RemoveNonPacks< Pack<Pack<int, double>, char, Pack<long, double, char>, int, Pack<short, int>> >::type,
Pack<Pack<int, double>, Pack<long, double, char>, Pack<short, int>>
>::value << std::endl; // true
std::cout << std::is_same<
ExtractEveryPack<Pack<Pack<int, double>, char, Pack<long, Pack<Pack<int, char>, Pack<char, Pack<double, int>>>, char>, int, Pack<short, int>>>::type,
Pack< Pack<int, double>, Pack<int, char>, Pack<double, int>, Pack<short, int> >
>::value << std::endl; // false (darn!)
}
这是怎么回事?我的计划或实施呢?什么是更好的计划?
为了它的价值,这里有一个辅助结构 IsLeafPack
来确定一个包是否不包含其他包(已测试),尽管我还没有想出如何使用它:
template <typename> struct IsLeafPack;
template <template <typename...> class P>
struct IsLeafPack<P<>> : std::true_type {};
template <template <typename...> class P, template <typename...> class P2, typename... Types, typename... Rest>
struct IsLeafPack<P<P2<Types...>, Rest...>> : std::false_type {};
template <template <typename...> class P, typename First, typename... Rest>
struct IsLeafPack<P<First, Rest...>> : IsLeafPack<P<Rest...>> {};
递归正确。但是应用 ExtractEveryPack
的结果可以是任意数量(包括 0)的叶包。因此,它必须 return 一组类型,而不是 return 单一类型。然后可以连接这些包以产生最终输出。
// A pack template.
template <typename...> struct Pack {};
// Test if Ts... contains any pack - not necessarily a Pack.
template <typename... Ts>
struct contains_any_pack : std::false_type {};
template <template <typename...> class P, typename... TPs, typename... Ts>
struct contains_any_pack<P<TPs...>, Ts...> : std::true_type {};
template <class F, typename... Ts>
struct contains_any_pack<F, Ts...> : contains_any_pack<Ts...> {};
// concatenates a list of Pack's into one Pack.
template <typename... Ts> struct concat_packs;
template <typename... Ts>
struct concat_packs<Pack<Ts...>> { using type = Pack<Ts...>; };
template <typename... Ts, typename... T1s, typename... T2s>
struct concat_packs<Pack<Ts...>, Pack<T1s...>, T2s... >
: concat_packs<Pack<Ts..., T1s...>, T2s... > {};
// T isn't a pack - return an empty Pack
template <typename T>
struct ExtractEveryPack { using type = Pack<>; };
// if P<Ts...> is a leaf pack, return it wrapped in a Pack.
// else, apply ExtractEveryPack to Ts... recursively,
// and concatenate the results
template <template <typename...> class P, typename... Ts>
struct ExtractEveryPack<P<Ts...>> {
using type = typename std::conditional<contains_any_pack<Ts...>::value,
typename concat_packs<typename ExtractEveryPack<Ts>::type...>::type,
Pack<P<Ts...>>>::type;
};
为了简化实施,上面 ExtractEveryPack
总是 return 一个 Pack
叶包。然而,叶包的类型并不限于 Pack
s.
ExtractEveryPack<Pack>::type
是 Pack
中所有 "leaf-packs" 的集合。
例如,ExtractEveryPack< Pack<double, Pack<int, char>, int, Pack<long, short>> >::type
是 Pack< Pack<int, char>, Pack<long, short> >
。
但是 "outer packs" 没有返回。仅提取最内部的包(我称之为 "leaf packs")。所以
ExtractEveryPack<Pack<Pack<int, double>, char, Pack<long, Pack<Pack<int, char>, Pack<char, Pack<double, int>>>, char>, int, Pack<short, int>>>::type,
是
Pack< Pack<int, double>, Pack<int, char>, Pack<double, int>, Pack<short, int>.
我的想法:ExtractEveryPack<T>::type
默认是T
。然后递归地,将 ExtractEveryPack
应用于每个类型并删除所有不是包的类型:
#include <iostream>
template <typename, typename> struct RemoveNonPacksHelper;
template <template <typename...> class P, typename... Accumulated>
struct RemoveNonPacksHelper<P<>, P<Accumulated...>> {
using type = P<Accumulated...>;
};
template <template <typename...> class P, typename First, typename... Rest, typename... Accumulated>
struct RemoveNonPacksHelper<P<First, Rest...>, P<Accumulated...>> : RemoveNonPacksHelper<P<Rest...>, P<Accumulated...>> {};
template <template <typename...> class P, typename... Types, typename... Rest, typename... Accumulated>
struct RemoveNonPacksHelper<P<P<Types...>, Rest...>, P<Accumulated...>> : RemoveNonPacksHelper<P<Rest...>, P<Accumulated..., P<Types...>>> {};
template <typename> struct RemoveNonPacks;
template <template <typename...> class P, typename... Types>
struct RemoveNonPacks<P<Types...>> : RemoveNonPacksHelper<P<Types...>, P<>> {};
template <typename T> struct Identity { using type = T; };
template <typename T>
struct ExtractEveryPack : Identity<T> {}; // Do nothing for non-packs.
// The key idea here, but apparently not correct:
template <template <typename...> class P, typename... Types>
struct ExtractEveryPack<P<Types...>> :
RemoveNonPacks<P<typename ExtractEveryPack<Types>::type...>> {};
// Testing
template <typename...> struct Pack {};
int main() {
std::cout << std::boolalpha << std::is_same<
RemoveNonPacks< Pack<Pack<int, double>, char, Pack<long, double, char>, int, Pack<short, int>> >::type,
Pack<Pack<int, double>, Pack<long, double, char>, Pack<short, int>>
>::value << std::endl; // true
std::cout << std::is_same<
ExtractEveryPack<Pack<Pack<int, double>, char, Pack<long, Pack<Pack<int, char>, Pack<char, Pack<double, int>>>, char>, int, Pack<short, int>>>::type,
Pack< Pack<int, double>, Pack<int, char>, Pack<double, int>, Pack<short, int> >
>::value << std::endl; // false (darn!)
}
这是怎么回事?我的计划或实施呢?什么是更好的计划?
为了它的价值,这里有一个辅助结构 IsLeafPack
来确定一个包是否不包含其他包(已测试),尽管我还没有想出如何使用它:
template <typename> struct IsLeafPack;
template <template <typename...> class P>
struct IsLeafPack<P<>> : std::true_type {};
template <template <typename...> class P, template <typename...> class P2, typename... Types, typename... Rest>
struct IsLeafPack<P<P2<Types...>, Rest...>> : std::false_type {};
template <template <typename...> class P, typename First, typename... Rest>
struct IsLeafPack<P<First, Rest...>> : IsLeafPack<P<Rest...>> {};
递归正确。但是应用 ExtractEveryPack
的结果可以是任意数量(包括 0)的叶包。因此,它必须 return 一组类型,而不是 return 单一类型。然后可以连接这些包以产生最终输出。
// A pack template.
template <typename...> struct Pack {};
// Test if Ts... contains any pack - not necessarily a Pack.
template <typename... Ts>
struct contains_any_pack : std::false_type {};
template <template <typename...> class P, typename... TPs, typename... Ts>
struct contains_any_pack<P<TPs...>, Ts...> : std::true_type {};
template <class F, typename... Ts>
struct contains_any_pack<F, Ts...> : contains_any_pack<Ts...> {};
// concatenates a list of Pack's into one Pack.
template <typename... Ts> struct concat_packs;
template <typename... Ts>
struct concat_packs<Pack<Ts...>> { using type = Pack<Ts...>; };
template <typename... Ts, typename... T1s, typename... T2s>
struct concat_packs<Pack<Ts...>, Pack<T1s...>, T2s... >
: concat_packs<Pack<Ts..., T1s...>, T2s... > {};
// T isn't a pack - return an empty Pack
template <typename T>
struct ExtractEveryPack { using type = Pack<>; };
// if P<Ts...> is a leaf pack, return it wrapped in a Pack.
// else, apply ExtractEveryPack to Ts... recursively,
// and concatenate the results
template <template <typename...> class P, typename... Ts>
struct ExtractEveryPack<P<Ts...>> {
using type = typename std::conditional<contains_any_pack<Ts...>::value,
typename concat_packs<typename ExtractEveryPack<Ts>::type...>::type,
Pack<P<Ts...>>>::type;
};
为了简化实施,上面 ExtractEveryPack
总是 return 一个 Pack
叶包。然而,叶包的类型并不限于 Pack
s.