Ich habe überprüft, ob es kompiliert wird. Aber was bedeutet es? Ist es ein Nicht-Typ-Parameter? Und wenn ja, wie können wir eine Vorlage ohne Typparameter haben?
Es ist durchaus möglich, eine Klasse auf einer Ganzzahl anstatt auf einem Typ zu erstellen. Wir können den Vorlagenwert einer Variablen zuweisen oder ihn auf andere Weise so bearbeiten, wie wir es mit einem anderen ganzzahligen Literal tun könnten:
unsignedint x = N;
Tatsächlich können wir Algorithmen erstellen, die zur Kompilierungszeit ausgewertet werden (aus Wikipedia ):
template<int N>structFactorial{enum{ value = N *Factorial<N -1>::value };};template<>structFactorial<0>{enum{ value =1};};// Factorial<4>::value == 24// Factorial<0>::value == 1void foo(){int x =Factorial<4>::value;// == 24int y =Factorial<0>::value;// == 1}
Sie können auch type static constexpr intanstelle von your verwenden enum. Also die Factorial<0>Vorlage hätte static constexpr int value = 1und template <int N> struct Factorialkann habenstatic constexpr int value = N * Factorial<N - 1>::value;
Bobobobo
@bobobobo dies wurde vor C ++ 11 und beantwortet constexpr.
Justin Meiners
153
Ja, es handelt sich um einen Parameter ohne Typ. Sie können verschiedene Arten von Vorlagenparametern verwenden
Geben Sie Parameter ein.
Typen
Vorlagen (nur Klassen- und Aliasvorlagen, keine Funktionen oder Variablenvorlagen)
Nicht typisierte Parameter
Zeiger
Verweise
Integrale konstante Ausdrücke
Was Sie dort haben, ist von letzter Art. Es ist eine Kompilierungszeitkonstante (sogenannter konstanter Ausdruck) und vom Typ Integer oder Enumeration. Nachdem ich es im Standard nachgeschlagen hatte, musste ich Klassenvorlagen in den Abschnitt Typen verschieben - obwohl Vorlagen keine Typen sind. Sie werden jedoch als Typparameter bezeichnet, um diese Arten dennoch zu beschreiben. Sie können Zeiger (und auch Elementzeiger) und Verweise auf Objekte / Funktionen haben, die eine externe Verknüpfung haben (solche, mit denen aus anderen Objektdateien verknüpft werden kann und deren Adresse im gesamten Programm eindeutig ist). Beispiele:
Parameter für den Vorlagentyp:
template<typename T>structContainer{
T t;};// pass type "long" as argument.Container<long> test;
Template Integer Parameter:
template<unsignedint S>structVector{unsignedchar bytes[S];};// pass 3 as argument.Vector<3> test;
Vorlagenzeigerparameter (Übergabe eines Zeigers an eine Funktion)
template<void(*F)()>structFunctionWrapper{staticvoid call_it(){ F();}};// pass address of function do_it as argument.void do_it(){}FunctionWrapper<&do_it> test;
Vorlagenreferenzparameter (Übergabe einer Ganzzahl)
template<int&A>structSillyExample{staticvoid do_it(){ A =10;}};// pass flag as argumentint flag;SillyExample<flag> test;
Vorlagenvorlagenparameter.
template<template<typename T>classAllocatePolicy>structPool{void allocate(size_t n){int*p =AllocatePolicy<int>::allocate(n);}};// pass the template "allocator" as argument. template<typename T>struct allocator {static T * allocate(size_t n){return0;}};Pool<allocator> test;
Eine Vorlage ohne Parameter ist nicht möglich. Eine Vorlage ohne explizites Argument ist jedoch möglich - sie enthält Standardargumente:
Johannes, werden Vorlagen unter "Typen" abgelegt? Ich dachte, sie wären die Typen, aus denen man sie machen kann, aber nicht die Typen selbst?
sbi
@sbi siehe die Erklärung: "Nachdem ich es im Standard nachgeschlagen hatte, musste ich Klassenvorlagen in den Typabschnitt verschieben - obwohl Vorlagen keine Typen sind. Sie werden jedoch als Typparameter bezeichnet, um diese Typen trotzdem zu beschreiben. ". In Fußnote 126 vom 14.1 / 2 heißt es. Es ist nur eine Klassifizierung, die vorgenommen wird, um Nicht-Typ-Parameter zu etwas zu machen, das einen Wert / eine Referenz deklariert, und Typparameter zu etwas, das einen Typ- oder Vorlagennamen deklariert.
Johannes Schaub - litb
@ JohannesSchaub-litb, also gibt es keine Möglichkeit, eine Vorlage mit beispielsweise std :: string einzugeben? wie die Klasse template <std :: string S> mit einem statischen Zähler, um eine eindeutige ID für jede andere Zeichenfolge zu erstellen? Hashing String zu Int wäre der einzige Weg leider richtig?
Relaxxx
1
Ich würde gerne sehen, dass diese Antwort mit Elementen von Vorlagenklassenmitgliedern vervollständigt wird, dh Vorlage <Typname C, Typname R, Typname P1, Typname P2> Strukturmystruktur <R (C :: *) (P1, P2)>
Johnny Pauling
Der Code mit SillyExamplekann von GCC 4.8.4 nicht kompiliert werden. Der erste Fehler ist the value of ‘flag’ is not usable in a constant expression. Es gibt auch andere Fehler
HEKTO
17
Sie templatisieren Ihre Klasse basierend auf einem 'unsigned int'.
Beispiel:
template<unsignedint N>classMyArray{public:private:double data[N];// Use N as the size of the array};int main(){MyArray<2> a1;MyArray<2> a2;MyArray<4> b1;
a1 = a2;// OK The arrays are the same size.
a1 = b1;// FAIL because the size of the array is part of the// template and thus the type, a1 and b1 are different types.// Thus this is a COMPILE time failure.}
Eine Vorlagenklasse ist wie ein Makro, nur viel weniger böse.
Stellen Sie sich eine Vorlage als Makro vor. Die Parameter der Vorlage werden in eine Klassen- (oder Funktions-) Definition eingesetzt, wenn Sie eine Klasse (oder Funktion) mithilfe einer Vorlage definieren.
Der Unterschied besteht darin, dass die Parameter "Typen" haben und übergebene Werte während der Kompilierung überprüft werden, wie Parameter an Funktionen. Die gültigen Typen sind Ihre regulären C ++ - Typen wie int und char. Wenn Sie eine Vorlagenklasse instanziieren, übergeben Sie einen Wert des von Ihnen angegebenen Typs. In einer neuen Kopie der Vorlagenklassendefinition wird dieser Wert überall dort eingesetzt, wo der Parametername in der ursprünglichen Definition enthalten war. Genau wie ein Makro.
Sie können auch die Typen " class" oder " typename" für Parameter verwenden (sie sind wirklich gleich). Mit einem Parameter eines dieser Typen können Sie anstelle eines Werts einen Typnamen übergeben. Wie zuvor wird der Parametername überall in der Vorlagenklassendefinition, sobald Sie eine neue Instanz erstellen, zu dem Typ, den Sie übergeben. Dies ist die häufigste Verwendung für eine Vorlagenklasse. Jeder, der etwas über C ++ - Vorlagen weiß, weiß, wie das geht.
Betrachten Sie diesen Beispielcode für Vorlagenklassen:
static constexpr int
anstelle von your verwendenenum
. Also dieFactorial<0>
Vorlage hättestatic constexpr int value = 1
undtemplate <int N> struct Factorial
kann habenstatic constexpr int value = N * Factorial<N - 1>::value;
constexpr
.Ja, es handelt sich um einen Parameter ohne Typ. Sie können verschiedene Arten von Vorlagenparametern verwenden
Was Sie dort haben, ist von letzter Art. Es ist eine Kompilierungszeitkonstante (sogenannter konstanter Ausdruck) und vom Typ Integer oder Enumeration. Nachdem ich es im Standard nachgeschlagen hatte, musste ich Klassenvorlagen in den Abschnitt Typen verschieben - obwohl Vorlagen keine Typen sind. Sie werden jedoch als Typparameter bezeichnet, um diese Arten dennoch zu beschreiben. Sie können Zeiger (und auch Elementzeiger) und Verweise auf Objekte / Funktionen haben, die eine externe Verknüpfung haben (solche, mit denen aus anderen Objektdateien verknüpft werden kann und deren Adresse im gesamten Programm eindeutig ist). Beispiele:
Parameter für den Vorlagentyp:
Template Integer Parameter:
Vorlagenzeigerparameter (Übergabe eines Zeigers an eine Funktion)
Vorlagenreferenzparameter (Übergabe einer Ganzzahl)
Vorlagenvorlagenparameter.
Eine Vorlage ohne Parameter ist nicht möglich. Eine Vorlage ohne explizites Argument ist jedoch möglich - sie enthält Standardargumente:
Syntaktisch
template<>
ist reserviert, um eine explizite Vorlagenspezialisierung anstelle einer Vorlage ohne Parameter zu markieren:quelle
SillyExample
kann von GCC 4.8.4 nicht kompiliert werden. Der erste Fehler istthe value of ‘flag’ is not usable in a constant expression
. Es gibt auch andere FehlerSie templatisieren Ihre Klasse basierend auf einem 'unsigned int'.
Beispiel:
quelle
Eine Vorlagenklasse ist wie ein Makro, nur viel weniger böse.
Stellen Sie sich eine Vorlage als Makro vor. Die Parameter der Vorlage werden in eine Klassen- (oder Funktions-) Definition eingesetzt, wenn Sie eine Klasse (oder Funktion) mithilfe einer Vorlage definieren.
Der Unterschied besteht darin, dass die Parameter "Typen" haben und übergebene Werte während der Kompilierung überprüft werden, wie Parameter an Funktionen. Die gültigen Typen sind Ihre regulären C ++ - Typen wie int und char. Wenn Sie eine Vorlagenklasse instanziieren, übergeben Sie einen Wert des von Ihnen angegebenen Typs. In einer neuen Kopie der Vorlagenklassendefinition wird dieser Wert überall dort eingesetzt, wo der Parametername in der ursprünglichen Definition enthalten war. Genau wie ein Makro.
Sie können auch die Typen "
class
" oder "typename
" für Parameter verwenden (sie sind wirklich gleich). Mit einem Parameter eines dieser Typen können Sie anstelle eines Werts einen Typnamen übergeben. Wie zuvor wird der Parametername überall in der Vorlagenklassendefinition, sobald Sie eine neue Instanz erstellen, zu dem Typ, den Sie übergeben. Dies ist die häufigste Verwendung für eine Vorlagenklasse. Jeder, der etwas über C ++ - Vorlagen weiß, weiß, wie das geht.Betrachten Sie diesen Beispielcode für Vorlagenklassen:
Es ist funktional dasselbe wie dieser Makro-verwendende Code:
Natürlich ist die Vorlagenversion milliardenfach sicherer und flexibler.
quelle