Index trick used for multiple components

Consider this fully working code:

#include <type_traits> template <typename T, typename IndexPack> struct Make; template <typename T, template <T...> class P, T... Indices> struct Make<T, P<Indices...>> { using type = P<(Indices+1)..., (-3*Indices)..., (Indices-1)...>; }; template <int...> class Pack; int main() { static_assert (std::is_same<Make<int, Pack<1,2,3,4>>::type, Pack<2,3,4,5, -3,-6,-9,-12, 0,1,2,3>>::value, "false"); } 

In fact, I want the output to be

 Pack<2,-3,0, 3,-6,1, 4,-9,2, 5,-12,3> 

instead of Pack<2,3,4,5, -3,-6,-9,-12, 0,1,2,3> . I tried it first

 using type = P<(Indices+1, -3*Indices, Indices-1)...>; 

but this is simply understood by the compiler as a useless comma operator. What is the desired syntax for getting what I want? If there is no such syntax, then what is the cleanest way to do this, bearing in mind that using Indices 3 times is just an example (we can use it more than 3 times). Please do not tell me that I should write an assistant to extract individual packages, and then "twist" all the elements. This nightmare method may not be the best solution (and such a solution will also work only if we know exactly how many individual packages to remove).

Would determine

 template <typename T, template <T...> class P, T I> struct Component { using type = P<I+1, -3*I, I-1>; }; 

help me somehow? Do package extension on this?

+5
source share
2 answers

Yes, you can do it recursively:

 template <typename, typename, typename> struct Concat; template <typename T, template <T...> class P, T... A, T... B> struct Concat<T, P<A...>, P<B...>> { using type = P<A..., B...>; }; template <typename T, typename IndexPack> struct Make; template <typename T, template <T...> class P, T... I, TF > struct Make<T, P<F, I...>> { using type = typename Concat<T, typename Make<T, P<F>>::type, typename Make<T, P<I...>>::type>::type; }; template <typename T, template <T...> class P, T I> struct Make<T, P<I>> { using type = P<I+1, -3*I, I-1>; }; 

Demo

+4
source

This was inspired by the Columbo decision. It uses the package extension syntax that I originally looked for, namely

 using type = typename Merge<T, typename Component<T, P, Indices>::type...>::type; 

As a result, Make can now be reused, first using Triple and then using Quadruple , so any number of Indices can be deployed at once. Here, Component is a template-template-template parameter passed to Make :

 #include <type_traits> template <typename T, typename... Packs> struct Merge; template <typename T, template <T...> class P1, template <T...> class P2, T... Is, T... Js> struct Merge<T, P1<Is...>, P2<Js...>> { using type = P1<Is..., Js...>; }; template <typename T, typename Pack1, typename Pack2, typename... Packs> struct Merge<T, Pack1, Pack2, Packs...> { using type = typename Merge<T, Pack1, typename Merge<T, Pack2, Packs...>::type>::type; }; template <typename T, template <T...> class P, T I> struct Triple { using type = P<I+1, -3*I, I-1>; }; template <typename T, template <T...> class P, T I> struct Quadruple { using type = P<I+1, -3*I, I-1, I>; }; template <typename T, typename IndexPack, template <typename U, template <U...> class P, U I> class Component> struct Make; template <typename T, template <T...> class Z, T... Indices, template <typename U, template <U...> class P, U I> class Component> struct Make<T, Z<Indices...>, Component> { using type = typename Merge<T, typename Component<T, Z, Indices>::type...>::type; }; template <int...> class Pack; int main() { static_assert (std::is_same<Make<int, Pack<1,2,3,4>, Triple>::type, Pack<2,-3,0, 3,-6,1, 4,-9,2, 5,-12,3>>::value, "false"); static_assert (std::is_same<Make<int, Pack<1,2,3,4>, Quadruple>::type, Pack<2,-3,0,1, 3,-6,1,2, 4,-9,2,3, 5,-12,3,4>>::value, "false"); } 
0
source

All Articles