Templates
Ein Template ist eine C++-Entität, die eines der folgenden Elemente definiert
- eine Familie von Klassen (Klassentemplate), die verschachtelte Klassen sein können
- eine Familie von Funktionen (Funktionstemplates), die Member-Funktionen sein können
|
(seit C++11) |
|
(seit C++14) |
|
(seit C++20) |
Templates werden durch einen oder mehrere Template-Parameter parametrisiert, und zwar drei Arten: Typ-Template-Parameter, Nicht-Typ-Template-Parameter und Template-Template-Parameter.
Wenn Template-Argumente bereitgestellt werden oder, für Funktions- und Klassen(seit C++17)-Templates nur, abgeleitet werden, werden sie für die Template-Parameter substituiert, um eine *Spezialisierung* des Templates zu erhalten, d.h. einen spezifischen Typ oder einen spezifischen Funktions-Lvalue.
Spezialisierungen können auch explizit bereitgestellt werden: Vollständige Spezialisierungen sind für Klassen, Variablen(seit C++14) und Funktionstemplates erlaubt, partielle Spezialisierungen sind nur für Klassentemplates und Variable Templates(seit C++14) erlaubt.
Wenn eine Klassen-Template-Spezialisierung in einem Kontext referenziert wird, der einen vollständigen Objekttyp erfordert, oder wenn eine Funktions-Template-Spezialisierung in einem Kontext referenziert wird, der die Existenz einer Funktionsdefinition erfordert, wird das Template *instanziiert* (der Code dafür wird tatsächlich kompiliert), es sei denn, das Template wurde bereits explizit spezialisiert oder instanziiert. Die Instanziierung eines Klassentemplates instanziiert keine seiner Member-Funktionen, es sei denn, sie werden ebenfalls verwendet. Zur Link-Zeit werden identische Instanziierungen, die von verschiedenen Translation Units generiert wurden, zusammengeführt.
Die Definition eines Klassentemplates muss an der Stelle der impliziten Instanziierung sichtbar sein, weshalb Template-Bibliotheken typischerweise alle Template-Definitionen in Headern bereitstellen (z.B. die meisten Boost-Bibliotheken sind Header-only).
Inhalt |
[edit] Syntax
template <parameter-list > requires-clause (optional) declaration |
(1) | ||||||||
export template <parameter-list > declaration |
(2) | (bis C++11) | |||||||
template <parameter-list > concept concept-name = constraint-expression ; |
(3) | (seit C++20) | |||||||
| parameter-liste | - | eine nicht-leere, durch Kommas getrennte Liste der Template-Parameter, von denen jeder entweder ein Nicht-Typ-Parameter, ein Typ-Parameter, ein Template-Parameter, oder ein Parameter-Pack von beliebigen davon(seit C++11) ist. |
| requires-clause | - | (seit C++20) eine Requires-Klausel, die die Constraints für die Template-Argumente angibt. |
| Deklaration | - | Deklaration eines Klasse (einschließlich struct und union), eines Member-Klasse oder Member-Enumerationstyps, einer Funktion oder Member-Funktion, eines statischen Datenmembers auf Namespace-Ebene, einer Variablen oder eines statischen Datenmembers auf Klassenebene(seit C++14), oder eines Alias-Templates(seit C++11). Es kann auch eine Template-Spezialisierung definieren. |
| Konzeptname Constraint-Ausdruck |
- | siehe Constraints und Konzepte |
|
export war ein optionaler Modifikator, der das Template als *exportiert* deklarierte (wenn mit einem Klassentemplate verwendet, wurden auch alle seine Member exportiert). Dateien, die exportierte Templates instanziierten, mussten ihre Definitionen nicht einschließen: die Deklaration war ausreichend. Implementierungen von export waren selten und stimmten in Details nicht überein. |
(bis C++11) |
| Dieser Abschnitt ist unvollständig Grund: Kernsyntax, Template-Parameter und Instanziierungen, Übernahme gemeinsamer Inhalte zwischen class_template und function_template |
[edit] Template-Identifikatoren
Ein Template-Identifikator hat eine der folgenden Syntaxen
template-name <template-argument-list (optional)> |
(1) | ||||||||
operatorop <template-argument-list (optional)> |
(2) | ||||||||
operator "" identifier <template-argument-list (optional)> |
(3) | (seit C++11) (veraltet) | |||||||
operator user-defined-string-literal <template-argument-list (optional)> |
(4) | (seit C++11) | |||||||
| template-name | - | ein Bezeichner, der ein Template benennt |
| op | - | ein überladbarer Operator |
| identifier | - | ein Bezeichner |
| user-defined-string-literal | - | "" gefolgt von einem Bezeichner |
Ein einfacher Template-Identifikator, der ein Klassentemplate benennt, benennt eine Klasse.
Ein Template-Identifikator, der ein Alias-Template benennt, benennt einen Typ.
Ein Template-Identifikator, der eine Funktions-Template-Spezialisierung benennt, benennt eine Funktion.
Wenn alle folgenden Bedingungen erfüllt sind, ist ein Template-Identifikator *gültig*
- Es gibt höchstens so viele Argumente wie Parameter oder ein Parameter ist ein Template Parameter-Pack(seit C++11).
- Für jeden nicht-deduzierbaren Nicht-Pack(seit C++11) Parameter, der keinen Standard-Template-Argument hat, gibt es ein Argument.
- Jedes Template-Argument passt zum entsprechenden Template-Parameter.
- Die Substitution jedes Template-Arguments in die folgenden Template-Parameter (falls vorhanden) ist erfolgreich.
|
(seit C++20) |
Ein ungültiges einfaches Template-ID ist ein Kompilierungsfehler, es sei denn, es benennt eine Funktions-Template-Spezialisierung (in diesem Fall kann SFINAE angewendet werden).
template<class T, T::type n = 0> class X; struct S { using type = int; }; using T1 = X<S, int, int>; // error: too many arguments using T2 = X<>; // error: no default argument for first template parameter using T3 = X<1>; // error: value 1 does not match type-parameter using T4 = X<int>; // error: substitution failure for second template parameter using T5 = X<S>; // OK
|
Wenn der template-name eines einfachen Template-IDs ein eingeschränktes Nicht-Funktions-Template oder einen eingeschränkten Template-Template-Parameter benennt, aber kein Member-Template, das ein Mitglied einer unbekannten Spezialisierung ist, und alle Template-Argumente im einfachen Template-ID nicht-abhängig sind, müssen die zugehörigen Constraints des eingeschränkten Templates erfüllt sein. template<typename T> concept C1 = sizeof(T) != sizeof(int); template<C1 T> struct S1 {}; template<C1 T> using Ptr = T*; S1<int>* p; // error: constraints not satisfied Ptr<int> p; // error: constraints not satisfied template<typename T> struct S2 { Ptr<int> x; }; // error, no diagnostic required template<typename T> struct S3 { Ptr<T> x; }; // OK, satisfaction is not required S3<int> x; // error: constraints not satisfied template<template<C1 T> class X> struct S4 { X<int> x; // error, no diagnostic required }; template<typename T> concept C2 = sizeof(T) == 1; template<C2 T> struct S {}; template struct S<char[2]>; // error: constraints not satisfied template<> struct S<char[2]> {}; // error: constraints not satisfied |
(seit C++20) |
Wenn alle folgenden Bedingungen erfüllt sind, sind zwei Template-Identifikatoren *gleich*
- Ihre template-name oder Operatoren beziehen sich auf dasselbe Template.
- Ihre entsprechenden Typ-Template-Argumente sind derselbe Typ.
- Die durch ihre entsprechenden Nicht-Typ-Template-Argumente bestimmten Template-Parameterwerte sind Template-Argument-äquivalent.
- Ihre entsprechenden Template-Template-Argumente beziehen sich auf dasselbe Template.
Zwei Template-Identifikatoren, die gleich sind, beziehen sich auf dieselbe Variable,(seit C++14) Klasse oder Funktion.
[edit] Templated Entity
Eine *templated entity* (oder in einigen Quellen "temploid") ist jede Entität, die innerhalb einer Template-Definition definiert (oder, für einen Lambda-Ausdruck, erstellt)(seit C++11) wird. Alle folgenden sind templated entities
- ein Klassen-/Funktions/Variablen(seit C++14)-Template
|
(seit C++20) |
- ein Mitglied einer templated entity (z.B. eine Nicht-Template-Member-Funktion eines Klassentemplates)
- ein Aufzähler einer Aufzählung, die eine templated entity ist
- jede Entität, die innerhalb einer templated entity definiert oder erstellt wird: eine lokale Klasse, eine lokale Variable, eine Freundschaftsfunktion usw.
|
(seit C++11) |
Zum Beispiel in
template<typename T> struct A { void f() {} };
ist die Funktion `A::f` kein Funktionstemplates, wird aber trotzdem als templated betrachtet.
Eine *templated function* ist ein Funktionstemplates oder eine Funktion, die templated ist.
Eine *templated class* ist ein Klassentemplate oder eine Klasse, die templated ist.
|
Eine *templated variable* ist ein Variable Template oder eine Variable, die templated ist. |
(seit C++14) |
[edit] Schlüsselwörter
[edit] Fehlerberichte
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 2293 | C++98 | Die Regeln zur Bestimmung, ob ein Template Identifikator gültig ist, wurden nicht bereitgestellt |
bereitgestellt |
| CWG 2682 | C++98 C++14 |
Die Definitionen von templated function/template class (C++98)/templated variable (C++14) fehlten |
hinzugefügt |
| P2308R1 | C++98 | Zwei Template-Identifikatoren waren unterschiedlich, wenn ihre entsprechenden Nicht-Typ-Template-Argumente nicht template-argument-equivalent sind |
Sie sind unterschiedlich, wenn ihre entsprechenden Nicht-Typ-Template-Parameterwerte nicht template-argument-equivalent sind |
[edit] Siehe auch
| C-Dokumentation für Generische Auswahl
|