Namespaces
Variants

Template parameters

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Jede Template wird durch einen oder mehrere Template-Parameter parametrisiert.

Jeder Parameter in der template-parameter-list (siehe template declaration syntax ) gehört zu einer der folgenden Kategorien:

  • konstanter Template-Parameter
  • Typ-Template-Parameter
  • Template-Template-Parameter

Inhaltsverzeichnis

Konstanter Template-Parameter

Auch bekannt als non-type template parameter (siehe unten ).

Typ Name  (optional) (1)
Typ Name  (optional) = Standardwert (2)
Typ ... Name  (optional) (3) (seit C++11)
type - einer der folgenden Typen:
  • ein struktureller Typ (siehe unten)
(seit C++17)
(seit C++20)
name - der Name des konstanten Template-Parameters
default - das Standard-Template-Argument
1) Ein konstanter Template-Parameter.
2) Ein konstanter Template-Parameter mit einem Standard-Template-Argument.
3) Ein konstanter Template- Parameter Pack .


Ein struktureller Typ ist einer der folgenden Typen (optional cv-qualifiziert, die Qualifizierer werden ignoriert):

(seit C++11)
  • alle Basisklassen und nicht-statischen Datenelemente sind öffentlich und nicht-veränderlich und
  • die Typen aller Basisklassen und nicht-statischen Datenelemente sind strukturelle Typen oder (möglicherweise mehrdimensionale) Arrays davon.
(seit C++20)

Array- und Funktionstypen können in einer Template-Deklaration geschrieben werden, werden jedoch automatisch durch Zeiger auf Objekt und Zeiger auf Funktion entsprechend ersetzt.

Wenn der Name eines konstanten Template-Parameters in einem Ausdruck innerhalb des Rumpfs des Klassentemplates verwendet wird, ist es ein nicht modifizierbarer prvalue , es sei denn, sein Typ war ein Lvalue-Referenztyp , oder es sei denn, sein Typ ist ein Klassentyp (since C++20) .

Ein Template-Parameter der Form class Foo ist kein unbenannter konstanter Template-Parameter vom Typ Foo , selbst wenn ansonsten class Foo ein elaborated type specifier ist und class Foo x ; x als vom Typ Foo deklariert.

Ein Bezeichner , der einen konstanten Template-Parameter vom Klassentyp T benennt, bezeichnet ein Objekt mit statischer Speicherdauer vom Typ const T , genannt ein Template-Parameter-Objekt , das Template-Argument-Äquivalenz zum entsprechenden Template-Argument aufweist, nachdem es in den Typ des Template-Parameters konvertiert wurde. Keine zwei Template-Parameter-Objekte sind template-argument-äquivalent.

struct A
{
    friend bool operator==(const A&, const A&) = default;
};
template<A a>
void f()
{
    &a;                       // OK
    const A& ra = a, &rb = a; // Both bound to the same template parameter object
    assert(&ra == &rb);       // passes
}
(seit C++20)

Typ-Template-Parameter

type-parameter-key name  (optional) (1)
type-parameter-key name  (optional) = default (2)
type-parameter-key ... name  (optional) (3) (seit C++11)
type-constraint name  (optional) (4) (seit C++20)
type-constraint name  (optional) = default (5) (seit C++20)
type-constraint ... name  (optional) (6) (seit C++20)
type-parameter-key - entweder typename oder class . Es gibt keinen Unterschied zwischen diesen Schlüsselwörtern in einer Typ-Template-Parameterdeklaration
type-constraint - entweder der Name eines Konzepts oder der Name eines Konzepts gefolgt von einer Liste von Template-Argumenten (in spitzen Klammern). In beiden Fällen kann der Konzeptname optional qualifiziert sein
name - der Name des Typ-Template-Parameters
default - das Standard-Template-Argument
1) Ein Typ-Template-Parameter ohne Standardwert.
template<class T>
class My_vector { /* ... */ };
2) Ein Typ-Template-Parameter mit einem Standardwert.
template<class T = void>
struct My_op_functor { /* ... */ };
3) Ein Typ-Template Parameterpaket .
template<typename... Ts>
class My_tuple { /* ... */ };
4) Ein eingeschränkter Typ-Template-Parameter ohne Standardwert.
template<My_concept T>
class My_constrained_vector { /* ... */ };
5) Ein eingeschränkter Typ-Template-Parameter mit einem Standardwert.
template<My_concept T = void>
class My_constrained_op_functor { /* ... */ };
6) Ein eingeschränkter Typ-Template Parameter Pack .
template<My_concept... Ts>
class My_constrained_tuple { /* ... */ };


