2015-04-27 19 views
5

Considerate questo codice completamente funzionante:Indici trucco usato per diversi componenti

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

Quello che in realtà voglio l'uscita per essere è

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

invece di Pack<2,3,4,5, -3,-6,-9,-12, 0,1,2,3>. Ho provato per la prima volta

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

ma questo è semplicemente capito dal compilatore come un operatore virgola inutile. Qual è la sintassi desiderata per ottenere ciò che voglio? Se non esiste una tale sintassi, qual è il modo più pulito per farlo, tenendo presente che l'utilizzo di Indices 3 volte è solo un esempio (potremmo volerlo utilizzare più di 3 volte). Per favore non dirmi che devo scrivere un aiutante per estrarre i singoli pacchetti e quindi "intrecciare" tutti gli elementi. Quel metodo da incubo non può essere la soluzione migliore (e una soluzione del genere funzionerebbe anche solo se sapessimo esattamente quanti singoli pacchetti estrarre).

Sarebbe definire

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

aiuto in qualche modo? Fai un'espansione di pacchetto su questo?

+0

Non sono sicuro che scrivere una funzione per fare qualcosa è così da incubo - è esattamente quello che si potrebbe fare se si stava tentando di fare lo stesso sorta di cosa a * runtime *. – Hurkyl

+0

@Hurkyl. In realtà non è così da incubo, hai ragione. Ma la soluzione di Columbo qui sotto è di gran lunga migliore. – prestokeys

risposta

4

Sì, è possibile concat in modo ricorsivo:

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

Mi hai battuto. – orlp

+0

@orlp So come ci si sente. – Columbo

0

Questo è stato ispirato da una soluzione di Columbo. Si utilizza la sintassi di espansione pack che ho inizialmente cercato, cioè

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

Come risultato, ora Make è riutilizzabile, prima con Triple, e quindi utilizzando Quadruple, in modo che qualsiasi numero di utilizzi di Indices può essere espansa simultaneamente. Qui Component è un parametro di modello-modello-modello passata alla 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"); 
} 
Problemi correlati