2016-03-28 4 views
4

Ich versuche, den Typ am angegebenen Index in einem Parameter-Pack mit Vorlage Metaprogrammierung zu erhalten. Ich habe den Code unten, aber aus irgendeinem Grund gibt es immer eine int zurück, könnte mir jemand sagen, was ich falsch mache?Wie man Template-Spezialisierungen abrollt

#include <string> 
#include <iostream> 
using std::cout; 
using std::endl; 
using std::string; 

template <int current_index, typename... Vs> 
struct TypeForIndex {}; 
template <int current_index, typename Head, typename... Tail> 
struct TypeForIndex<current_index, Head, Tail...> : private TypeForIndex<current_index + 1> { 
    using type = Head; 
}; 
template <int current_index, typename Tail> 
struct TypeForIndex<current_index, Tail> { 
    using type = Tail; 
}; 

int main() { 

    TypeForIndex <2, int, double, string>::type a {"hello"}; 
    cout << a << endl; 

    return 0; 
} 

Der obige Code sollte string als Typ für a zurück, aber irgendwie ist es immer eine int

Antwort

7
TypeForIndex<2, int, double, string> 

ok, Pattern-Matching-Zeit. Erstens passt es eindeutig

template <int current_index, typename... Vs> 
struct TypeForIndex {}; 

so kein Fehler. Passt es zu anderen Spezialisierungen?

A:

template <int current_index, typename Head, typename... Tail> 
struct TypeForIndex<current_index, Head, Tail...> 

B:

template <int current_index, typename Tail> 
struct TypeForIndex<current_index, Tail> 

Nun, passt es (A) und nicht (B).

mit (A), ist current_index2, Head ist int und Tail...double, std::string ist.

template <int current_index, typename Head, typename... Tail> 
struct TypeForIndex<current_index, Head, Tail...> : private TypeForIndex<current_index + 1> { 
    using type = Head; 
}; 

Jetzt ist die private TypeForIndex<current_index + 1> ziemlich nutzlos. Es entspricht immer nur der primären Spezialisierung, die einen leeren Körper hat, und es ist privat, so dass niemand es bemerken wird. Wir können es entfernen, ohne das Verhalten Ihres Programms zu ändern.

template <int current_index, typename Head, typename... Tail> 
struct TypeForIndex<current_index, Head, Tail...> { 
    using type = Head; 
}; 

Wie oben erwähnt, ist Headint. So erhalten wir type=int.

Und das ist es. Deshalb ist typeint.

...

Was falsch Sie tun, ist fast alles? Abgesehen von der Kompilierung (dh die primäre Spezialisierung existiert, die der Signatur entspricht), hat der von Ihnen angegebene Code nichts mit dem zu tun, was Sie in Ihrem Text beschreiben. Auch current_index+1 ist eine Zeichenfolge, die ich nicht erwarten würde, in Code zu existieren, der tut, was Ihr Text beschreibt.

alles außer der primären Spezialisierung Haufen zu werfen, das funktioniert:

template <typename Head, typename... Tail> 
struct TypeForIndex<0, Head, Tail...> { 
    using type = Head; 
}; 
template <int current_index, typename Head, typename... Tail> 
struct TypeForIndex<current_index, Head, Tail...>: 
    TypeForIndex<current_index-1, Tail...> 
{}; 

und es fehlt richtig eine Definition für type, wenn Sie einen zu großen Index passieren.

Ich würde auch eine size_t nicht eine int verwenden.

2

Hier ist Ihre Lösung.

#include <string> 
#include <iostream> 
using std::cout; 
using std::endl; 
using std::string; 

template <int current_index, typename... Vs> 
struct TypeForIndex {}; 

template <int current_index, typename Head, typename... Tail> 
struct TypeForIndex<current_index, Head, Tail...> : TypeForIndex<current_index - 1, Tail...> {}; 

template <typename Head, typename... Tail> 
struct TypeForIndex<0, Head, Tail...> { 
    using type = Head; 
}; 

int main() { 
    TypeForIndex <2, int, double, string, char>::type a ("hello"); 
    cout << a << endl; 
} 
+0

oben Das ist nur ein Update soweit ersetzt 'TypeForIndex <2, int, double, string> :: Baumuster zur mit' string' ist fix: http: //coliru.stacked-crooked.com/a/d2876707b8677e26 - es gibt den richtigen Typ zurück, ist aber nicht korrekt. In dem Link habe ich am Ende des Pakets einen "char" -Typ hinzugefügt, und der Code kann nicht kompiliert werden. – Yakk

+1

Ja. Ich habe gerade seinen Code bearbeitet, bis er kompiliert wurde. Ich wusste nicht, dass er noch mehr Fehler hatte. Ich fügte den fehlenden 'Schwanz ...' dem Code hinzu. – prestokeys

+0

@prestokeys Vielen Dank für Ihre Antwort! Ihr hat mir genauso viel Sinn gemacht, aber ich werde weitermachen und Yakks Antwort akzeptieren, nur weil es eine bessere Erklärung hat. Ich habe dich mit den 15 Punkten aufgewertet! – Curious