Der Name des Parameters ist optional:

// Deklarationen der oben gezeigten Templates:
template<class>
class My_vector;
template<class = void>
struct My_op_functor;
template<typename...>
class My_tuple;

Im Rumpf der Template-Deklaration ist der Name eines Typparameters ein Typalias-Name, der den Typ referenziert, der bei der Instanziierung des Templates angegeben wird.

Jeder eingeschränkte Parameter P , dessen Typ-Einschränkung Q das Konzept C bezeichnet, führt einen Constraint-Ausdruck E gemäß den folgenden Regeln ein:

  • falls Q gleich C ist (ohne Argumentliste),
  • wenn P kein Parameter-Pack ist, dann ist E einfach C<P>
  • andernfalls, wenn P ein Parameter-Pack ist, dann ist E ein Fold-Ausdruck (C<P> && ...)
  • falls Q gleich C<A1,A2...,AN> ist, dann ist E entsprechend C<P,A1,A2,...AN> oder (C<P,A1,A2,...AN> && ...) .
template<typename T>
concept C1 = true;
template<typename... Ts> // variadic concept
concept C2 = true;
template<typename T, typename U>
concept C3 = true;
template<C1 T>         struct s1; // constraint-expression is C1<T>
template<C1... T>      struct s2; // constraint-expression is (C1<T> && ...)
template<C2... T>      struct s3; // constraint-expression is (C2<T> && ...)
template<C3<int> T>    struct s4; // constraint-expression is C3<T, int>
template<C3<int>... T> struct s5; // constraint-expression is (C3<T, int> && ...)
(seit C++20)

Template-Template-Parameter

template < parameter-list > type-parameter-key name  (optional) (1)
template < parameter-list > type-parameter-key name  (optional) = default (2)
template < parameter-list > type-parameter-key ... name  (optional) (3) (seit C++11)
type-parameter-key - class oder typename (seit C++17)
1) Ein Template-Template-Parameter mit einem optionalen Namen.
2) Ein Template-Template-Parameter mit einem optionalen Namen und einem Standardwert.
3) Eine Template-Template parameter pack mit einem optionalen Namen.


Im Rumpf der Template-Deklaration ist der Name dieses Parameters ein Template-Name (und benötigt Argumente zur Instanziierung).

template<typename T>
class my_array {};
// Zwei Typ-Template-Parameter und ein Template-Template-Parameter:
template<typename K, typename V, template<typename> typename C = my_array>
class Map
{
    C<K> key;
    C<V> value;
};

Namensauflösung für Template-Parameter

Der Name eines Template-Parameters darf innerhalb seines Gültigkeitsbereichs (einschließlich verschachtelter Gültigkeitsbereiche) nicht erneut deklariert werden. Ein Template-Parameter darf nicht denselben Namen wie der Template-Name haben.

template<class T, int N>
class Y
{
    int T;      // Fehler: Template-Parameter neu deklariert
    void f()
    {
        char T; // Fehler: Template-Parameter neu deklariert
    }
};
template<class X>
class X; // Fehler: Template-Parameter neu deklariert

In der Definition eines Members einer Klassenvorlage, die außerhalb der Klassenvorlagendefinition erscheint, verdeckt der Name eines Members der Klassenvorlage den Namen eines Template-Parameters einer beliebigen umschließenden Klassenvorlage, jedoch nicht einen Template-Parameter des Members, wenn der Member eine Klassen- oder Funktionsvorlage ist.

template<class T>
struct A
{
    struct B {};
    typedef void C;
    void f();
    template<class U>
    void g(U);
};
template<class B>
void A<B>::f()
{
    B b; // A's B, nicht der Template-Parameter
}
template<class B>
template<class C>
void A<B>::g(C)
{
    B b; // A's B, nicht der Template-Parameter
    C c; // der Template-Parameter C, nicht A's C
}

In der Definition eines Members einer Klassenvorlage, die außerhalb des Namensraums erscheint, der die Klassenvorlagendefinition enthält, verdeckt der Name eines Template-Parameters den Namen eines Members dieses Namensraums.

namespace N
{
    class C {};
    template<class T>
    class B
    {
        void f(T);
    };
}
template<class C>
void N::B<C>::f(C)
{
    C b; // C ist der Template-Parameter, nicht N::C
}

In der Definition eines Klassentemplates oder in der Definition eines Members eines solchen Templates, die außerhalb der Templatedefinition erscheint, verdeckt für jede nicht- abhängige Basisklasse, wenn der Name der Basisklasse oder der Name eines Members der Basisklasse mit dem Namen eines Template-Parameters übereinstimmt, der Basisklassenname oder Membername den Template-Parameternamen.

struct A
{
    struct B {};
    int C;
    int Y;
};
template<class B, class C>
struct X : A
{
    B b; // A's B
    C b; // Fehler: A's C ist kein Typname
};

Standardmäßige Template-Argumente

Standardmäßige Template-Argumente werden in den Parameterlisten nach dem = Zeichen angegeben. Standardwerte können für jede Art von Template-Parameter (Typ, Konstante oder Template) , jedoch nicht für Parameter-Packs (since C++11) spezifiziert werden.

Wenn für einen Template-Parameter eines primären Klassentemplates ein Standardwert angegeben wird , eines primären Variablen-Templates, (seit C++14) muss jeder nachfolgende Template-Parameter ein Standardargument haben , außer der letzte kann ein Template-Parameterpaket sein (seit C++11) . In einem Funktions-Template gibt es keine Einschränkungen für Parameter, die einem Standardwert folgen , und ein Parameterpaket kann nur dann von weiteren Typparametern gefolgt werden, wenn diese Standardwerte haben oder von den Funktionsargumenten abgeleitet werden können (seit C++11) .

Standardparameter sind nicht erlaubt

  • in der außerhalb der Klasse befindlichen Definition eines Members einer Klassenvorlage (diese müssen in der Deklaration innerhalb des Klassenkörpers bereitgestellt werden). Beachten Sie, dass Membervorlagen von Nicht-Vorlagenklassen Standardparameter in ihren außerhalb der Klasse befindlichen Definitionen verwenden können (siehe GCC Bug 53856 )
  • in friend-Klassenvorlagen Deklarationen
(bis C++11)

Bei einer Friend-Funktionstemplate-Deklaration sind Standard-Template-Argumente nur zulässig, wenn die Deklaration eine Definition ist und keine weiteren Deklarationen dieser Funktion in dieser Übersetzungseinheit auftreten.

(since C++11)

Standardmäßige Template-Argumente, die in den Deklarationen erscheinen, werden ähnlich wie Standard-Funktionsargumente zusammengeführt:

template<typename T1, typename T2 = int> class A;
template<typename T1 = int, typename T2> class A;
// die obigen Zeilen entsprechen der folgenden:
template<typename T1 = int, typename T2 = int> class A;

Derselbe Parameter kann jedoch nicht zweimal in demselben Gültigkeitsbereich mit Standardargumenten versehen werden:

template<typename T = int> class X;
template<typename T = int> class X {}; // Fehler

Beim Parsen eines Standard-Template-Arguments für einen konstanten Template-Parameter wird das erste nicht-geschachtelte > als Ende der Template-Parameterliste interpretiert und nicht als Größer-als-Operator:

template<int i = 3 > 4>   // Syntaxfehler
class X { /* ... */ };
template<int i = (3 > 4)> // OK
class Y { /* ... */ };

Die Template-Parameterlisten von Template-Template-Parametern können ihre eigenen Standardargumente haben, die nur wirksam sind, wo der Template-Template-Parameter selbst im Gültigkeitsbereich ist:

// Klassentemplate mit einem Typ-Template-Parameter mit einem Standardwert
template<typename T = float>
struct B {};
// Template-Template-Parameter T hat eine Parameterliste, die
// aus einem Typ-Template-Parameter mit einem Standardwert besteht
template<template<typename = float> typename T>
struct A
{
    void f();
    void g();
};
// Out-of-Body-Memberfunktions-Template-Definitionen
template<template<typename TT> class T>
void A<T>::f()
{
    T<> t; // Fehler: TT hat keinen Standardwert im Gültigkeitsbereich
}
template<template<typename TT = char> class T>
void A<T>::g()
{
    T<> t; // OK: t ist T<char>
}

Memberenzugriff für die in einem Standard-Template-Parameter verwendeten Namen wird bei der Deklaration überprüft, nicht an der Stelle der Verwendung:

class B {};
template<typename T>
class C
{
protected:
    typedef T TT;
};
template<typename U, typename V = typename U::TT>
class D: public U {};
D<C<B>>* d; // Fehler: C::TT ist geschützt

Das Standard-Template-Argument wird implizit instanziiert, wenn der Wert dieses Standardarguments benötigt wird, außer wenn das Template zur Benennung einer Funktion verwendet wird:

template<typename T, typename U = int>
struct S {};
S<bool>* p; // The default argument for U is instantiated at this point
            // the type of p is S<bool, int>*
(since C++14)

Hinweise

Vor C++26 wurden konstante Template-Parameter in der Standardformulierung als Nicht-Typ-Template-Parameter bezeichnet. Die Terminologie wurde geändert durch P2841R6 / PR#7587 .

In Template-Parametern können Typ-Einschränkungen sowohl für Typ- als auch für Konstanten-Parameter verwendet werden, abhängig davon, ob auto vorhanden ist.

template<typename>
concept C = true;
template<C,     // type parameter 
         C auto // constant parameter
        >
struct S{};
S<int, 0> s;


(since C++20)
Feature-Test-Makro Wert Std Feature
__cpp_nontype_template_parameter_auto 201606L (C++17) Deklaration von konstanten Template-Parametern mit auto
__cpp_nontype_template_args 201411L (C++17) Erlaubt konstante Auswertung für alle konstanten Template-Argumente
201911L (C++20) Klassentypen und Gleitkommatypen in konstanten Template-Parametern

Beispiele

#include <array>
#include <iostream>
#include <numeric>
// einfacher konstanter Template-Parameter
template<int N>
struct S { int a[N]; };
template<const char*>
struct S2 {};
// komplexes Konstanten-Beispiel
template
<
    char c,             // integraler Typ
    int (&ra)[5],       // Lvalue-Referenz auf Objekt (vom Array-Typ)
    int (*pf)(int),     // Zeiger auf Funktion
    int (S<10>::*a)[10] // Zeiger auf Member-Objekt (vom Typ int[10])
>
struct Complicated
{
    // ruft die zur Kompilierzeit ausgewählte Funktion auf
    // und speichert das Ergebnis im zur Kompilierzeit ausgewählten Array
    void foo(char base)
    {
        ra[4] = pf(c - base);
    }
};
//  S2<"fail"> s2;        // Fehler: Zeichenkette kann nicht verwendet werden
    char okay[] = "okay"; // statisches Objekt mit Verknüpfung
//  S2<&okay[0]> s3;      // Fehler: Array-Element hat keine Verknüpfung
    S2<okay> s4;          // funktioniert
int a[5];
int f(int n) { return n; }
// C++20: NTTP kann ein Literal-Klassentyp sein
template<std::array arr>
constexpr
auto sum() { return std::accumulate(arr.cbegin(), arr.cend(), 0); }
// C++20: Klassen-Template-Argumente werden am Aufrufort abgeleitet
static_assert(sum<std::array<double, 8>{3, 1, 4, 1, 5, 9, 2, 6}>() == 31.0);
// C++20: NTTP-Argumentableitung und CTAD
static_assert(sum<std::array{2, 7, 1, 8, 2, 8}>() == 28);
int main()
{
    S<10> s; // s.a ist ein Array von 10 int
    s.a[9] = 4;
    Complicated<'2', a, f, &S<10>::a> c;
    c.foo('0');
    std::cout << s.a[9] << a[4] << '\n';
}

Ausgabe:

42

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 184 C++98 ob Template-Parameter von Template-Template-Parametern
Standardargumente haben dürfen, war nicht spezifiziert
Spezifikation hinzugefügt
CWG 1922 C++98 es war unklar, ob ein Klassentemplate, dessen Name ein
injizierter Klassenname ist, Standardargumente aus früheren Deklarationen verwenden kann
erlaubt
CWG 2032 C++14 für Variablen-Templates gab es keine Einschränkung für die Template-Parameter
nach einem Template-Parameter mit einem Standardargument
dieselbe Einschränkung anwenden
wie bei Klassentemplates
und Alias-Templates
CWG 2542 C++20 es war unklar, ob der Closure-Typ strukturell ist er ist nicht strukturell
CWG 2845 C++20 der Closure-Typ war nicht strukturell er ist strukturell
wenn erfanglos