requires
expression
(since C++20)
Ergibt einen prvalue-Ausdruck vom Typ bool , der die Constraints beschreibt.
Inhaltsverzeichnis |
Syntax
requires
{
requirement-seq
}
|
(1) | ||||||||
requires
(
parameter-list
(optional)
)
{
requirement-seq
}
|
(2) | ||||||||
| parameter-list | - | eine Parameterliste |
| requirement-seq | - | Folge von Anforderungen , jede Anforderung ist eine der folgenden: |
Erklärung
Anforderungen können sich auf die Template-Parameter beziehen, die im Gültigkeitsbereich sind, auf die Parameter der parameter-list , und auf alle anderen Deklarationen, die vom umschließenden Kontext aus sichtbar sind.
Die Substitution von Template-Argumenten in einen requires -Ausdruck, der in einer Deklaration einer templated entity verwendet wird, kann zur Bildung ungültiger Typen oder Ausdrücke in seinen Anforderungen oder zur Verletzung semantischer Constraints dieser Anforderungen führen. In solchen Fällen ergibt der requires -Ausdruck false und führt nicht dazu, dass das Programm ill-formed wird. Die Substitution und semantische Constraint-Überprüfung erfolgt in lexikalischer Reihenfolge und stoppt, wenn eine Bedingung angetroffen wird, die das Ergebnis des requires -Ausdrucks bestimmt. Wenn die Substitution (falls vorhanden) und semantische Constraint-Überprüfung erfolgreich sind, ergibt der requires -Ausdruck true .
Wenn für jedes mögliche Template-Argument ein Substitutionsfehler in einem requires -Ausdruck auftreten würde, ist das Programm fehlerhaft, keine Diagnose erforderlich:
template<class T> concept C = requires { new int[-(int)sizeof(T)]; // ungültig für jedes T: fehlerhaft, keine Diagnose erforderlich };
Wenn ein requires -Ausdruck ungültige Typen oder Ausdrücke in seinen Anforderungen enthält und er nicht innerhalb der Deklaration einer templated entity erscheint, dann ist das Programm fehlerhaft.
Lokale Parameter
Ein requires -Ausdruck kann lokale Parameter mittels einer Parameterliste einführen. Diese Parameter besitzen keine Bindung, Speicherung oder Lebensdauer; sie dienen lediglich als Notation zur Definition von Anforderungen.
Der Typ jedes Parameters wird auf die gleiche Weise bestimmt wie die Bestimmung des tatsächlichen Typs von Funktionsparametern:
template<typename T> concept C = requires(T p[2]) { (decltype(p))nullptr; // OK, p hat den Typ T* };
Wenn eine der folgenden Bedingungen erfüllt ist, ist das Programm fehlerhaft:
- Ein lokaler Parameter hat ein default argument .
- Die Parameterliste endet mit einer Ellipse.
template<typename T> concept C1 = requires(T t = 0) // Fehler: t hat einen Standardargument { t; }; template<typename T> concept C2 = requires(T t, ...) // Fehler: endet mit einer Ellipse { t; };
Einfache Anforderungen
Ausdruck
;
|
|||||||||
| expression | - | ein Ausdruck, der nicht mit requires beginnt |
Eine einfache Anforderung stellt sicher, dass
expression
gültig ist.
expression
ist ein
unevaluated operand
.
template<typename T> concept Addable = requires (T a, T b) { a + b; // "der Ausdruck „a + b“ ist ein gültiger Ausdruck, der kompiliert wird" }; template<class T, class U = T> concept Swappable = requires(T&& t, U&& u) { swap(std::forward<T>(t), std::forward<U>(u)); swap(std::forward<U>(u), std::forward<T>(t)); };
Eine Anforderung, die mit dem Schlüsselwort requires beginnt, wird immer als eine verschachtelte Anforderung interpretiert. Daher kann eine einfache Anforderung nicht mit einem nicht in Klammern gesetzten requires -Ausdruck beginnen.
Typanforderungen
typename
Bezeichner
;
|
|||||||||
| identifier | - | ein (möglicherweise qualifizierter) identifier (einschließlich simple template identifier ) |
Eine Typanforderung stellt sicher, dass der durch
identifier
benannte Typ gültig ist: Dies kann verwendet werden, um zu überprüfen, ob ein bestimmter geschachtelter Typ existiert oder ob eine Klassen-/Alias-Templatespezialisierung einen Typ benennt. Eine Typanforderung, die eine Klassentemplatespezialisierung benennt, erfordert nicht, dass der Typ vollständig ist.
template<typename T> using Ref = T&; template<typename T> concept C = requires { typename T::inner; // erforderlicher geschachtelter Member-Name typename S<T>; // erforderliche Klassentemplate-Spezialisierung typename Ref<T>; // erforderliche Alias-Template-Substitution {; template<class T, class U> using CommonType = std::common_type_t<T, U>; template<class T, class U> concept Common = requires (T&& t, U&& u) { typename CommonType<T, U>; // CommonType<T, U> ist gültig und benennt einen Typ { CommonType<T, U>{std::forward<T>(t)} }; { CommonType<T, U>{std::forward<U>(u)} }; };
Zusammengesetzte Anforderungen
{
Ausdruck
};
|
(1) | ||||||||
{
Ausdruck
}
noexcept
;
|
(2) | ||||||||
{
Ausdruck
} ->
Typ-Einschränkung
;
|
(3) | ||||||||
{
Ausdruck
}
noexcept ->
Typ-Einschränkung
;
|
(4) | ||||||||
| expression | - | ein Ausdruck |
| type-constraint | - | eine constraint |
Eine zusammengesetzte Anforderung behauptet Eigenschaften eines
expression
. Substitution und semantische Einschränkungsüberprüfung erfolgen in folgender Reihenfolge:
expression ist ein unevaluated operand .
template<typename T> concept C2 = requires(T x) { // Der Ausdruck *x muss gültig sein // UND der Typ T::inner muss gültig sein // UND das Ergebnis von *x muss in T::inner konvertierbar sein {*x} -> std::convertible_to<typename T::inner>; // Der Ausdruck x + 1 muss gültig sein // UND std::same_as<decltype((x + 1)), int> muss erfüllt sein // d.h. (x + 1) muss ein Prvalue vom Typ int sein {x + 1} -> std::same_as<int>; // Der Ausdruck x * 1 muss gültig sein // UND sein Ergebnis muss in T konvertierbar sein {x * 1} -> std::convertible_to<T>; };
Verschachtelte Anforderungen
requires
Constraint-Ausdruck
;
|
|||||||||
| constraint-expression | - | ein Ausdruck, der constraints repräsentiert |
Eine geschachtelte Anforderung kann verwendet werden, um zusätzliche Einschränkungen in Bezug auf lokale Parameter zu spezifizieren.
constraint-expression
muss durch die substituierten Template-Argumente erfüllt werden, falls vorhanden. Die Substitution von Template-Argumenten in eine geschachtelte Anforderung führt nur in dem Umfang zur Substitution in
constraint-expression
, der notwendig ist, um zu bestimmen, ob
constraint-expression
erfüllt ist.
template<class T> concept Semiregular = DefaultConstructible<T> && CopyConstructible<T> && CopyAssignable<T> && Destructible<T> && requires(T a, std::size_t n) { requires Same<T*, decltype(&a)>; // verschachtelt: "Same<...> ergibt true" { a.~T() } noexcept; // zusammengesetzt: "a.~T()" ist ein gültiger Ausdruck, der keine Ausnahme wirft requires Same<T*, decltype(new T)>; // verschachtelt: "Same<...> ergibt true" requires Same<T*, decltype(new T[n])>; // verschachtelt { delete new T }; // zusammengesetzt { delete new T[n] }; // zusammengesetzt };
Hinweis
Das Schlüsselwort requires wird auch verwendet, um requires -Klauseln einzuführen.
template<typename T> concept Addable = requires (T x) { x + x; }; // Requires-Ausdruck template<typename T> requires Addable<T> // Requires-Klausel, kein Requires-Ausdruck T add(T a, T b) { return a + b; } template<typename T> requires requires (T x) { x + x; } // Ad-hoc-Einschränkung, beachte doppelte Verwendung des Schlüsselworts T add(T a, T b) { return a + b; }
Schlüsselwörter
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrektes Verhalten |
|---|---|---|---|
| CWG 2560 | C++20 | es war unklar, ob Parametertypen in requires Ausdrücken angepasst werden | ebenfalls angepasst |
| CWG 2911 | C++20 |
alle Ausdrücke innerhalb von
requires
Ausdrücken waren nicht ausgewertete Operanden |
nur einige
Ausdrücke sind |
Referenzen
- C++23 Standard (ISO/IEC 14882:2024):
-
- 7.5.7 Requires-Ausdrücke [expr.prim.req]
- C++20 Standard (ISO/IEC 14882:2020):
-
- 7.5.7 Requires-Ausdrücke [expr.prim.req]
Siehe auch
| Constraints and concepts (C++20) | spezifiziert die Anforderungen an Template-Argumente |