2015-04-27 17 views
5

Rozważmy następujący kod w pełni robocze:Indeksy trik stosowany dla kilku składników

#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"); 
} 

Co faktycznie chcę być wyjście jest

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

zamiast Pack<2,3,4,5, -3,-6,-9,-12, 0,1,2,3>. Najpierw wypróbowałem

ale jest to po prostu zrozumiałe przez kompilator być bezużytecznym operatorem przecinka. Jaka jest pożądana składnia, aby uzyskać to, czego chcę? Jeśli nie ma takiej składni, jaki jest najczystszy sposób, aby to zrobić, pamiętając, że trzykrotne użycie numeru Indices jest tylko przykładem (możemy chcieć go użyć więcej niż 3 razy). Proszę nie mówić mi, że muszę napisać pomocnika, aby wyodrębnić poszczególne paczki, a następnie "przeplatać" wszystkie elementy. Ta koszmarna metoda nie może być najlepszym rozwiązaniem (i takie rozwiązanie zadziałałoby tylko wtedy, gdybyśmy dokładnie wiedzieli, ile pojedynczych pakietów do wyodrębnienia).

Czy definiowania

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

jakoś pomóc? Dodać do tego rozszerzenie paczki?

+0

Nie jestem pewien, pisząc funkcję do zrobienia czegoś jest tak koszmarny - to jest dokładnie to, co byś zrobił jakbyś próbował zrobić to samo coś w * runtime *. – Hurkyl

+0

@Hurkyl. W rzeczywistości nie jest tak koszmarnie, masz rację. Jednak poniższe rozwiązanie Columbo jest znacznie lepsze. – prestokeys

Odpowiedz

4

Tak, można Concat rekurencyjnie:

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, T F > 
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

+0

Uderzyłeś mnie w to. – orlp

+0

@orlp Wiem, jak to jest. – Columbo

0

ta była inspirowana przez Columbo za rozwiązanie. Używa składni Dodatek że pierwotnie zamierzonego, a mianowicie

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

W rezultacie teraz Make jest wielokrotnego użytku, najpierw za pomocą Triple, a następnie za pomocą Quadruple, więc dowolna liczba zwyczajów Indices można rozszerzyć jednocześnie. Tutaj Component jest parametrem szablonu szablon szablon przeszedł do 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"); 
} 
Powiązane problemy