2015-01-27 3 views
9

При любом количестве пакетов, возьмите первый тип из каждого пакета, соедините их. Затем второй тип из каждой упаковки, соедините их и т. Д. Затем объедините их все. Любые левые будут повторять этот процесс между собой. Например, при использовании целых чисел для представления различных типов для лучшей читаемости,Шаблоны Variadic: чередование нескольких пакетов

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> 

результаты вместо этого?

Примечание: Я пробовал использовать MaxPackSize, используя MinPackSize, и, как и ожидалось, это не скомпилировалось. Одна идея состоит в том, чтобы отбросить пустые пакеты после итераций 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...> {}; 
+0

Не разрешено C++ 14? – Columbo

+0

Ну, вы можете отправить решение C++ 14, если хотите (лучше, чем никакого решения). Конечно, я больше беспокоюсь о том, как идти дальше с моим собственным планом, чтобы использовать некоторую библиотечную функцию, о которой я никогда не слышал (нет, я еще не изучал C++ 14). Таким образом, предпочтительным является решение C++ 11, но я буду приветствовать ваше решение C++ 14, так как я скоро изучу C++ 14. – prestokeys

+0

После массового чрезмерного количества вещей мне удалось найти элегантное решение на C++ 11. Я не исправил ваш код - Jarod42 все же. – Columbo

ответ

13

Это моя самая короткая 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...>; 

Demo. P обозначает пакеты, R - это (текущий) пакет результатов, f - это первый тип, а t - это хвост пакета, который в настоящее время наблюдается. T - это шаблон, в котором хранятся пакеты.

+1

Вау! Краткость вашего решения ставит мою долгую попытку позора! Я не думаю, что любой может найти более короткое решение, чем это! – prestokeys

3

Следующее может помочь, это использовать вспомогательный класс и агрегировать результат в первом шаблоне аргумента:

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; 
}; 

Live demo