簡體   English   中英

可變模板:隔行掃描多個包

[英]Variadic templates: Interlacing multiple packs

給定任意數量的包裝,從每個包裝中取出第一種類型,將它們放在一起。 然后是每個包中的第二種類型,將它們放在一起等等......然后將它們全部合並。 任何左撇子都會在他們之間重復這個過程。 例如,使用整數表示不同類型以獲得更好的可讀性,

InterlacePacks<Pack<1 2 3 4>, Pack<5 6 7>, Pack<8 9 10 11 12>>::type

會給

Pack<1 5 8 2 6 9 3 7 10 4 11 12>

如果所有包只是相同的大小,則以下代碼有效。 我現在完全陷入對付“左結轉”的時候,包的大小不同 到目前為止,這是我的代碼。 我解釋每個階段,以便你知道我的計划是什么:

#include <iostream>

// First a helper to remove the first N types from a pack:
template <int, typename> struct RemoveHead;

template <typename Pack>
struct RemoveHead<0, Pack> { using type = Pack; };

template <template <typename...> class P, typename First, typename... Rest>
struct RemoveHead<0, P<First, Rest...>> { using type = P<First, Rest...>; };

template <int N, template <typename...> class P, typename First, typename... Rest>
struct RemoveHead<N, P<First, Rest...>> : RemoveHead<N-1, P<Rest...>> {};

// Now a helper to merge multiple packs:
template <typename...> struct MergePacks;

template <typename Pack>
struct MergePacks<Pack> {
    using type = Pack;
};

// Final Pack type shall be the first one listed, if there are different pack types.
template <template <typename...> class P1, template <typename...> class P2, typename... Types1, typename... Types2, typename... Packs>
struct MergePacks<P1<Types1...>, P2<Types2...>, Packs...> : MergePacks<P1<Types1..., Types2...>, Packs...> {};

// First collect the first type from each pack:
template <typename, typename...> struct InterlacePacksHelper1;

template <template <typename...> class P, typename... Ts>
struct InterlacePacksHelper1<P<Ts...>> { using type = P<Ts...>; };

template <template <typename...> class P, template <typename...> class FirstPack, typename... Ts, typename First, typename... Rest, typename... Packs>
struct InterlacePacksHelper1<P<Ts...>, FirstPack<First, Rest...>, Packs...> : InterlacePacksHelper1<P<Ts..., First>, Packs...> {};

// Now remove the first type from each pack and repeat the process.  Use a parameter N as a counter, where N will start as the minimum size of the packs.
template <int, typename, typename...> struct InterlacePacksHelper;

template <template <typename...> class P, typename... Ts, typename... Packs>
struct InterlacePacksHelper<0, P<Ts...>, Packs...> { using type = P<Ts...>; };

template <int N, template <typename...> class P, typename... Ts, typename... Packs>
struct InterlacePacksHelper<N, P<Ts...>, Packs...> : InterlacePacksHelper<N-1,
    typename MergePacks<P<Ts...>, typename InterlacePacksHelper1<P<>, Packs...>::type>::type,
    typename RemoveHead<1, Packs>::type...> {};

// Now obtain the smallest pack size, given a list of packs.
template <int N, typename...> struct MinPackSize;

template <int N>
struct MinPackSize<N> : std::integral_constant<int, N> {};

template <int N, template <typename...> class P, typename... Types, typename... Packs>
struct MinPackSize<N, P<Types...>, Packs...> : std::integral_constant<int,
    (sizeof...(Types) < N) ? sizeof...(Types) : N> {}; 

// Finally, InterlacePacks itself.
template <typename...> struct InterlacePacks;

template <template <typename...> class P, typename... Ts, typename... Packs>
struct InterlacePacks<P<Ts...>, Packs...> : InterlacePacksHelper<MinPackSize<sizeof...(Ts), Packs...>::value, P<>, P<Ts...>, Packs...> {};

// test ----------------------------------------------------------------
template <typename...> struct Pack {};
template <typename...> struct Group {};
template <typename...> struct Wrap {};
struct Object {};  struct Blob {};

