Template-Parameter und Template-Argumente
Inhalt |
[bearbeiten] Template-Parameter
Jedes Template wird durch einen oder mehrere Template-Parameter parametrisiert, die in der parameter-list der Template-Deklarationssyntax angegeben sind.
template < parameter-list > declaration |
(1) | ||||||||
template < parameter-list > requires constraint declaration |
(2) | (seit C++20) | |||||||
Jeder Parameter in parameter-list kann sein
- ein Nicht-Typ-Template-Parameter;
- ein Typ-Template-Parameter;
- ein Template-Template-Parameter.
|
|
P2841 (Concept und Variable-Template-Template-Parameter) benannte „non-type template parameter/argument“ in „constant template parameter/argument“ um, ohne ihre Bedeutung zu ändern. Aufgrund der umfangreichen Verwendung von „non-type template parameter“ und seiner Abkürzung „NTTP“ werden die aktuellen Terminologien beibehalten. |
[bearbeiten] Nicht-Typ-Template-Parameter
| type name (optional) | (1) | ||||||||
type name (optional) = default |
(2) | ||||||||
type ... name (optional) |
(3) | (seit C++11) | |||||||
| type | - | einer der folgenden Typen
| ||||
| name | - | der Name des Nicht-Typ-Template-Parameters | ||||
| default | - | das Standard-Template-Argument |
Ein struktureller Typ ist einer der folgenden Typen (optional cv-qualifiziert, die Qualifizierer werden ignoriert)
- Lvalue-Referenztyp (auf Objekt oder Funktion);
- ein Integral-Typ;
- ein Zeigertyp (auf Objekt oder Funktion);
- ein Zeiger-auf-Mitglied-Typ (auf Mitgliedsobjekt oder Mitgliedsfunktion);
- ein Aufzählungstyp;
| (seit C++11) |
|
(seit C++20) |
Array- und Funktionstypen können in einer Template-Deklaration geschrieben werden, werden aber automatisch durch Zeiger auf Objekte und Zeiger auf Funktionen ersetzt, je nach Fall.
Wenn der Name eines Nicht-Typ-Template-Parameters in einem Ausdruck innerhalb des Körpers einer Klassenvorlage verwendet wird, ist er ein unveränderbares prvalue, es sei denn, sein Typ war ein Lvalue-Referenztyp, oder es sei denn, sein Typ ist ein Klassentyp(seit C++20).
Ein Template-Parameter der Form class Foo ist kein unbenannter Nicht-Typ-Template-Parameter vom Typ Foo, auch wenn class Foo ansonsten ein elaborierter Typspezifizierer ist und class Foo x; x vom Typ Foo deklariert.
|
Ein Bezeichner, der einen Nicht-Typ-Template-Parameter vom Klassentyp 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) |
[bearbeiten] 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-Parameter-Deklaration. |
| type-constraint | - | entweder der Name eines Konzepts oder der Name eines Konzepts gefolgt von einer Liste von Template-Argumenten (in spitzen Klammern). In jedem Fall kann der Konzeptname optional qualifiziert sein. |
| name | - | der Name des Typ-Template-Parameters |
| default | - | das Standard-Template-Argument |
template<class T> class My_vector { /* ... */ };
template<class T = void> struct My_op_functor { /* ... */ };
template<typename... Ts> class My_tuple { /* ... */ };
template<My_concept T> class My_constrained_vector { /* ... */ };
template<My_concept T = void> class My_constrained_op_functor { /* ... */ };
template<My_concept... Ts> class My_constrained_tuple { /* ... */ };
Der Name des Parameters ist optional.
// Declarations of the templates shown above: template<class> class My_vector; template<class = void> struct My_op_functor; template<typename...> class My_tuple;
Im Körper der Template-Deklaration ist der Name eines Typ-Parameters ein typedef-name, der auf den Typ aliasen, der bei der Instanziierung des Templates bereitgestellt wird.
|
Jeder eingeschränkte Parameter
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) |
[bearbeiten] 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) |
Im Körper der Template-Deklaration ist der Name dieses Parameters ein Template-Name (und benötigt Argumente zur Instanziierung).
template<typename T> class my_array {}; // two type template parameters and one template template parameter: template<typename K, typename V, template<typename> typename C = my_array> class Map { C<K> key; C<V> value; };
[bearbeiten] Namensauflösung für Template-Parameter
Der Name eines Template-Parameters darf in seinem Geltungsbereich (einschließlich verschachtelter Geltungsbereiche) 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; // error: template parameter redeclared void f() { char T; // error: template parameter redeclared } }; template<class X> class X; // error: template parameter redeclared
In der Definition eines Mitglieds einer Klassenvorlage, die außerhalb der Klassenvorlagen-Definition erscheint, überschattet der Name eines Mitglieds der Klassenvorlage den Namen eines Template-Parameters von umschließenden Klassenvorlagen, aber nicht den eines Template-Parameters des Mitglieds, wenn das Mitglied 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, not the template parameter } template<class B> template<class C> void A<B>::g(C) { B b; // A's B, not the template parameter C c; // the template parameter C, not A's C }
In der Definition eines Mitglieds einer Klassenvorlage, die außerhalb des Namespaces erscheint, der die Klassenvorlagen-Definition enthält, überschattet der Name eines Template-Parameters den Namen eines Mitglieds dieses Namespaces.
namespace N { class C {}; template<class T> class B { void f(T); }; } template<class C> void N::B<C>::f(C) { C b; // C is the template parameter, not N::C }
In der Definition einer Klassenvorlage oder in der Definition eines Mitglieds einer solchen Vorlage, die außerhalb der Vorlagen-Definition erscheint, gilt für jede nicht-abhängige Basisklasse: Wenn der Name der Basisklasse oder der Name eines Mitglieds der Basisklasse mit dem Namen eines Template-Parameters übereinstimmt, überschattet der Basisklassenname oder Mitgliedsname 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; // error: A's C isn't a type name };
[bearbeiten] Template-Argumente
Damit ein Template instanziiert werden kann, muss jeder Template-Parameter (Typ, Nicht-Typ oder Template) durch ein entsprechendes Template-Argument ersetzt werden. Für Klassenvorlagen werden die Argumente entweder explizit bereitgestellt, aus dem Initialisierer abgeleitet, (seit C++17) oder standardmäßig gesetzt. Für Funktionsvorlagen werden die Argumente explizit bereitgestellt, aus dem Kontext abgeleitet oder standardmäßig gesetzt.
Wenn ein Argument sowohl als type-id als auch als Ausdruck interpretiert werden kann, wird es immer als type-id interpretiert, auch wenn der entsprechende Template-Parameter ein Nicht-Typ ist.
template<class T> void f(); // #1 template<int I> void f(); // #2 void g() { f<int()>(); // "int()" is both a type and an expression, // calls #1 because it is interpreted as a type }
[bearbeiten] Nicht-Typ-Template-Argumente
|
Das Template-Argument, das mit einem Nicht-Typ-Template-Parameter verwendet werden kann, kann jeder offensichtlich konstanten Auswertung unterzogene Ausdruck sein. |
(bis C++11) |
|
Das Template-Argument, das mit einem Nicht-Typ-Template-Parameter verwendet werden kann, kann jede Initialisiererklausel sein. Wenn die Initialisiererklausel ein Ausdruck ist, muss sie offensichtlich konstanten Auswertung unterzogen werden. |
(seit C++11) |
Gegeben den Typ der Nicht-Typ-Template-Parameter-Deklaration als T und das für den Parameter bereitgestellte Template-Argument als E.
|
Die erfundene Deklaration T x = E; muss die semantischen Einschränkungen für die Definition einer constexpr Variablen mit statischer Speicherdauer erfüllen. |
(seit C++26) |
|
Wenn Wenn ein abgeleiteter Parametertyp kein struktureller Typ ist, ist das Programm fehlerhaft. Bei Nicht-Typ-Template-Parameterpaketen, deren Typ einen Platzhaltertyp verwendet, wird der Typ für jedes Template-Argument unabhängig abgeleitet und muss nicht übereinstimmen. |
(seit C++17) |
template<auto n> struct B { /* ... */ }; B<5> b1; // OK: non-type template parameter type is int B<'a'> b2; // OK: non-type template parameter type is char B<2.5> b3; // error (until C++20): non-type template parameter type cannot be double // C++20 deduced class type placeholder, class template arguments are deduced at the // call site template<std::array arr> void f(); f<std::array<double, 8>{}>(); template<auto...> struct C {}; C<'C', 0, 2L, nullptr> x; // OK
Der Wert eines Nicht-Typ-Template-Parameters P vom (möglicherweise abgeleitet)(seit C++17) Typ T wird aus seinem Template-Argument A wie folgt bestimmt:
|
(bis C++11) |
|
(seit C++11) (bis C++20) |
|
(seit C++20) |
template<int i> struct C { /* ... */ }; C<{42}> c1; // OK template<auto n> struct B { /* ... */ }; struct J1 { J1* self = this; }; B<J1{}> j1; // error: initialization of the template parameter object // is not a constant expression struct J2 { J2 *self = this; constexpr J2() {} constexpr J2(const J2&) {} }; B<J2{}> j2; // error: the template parameter object is not // template-argument-equivalent to introduced temporary
|
Die folgenden Einschränkungen gelten beim Instanziieren von Templates, die Nicht-Typ-Template-Parameter haben:
Insbesondere impliziert dies, dass Zeichenkettenliterale, Adressen von Array-Elementen und Adressen von nicht-statischen Mitgliedern nicht als Template-Argumente verwendet werden können, um Templates zu instanziieren, deren entsprechende Nicht-Typ-Template-Parameter Zeiger auf Objekte sind. |
(bis C++17) |
|
Nicht-Typ-Template-Parameter vom Referenz- oder Zeigertyp und nicht-statische Datenmember vom Referenz- oder Zeigertyp in einem Nicht-Typ-Template-Parameter vom Klassentyp und dessen Unterobjekten(seit C++20) dürfen nicht verweisen auf/die Adresse von
|
(seit C++17) |
template<const int* pci> struct X {}; int ai[10]; X<ai> xi; // OK: array to pointer conversion and cv-qualification conversion struct Y {}; template<const Y& b> struct Z {}; Y y; Z<y> z; // OK: no conversion template<int (&pa)[5]> struct W {}; int b[5]; W<b> w; // OK: no conversion void f(char); void f(int); template<void (*pf)(int)> struct A {}; A<&f> a; // OK: overload resolution selects f(int)
template<class T, const char* p> class X {}; X<int, "Studebaker"> x1; // error: string literal as template-argument template<int* p> class X {}; int a[10]; struct S { int m; static int s; } s; X<&a[2]> x3; // error (until C++20): address of array element X<&s.m> x4; // error (until C++20): address of non-static member X<&s.s> x5; // OK: address of static member X<&S::s> x6; // OK: address of static member template<const int& CRI> struct B {}; B<1> b2; // error: temporary would be required for template argument int c = 1; B<c> b1; // OK
[bearbeiten] Typ-Template-Argumente
Ein Template-Argument für einen Typ-Template-Parameter muss ein Typ-Bezeichner sein, der einen unvollständigen Typ benennen kann.
template<typename T> class X {}; // class template struct A; // incomplete type typedef struct {} B; // type alias to an unnamed type int main() { X<A> x1; // OK: 'A' names a type X<A*> x2; // OK: 'A*' names a type X<B> x3; // OK: 'B' names a type }
[bearbeiten] Template-Template-Argumente
Ein Template-Argument für einen Template-Template-Parameter muss ein id-Ausdruck sein, der eine Klassenvorlage oder ein Template-Alias benennt.
Wenn das Argument eine Klassenvorlage ist, wird nur die primäre Vorlage bei der Zuordnung zum Parameter berücksichtigt. Die partiellen Spezialisierungen, falls vorhanden, werden nur berücksichtigt, wenn eine Spezialisierung auf Basis dieser Template-Template-Parameter instanziiert wird.
template<typename T> // primary template class A { int x; }; template<typename T> // partial specialization class A<T*> { long x; }; // class template with a template template parameter V template<template<typename> class V> class C { V<int> y; // uses the primary template V<int*> z; // uses the partial specialization }; C<A> c; // c.y.x has type int, c.z.x has type long
Um ein Template-Template-Argument A einem Template-Template-Parameter P zuzuordnen, muss P mindestens so spezialisiert sein wie A (siehe unten). Wenn Ps Parameterliste einen Parameterpack enthält, werden null oder mehr Template-Parameter (oder Parameterpacks) aus der Template-Parameterliste von A durch ihn abgeglichen.(seit C++11)
Formal ist ein Template-Template-Parameter P mindestens so spezialisiert wie ein Template-Template-Argument A, wenn, unter Berücksichtigung der folgenden Umschreibung in zwei Funktionsvorlagen, die Funktionsvorlage, die P entspricht, mindestens so spezialisiert ist wie die Funktionsvorlage, die A entspricht, gemäß den Regeln der partiellen Ordnung für Funktionsvorlagen. Gegeben eine erfundene Klassenvorlage X mit der Template-Parameterliste von A (einschließlich Standardargumenten):
- Jede der beiden Funktionsvorlagen hat dieselben Template-Parameter wie
Pbzw.A. - Jede Funktionsvorlage hat einen einzelnen Funktionsparameter, dessen Typ eine Spezialisierung von
Xmit Template-Argumenten ist, die den Template-Parametern der jeweiligen Funktionsvorlage entsprechen, wobei für jeden Template-ParameterPPin der Template-Parameterliste der Funktionsvorlage ein entsprechender Template-ParameterAAgebildet wird. WennPPein Parameterpack deklariert, dann istAAdie Pack-ExpansionPP...; andernfalls(seit C++11) istAAder id-AusdruckPP.
Wenn die Umschreibung einen ungültigen Typ ergibt, dann ist P nicht mindestens so spezialisiert wie A.
template<typename T> struct eval; // primary template template<template<typename, typename...> class TT, typename T1, typename... Rest> struct eval<TT<T1, Rest...>> {}; // partial specialization of eval template<typename T1> struct A; template<typename T1, typename T2> struct B; template<int N> struct C; template<typename T1, int N> struct D; template<typename T1, typename T2, int N = 17> struct E; eval<A<int>> eA; // OK: matches partial specialization of eval eval<B<int, float>> eB; // OK: matches partial specialization of eval eval<C<17>> eC; // error: C does not match TT in partial specialization // because TT's first parameter is a // type template parameter, while 17 does not name a type eval<D<int, 17>> eD; // error: D does not match TT in partial specialization // because TT's second parameter is a // type parameter pack, while 17 does not name a type eval<E<int, float>> eE; // error: E does not match TT in partial specialization // because E's third (default) parameter is a non-type
Vor der Einführung von P0522R0 mussten die Template-Parameter von A exakt den entsprechenden Template-Parametern von P entsprechen. Dies verhinderte die Akzeptanz vieler sinnvoller Template-Argumente.
Obwohl es sehr früh darauf hingewiesen wurde (CWG#150), wurden die Änderungen zum Zeitpunkt seiner Behebung in das C++17-Arbeitspapier aufgenommen und die Auflösung wurde zu einem De-facto-C++17-Feature. Viele Compiler deaktivieren es standardmäßig.
- GCC deaktiviert es in allen Sprachmodi vor C++17 standardmäßig, es kann in diesen Modi nur durch Setzen eines Compiler-Flags aktiviert werden.
- Clang deaktiviert es in allen Sprachmodi standardmäßig, es kann nur durch Setzen eines Compiler-Flags aktiviert werden.
- Microsoft Visual Studio behandelt es als normales C++17-Feature und aktiviert es nur in C++17 und späteren Sprachmodi (d. h. keine Unterstützung im C++14-Sprachmodus, der der Standardmodus ist).
template<class T> class A { /* ... */ }; template<class T, class U = T> class B { /* ... */ }; template<class... Types> class C { /* ... */ }; template<template<class> class P> class X { /* ... */ }; X<A> xa; // OK X<B> xb; // OK after P0522R0 // Error earlier: not an exact match X<C> xc; // OK after P0522R0 // Error earlier: not an exact match template<template<class...> class Q> class Y { /* ... */ }; Y<A> ya; // OK Y<B> yb; // OK Y<C> yc; // OK template<auto n> class D { /* ... */ }; // note: C++17 template<template<int> class R> class Z { /* ... */ }; Z<D> zd; // OK after P0522R0: the template parameter // is more specialized than the template argument template<int> struct SI { /* ... */ }; template<template<auto> class> void FA(); // note: C++17 FA<SI>(); // Error
[bearbeiten] Standard-Template-Argumente
Standard-Template-Argumente werden in den Parameterlisten nach dem Zeichen = angegeben. Standardwerte können für jede Art von Template-Parameter (Typ, Nicht-Typ oder Template) angegeben werden, aber nicht für Parameterpacks(seit C++11).
Wenn der Standardwert für einen Template-Parameter einer primären Klassenvorlage, primären Variablentemplate,(seit C++14) oder Alias-Template angegeben wird, muss jeder nachfolgende Template-Parameter ein Standardargument haben, außer das allerletzte darf ein Template-Parameterpack sein(seit C++11). In einer Funktionsvorlage gibt es keine Einschränkungen für die Parameter, die auf einen Standardwert folgen, und ein Parameterpack darf von weiteren Typ-Parametern gefolgt werden, nur wenn diese Standardwerte haben oder aus den Funktionsargumenten abgeleitet werden können(seit C++11).
Standardparameter sind nicht erlaubt
- in der Out-of-Class-Definition eines Mitglieds einer Klassenvorlage (sie müssen in der Deklaration innerhalb des Klassenrumpfes angegeben werden). Beachten Sie, dass Mitgliedsvorlagen von Nicht-Template-Klassen Standardparameter in ihren Out-of-Class-Definitionen verwenden können (siehe GCC-Bug 53856).
- in Friend-Klassenvorlagen-Deklarationen
|
(bis C++11) |
|
Bei einer Friend-Funktionsvorlagen-Deklaration sind Standard-Template-Argumente nur erlaubt, wenn die Deklaration eine Definition ist und keine anderen Deklarationen dieser Funktion in dieser Übersetzungseinheit vorkommen. |
(seit C++11) |
Standard-Template-Argumente, die in den Deklarationen erscheinen, werden ähnlich wie standardmäßige Funktionsargumente zusammengeführt.
template<typename T1, typename T2 = int> class A; template<typename T1 = int, typename T2> class A; // the above is the same as the following: template<typename T1 = int, typename T2 = int> class A;
Aber derselbe Parameter kann nicht zweimal im selben Geltungsbereich Standardargumente erhalten.
template<typename T = int> class X; template<typename T = int> class X {}; // error
Beim Parsen eines Standard-Template-Arguments für einen Nicht-Typ-Template-Parameter wird das erste nicht-verschachtelte > als Ende der Template-Parameterliste und nicht als Größer-als-Operator betrachtet.
template<int i = 3 > 4> // syntax error class X { /* ... */ }; template<int i = (3 > 4)> // OK class Y { /* ... */ };
Die Template-Parameterlisten von Template-Template-Parametern können eigene Standardargumente haben, die nur dort wirksam sind, wo der Template-Template-Parameter selbst im Geltungsbereich liegt.
// class template, with a type template parameter with a default template<typename T = float> struct B {}; // template template parameter T has a parameter list, which // consists of one type template parameter with a default template<template<typename = float> typename T> struct A { void f(); void g(); }; // out-of-body member function template definitions template<template<typename TT> class T> void A<T>::f() { T<> t; // error: TT has no default in scope } template<template<typename TT = char> class T> void A<T>::g() { T<> t; // OK: t is T<char> }
Mitgliederzugriff für die in einem Standard-Template-Argument verwendeten Namen wird bei der Deklaration geprüft, nicht am Verwendungsort.
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; // error: C::TT is protected
|
Das Standard-Template-Argument wird implizit instanziiert, wenn der Wert dieses Standardarguments benötigt wird, es sei denn, das Template wird verwendet, um eine Funktion zu benennen. 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>* |
(seit C++14) |
[bearbeiten] Template-Argument-Äquivalenz
Die Template-Argument-Äquivalenz wird verwendet, um festzustellen, ob zwei Template-Bezeichner gleich sind.
Zwei Werte sind template-argument-äquivalent, wenn sie vom selben Typ sind und eine der folgenden Bedingungen erfüllt ist:
- Sie sind vom Integral- oder Aufzählungstyp und ihre Werte sind gleich.
- Sie sind vom Zeigertyp und haben denselben Zeigerwert.
- Sie sind vom Zeiger-auf-Mitglied-Typ und beziehen sich auf dasselbe Klassenmitglied oder sind beide der Null-Mitgliedszeigerwert.
- Sie sind vom Lvalue-Referenztyp und beziehen sich auf dasselbe Objekt oder dieselbe Funktion.
|
(seit C++11) |
|
(seit C++20) |
[bearbeiten] Hinweise
|
In Template-Parametern können Typbeschränkungen sowohl für Typ- als auch für Nicht-Typ-Parameter verwendet werden, je nachdem, ob auto vorhanden ist. template<typename> concept C = true; template<C, // type parameter C auto // non-type parameter > struct S{}; S<int, 0> s;
|
(seit C++20) |
| Feature-Testmakro | Wert | Std | Feature |
|---|---|---|---|
__cpp_nontype_template_parameter_auto |
201606L |
(C++17) | Deklaration von Nicht-Typ-Template-Parametern mit auto |
__cpp_template_template_args |
201611L |
(C++17) (DR) |
Abgleich von Template-Template-Argumenten |
__cpp_nontype_template_args |
201411L |
(C++17) | Erlaubt konstante Auswertung für alle Nicht-Typ-Template-Argumente |
201911L |
(C++20) | Klassentypen und Gleitkommatypen in Nicht-Typ-Template-Parametern |
[bearbeiten] Beispiele
#include <array> #include <iostream> #include <numeric> // simple non-type template parameter template<int N> struct S { int a[N]; }; template<const char*> struct S2 {}; // complicated non-type example template < char c, // integral type int (&ra)[5], // lvalue reference to object (of array type) int (*pf)(int), // pointer to function int (S<10>::*a)[10] // pointer to member object (of type int[10]) > struct Complicated { // calls the function selected at compile time // and stores the result in the array selected at compile time void foo(char base) { ra[4] = pf(c - base); } }; // S2<"fail"> s2; // error: string literal cannot be used char okay[] = "okay"; // static object with linkage // S2<&okay[0]> s3; // error: array element has no linkage S2<okay> s4; // works int a[5]; int f(int n) { return n; } // C++20: NTTP can be a literal class type template<std::array arr> constexpr auto sum() { return std::accumulate(arr.cbegin(), arr.cend(), 0); } // C++20: class template arguments are deduced at the call site static_assert(sum<std::array<double, 8>{3, 1, 4, 1, 5, 9, 2, 6}>() == 31.0); // C++20: NTTP argument deduction and CTAD static_assert(sum<std::array{2, 7, 1, 8, 2, 8}>() == 28); int main() { S<10> s; // s.a is an array of 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
| Dieser Abschnitt ist unvollständig Grund: Weitere Beispiele |
[bearbeiten] 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 150 (P0522R0) |
C++98 | Template-Template-Argumente mussten mit Parameterlisten von Template-Template-Parametern exakt übereinstimmen |
spezialisierter auch erlaubt |
| CWG 184 | C++98 | ob die Template-Parameter von Template-Template-Parametern Standardargumente haben dürfen, ist unbestimmt |
Spezifikation hinzugefügt |
| CWG 354 | C++98 | Nullzeigerwerte konnten keine Nicht-Typ-Template-Argumente sein | erlaubt |
| CWG 1398 | C++11 | Nicht-Typ-Template-Argumente konnten keinen Typ std::nullptr_t haben |
erlaubt |
| CWG 1570 | C++98 | Nicht-Typ-Template-Argumente konnten Adressen von Unterobjekten bezeichnen | nicht erlaubt |
| CWG 1922 | C++98 | es war unklar, ob eine Klassenvorlage, deren Name eine injected-class-name ist, die Standardargumente in früheren Deklarationen verwenden kann |
erlaubt |
| CWG 2032 | C++14 | für Variablentemplates gab es keine Einschränkung für die Template-Parameter nach einem Template-Parameter mit einem Standard-Template-Argument |
die gleiche Einschränkung anwenden wie bei Klassenvorlagen 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 Capture-los |
| P2308R1 | C++11 C++20 |
1. Listeninitialisierung war nicht erlaubt für Nicht-Typ-Template-Argumente (C++11) 2. es war unklar, wie Nicht-Typ-Template-Parameter von Klassentypen initialisiert werden (C++20) |
1. erlaubt 2. geklärt |