2015-04-27 3 views
5

Betrachten Sie diese voll funktionsfähige Code:Indizes Trick für mehrere Komponenten verwendet

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

Was ich will eigentlich der Ausgang zu sein, ist

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

statt Pack<2,3,4,5, -3,-6,-9,-12, 0,1,2,3>. Ich versuchte zuerst

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

, aber das wird einfach vom Compiler als ein nutzloser Komma-Operator verstanden. Was ist die gewünschte Syntax um zu bekommen was ich will? Wenn es keine solche Syntax gibt, was ist der sauberste Weg, dies zu tun, wenn man bedenkt, dass die Verwendung von Indices 3 mal nur ein Beispiel ist (wir können es mehr als 3 mal verwenden). Bitte sag mir nicht, dass ich einen Helfer schreiben muss, um die einzelnen Pakete zu extrahieren und dann alle Elemente zu "verschachteln". Diese alptraumhafte Methode kann nicht die beste Lösung sein (und eine solche Lösung würde auch nur funktionieren, wenn wir genau wüssten, wie viele einzelne Pakete extrahiert werden müssen).

Würde die Definition

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

Hilfe irgendwie? Machen Sie eine Pack-Erweiterung auf diesem?

+0

Ich bin nicht sicher, ob eine Funktion zu schreiben, etwas zu tun sind, so alptraum - es ist genau das, was Sie tun würden, wenn Sie das gleiche zu tun versuchen, etwas zur Laufzeit *. – Hurkyl

+0

@Hurkyl. Es ist nicht so albtraumhaft, du hast Recht. Die Lösung von Columbo ist jedoch weitaus besser. – prestokeys

Antwort

4

Ja, können Sie concat rekursiv:

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

Sie haben mich dazu geschlagen. – orlp

+0

@orlp Ich weiß, wie es sich anfühlt. – Columbo

0

Dies wurde inspiriert von Columbo-Lösung. Es nutzt die Expansion Pack Syntax, die ich ursprünglich gesucht, nämlich

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

Als Ergebnis jetzt Make ist wiederverwendbar, erste Triple verwenden und dann Quadruple verwenden, so eine beliebige Anzahl von Nutzungen Indices gleichzeitig erweitert werden. Hier Component sind ein Template-Template-Template-Parameter in Make geben:

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