int main() {
    using TestPack1 = Pack<int, double, Object>;  // 3 types
    using TestPack2 = Group<double, std::string, int, short, long>;  // 5 types
    using TestPack3 = Wrap<char, short, Blob, std::string>;  // 4 types
    InterlacePacks<TestPack1, TestPack2, TestPack3>::type interlacedPack;
    std::cout << std::boolalpha << std::is_same< decltype(interlacedPack),
        Pack<int, double, char, double, std::string, short, Object, int, Blob> >::value << std::endl;  // true
//  Want it to be Pack<int, double, char, double, std::string, short, Object, int, Blob, short, std::string, long>
}

那么如何修復代碼以便獲得所需的輸出

Pack<int, double, char, double, std::string, short, Object, int, Blob, short, std::string, long>

結果呢?

注意:我嘗試使用MaxPackSizeMinPackSize ,並且正如預期的那樣無法編譯。 一個想法是在MinPackSize迭代之后丟棄空包並繼續該過程,直到MaxPackSize迭代完成(每次刪除新的空包)。 這在理論上雖然(尚未嘗試過):

template <typename, typename...> struct RemoveAllEmptyPacksHelper;

template <template <typename...> class P, typename... Packs> 
struct RemoveAllEmptyPacksHelper<P<Packs...>> : Identity<P<Packs...>> {};

template <template <typename...> class P, typename... CurrentPacks, template <typename...> class FirstPack, typename... Types, typename... Packs> 
struct RemoveAllEmptyPacksHelper<P<CurrentPacks...>, FirstPack<Types...>, Packs...> : 
    std::conditional<(sizeof...(Types) == 0),
    RemoveAllEmptyPacksHelper<P<CurrentPacks...>, Packs...>,
    RemoveAllEmptyPacksHelper<P<CurrentPacks..., FirstPack<Types...>>, Packs...>
    >::type {};

template <typename> struct RemoveAllEmptyPacks;

template <template <typename...> class P, typename... Packs> 
struct RemoveAllEmptyPacks<P<Packs...>> : RemoveAllEmptyPacksHelper<P<>, Packs...> {};

這是迄今為止我最短的C ++ 11次嘗試:

template <class T, class...> struct interlace_ {using type = T;};
template <class... R,  template<class...> class T, class f, class... t, class... P>
struct interlace_<std::tuple<R...>, T<f, t...>, P...>
    : interlace_<std::tuple<R..., f>, P..., T<t...>> {};
template <class... R, template<class...> class T, class f, class... P>
struct interlace_<std::tuple<R...>, T<f>, P...>
    : interlace_<std::tuple<R..., f>, P...> {};

template <class... packs>
using interlace = interlace_<std::tuple<>, packs...>;

演示 P代表包, R是(當前)結果包, f是第一種類型, t是當前觀察到的包的尾部。 T是保存包的模板。

以下可能會有所幫助,它使用一個輔助類並在第一個模板參數中聚合結果:

template <typename...> struct InterlacePacksHelper;

// general case: take first parameter and en-queue the Pack for further computation
template <template <typename...> class PRes, typename... Ts,
          template <typename...> class P, typename U, typename... Us,
          typename... Packs>
struct InterlacePacksHelper<PRes<Ts...>, P<U, Us...>, Packs...>
{
    using type = typename InterlacePacksHelper<PRes<Ts..., U>, Packs..., P<Us...>>::type;
};

// final case
template <template <typename...> class PRes, typename... Ts>
struct InterlacePacksHelper<PRes<Ts...>>
{
    using type = PRes<Ts...>;
};

// Remove empty Pack.
template <template <typename...> class PRes, typename... Ts,
          template <typename...> class P,
          typename... Packs>
struct InterlacePacksHelper<PRes<Ts...>, P<>, Packs...>
{
    using type = typename InterlacePacksHelper<PRes<Ts...>, Packs...>::type;
};


// Finally, InterlacePacks itself.
template <typename...> struct InterlacePacks;

template <template <typename...> class P, typename... Ts, typename... Packs>
struct InterlacePacks<P<Ts...>, Packs...> : InterlacePacksHelper<P<>, P<Ts...>, Packs...>::type
{
    using type = typename InterlacePacksHelper<P<>, P<Ts...>, Packs...>::type;
};

現場演示

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM