lundi 23 février 2015

Extract every "leaf-pack" from a pack of nested packs

ExtractEveryPack<Pack>::type is the pack of all "leaf-packs" in Pack. For example, ExtractEveryPack< Pack<double, Pack<int, char>, int, Pack<long, short>> >::type is Pack< Pack<int, char>, Pack<long, short> >. But "outer packs" are not returned. Only the most inner packs (which I'm calling "leaf packs") are extracted. So



ExtractEveryPack<Pack<Pack<int, double>, char, Pack<long, Pack<Pack<int, char>, Pack<char, Pack<double, int>>>, char>, int, Pack<short, int>>>::type,


is



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


My idea: ExtractEveryPack<T>::type is T by default. Then recursively, apply ExtractEveryPack to every type and remove all types that are not packs:



#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!)
}


What's wrong here? My plan or the implementation of it? What would be a better plan?


Aucun commentaire:

Enregistrer un commentaire