2015-02-23 40 views
2

ExtractEveryPack<Pack>::typePack中所有「葉包裝」的包裝。 例如,ExtractEveryPack< Pack<double, Pack<int, char>, int, Pack<long, short>> >::typePack< Pack<int, char>, Pack<long, short> >。 但「外包裝」沒有退回。只有最內層的包(我稱之爲「葉包」)被提取。所以從一包嵌套包中提取每個「葉包裝」

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>::typeT默認。然後遞歸,適用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...>> {}; 
+0

現在你的第二種類型實際上是'Pack ,Pack ,Pack >>,Pack <>> – 2015-02-23 16:52:52

+0

哦。我想'RemoveNonPacks'意外地將非包裝從葉包裝中取出,而不是停在葉包裝上。嗯...如何告訴它何時停止呢? – prestokeys 2015-02-23 16:54:57

+0

此外,一個外包裝可以生產任意數量的葉包裝。 'RemoveNonPacks

:: type ... >>''在結果中永遠不會產生大於'sizeof ...(Types)'的包,所以它不可能是正確的。 – 2015-02-23 17:00:48

回答

1

遞歸是正確的。但是應用ExtractEveryPack的結果可以是任意數量(包括0)的葉包。因此,不必返回一個類型,它必須返回一組類型。然後可以將這些包連接起來以產生最終輸出。

// 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總是返回葉包的Pack。然而,葉包的類型不限於Pack