requires Ausdruck (seit C++20)
Liefert einen prvalue-Ausdruck vom Typ bool, der die Constraints beschreibt.
Inhalt |
[bearbeiten] Syntax
requires { requirement-seq } |
(1) | ||||||||
requires ( parameter-list (optional) ) { requirement-seq } |
(2) | ||||||||
| parameter-liste | - | eine Parameterliste |
| requirement-seq | - | Sequenz von Anforderungen, wobei jede Anforderung eine der folgenden ist |
[bearbeiten] Erklärung
Anforderungen können auf Template-Parameter verweisen, die im Gültigkeitsbereich liegen, auf die Parameter von parameter-list und auf alle anderen Deklarationen, die aus dem umgebenden Kontext sichtbar sind.
Die Substitution von Template-Argumenten in einem requires-Ausdruck, der in der Deklaration einer templated entity verwendet wird, kann zur Bildung ungültiger Typen oder Ausdrücke in seinen Anforderungen führen oder zur Verletzung semantischer Constraints dieser Anforderungen. In solchen Fällen wird der requires-Ausdruck zu false ausgewertet und führt nicht dazu, dass das Programm fehlerhaft ist. Die Substitution und die Überprüfung semantischer Constraints erfolgen in lexikalischer Reihenfolge und stoppen, sobald eine Bedingung auftritt, die das Ergebnis des requires-Ausdrucks bestimmt. Wenn die Substitution (falls vorhanden) und die Überprüfung semantischer Constraints erfolgreich sind, wird der requires-Ausdruck zu true ausgewertet.
Wenn bei einem requires-Ausdruck für jedes mögliche Template-Argument eine Substitutionsfehlfunktion auftreten würde, ist das Programm fehlerhaft, keine Diagnose erforderlich.
template<class T> concept C = requires { new int[-(int)sizeof(T)]; // invalid for every T: ill-formed, no diagnostic required };
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.
[bearbeiten] Lokale Parameter
Ein requires-Ausdruck kann lokale Parameter mithilfe einer Parameterliste einführen. Diese Parameter haben keine Verknüpfung, keinen Speicher und keine Lebensdauer; sie werden nur als Notation für die Definition von Anforderungen verwendet.
Der Typ jedes Parameters wird auf die gleiche Weise bestimmt wie die tatsächliche Bestimmung des Typs von Funktionsparametern.
template<typename T> concept C = requires(T p[2]) { (decltype(p))nullptr; // OK, p has type T* };
Wenn eine der folgenden Bedingungen erfüllt ist, ist das Programm ill-formed (wohlgeformt):
- Ein lokaler Parameter hat ein Standardargument.
- Die Parameterliste endet mit einer Ellipse.
template<typename T> concept C1 = requires(T t = 0) // Error: t has a default argument { t; }; template<typename T> concept C2 = requires(T t, ...) // Error: terminates with an ellipsis { t; };
[bearbeiten] Einfache Anforderungen
expression ; |
|||||||||
| expression | - | ein Ausdruck, der nicht mit requires beginnt |
Eine einfache Anforderung besagt, dass expression gültig ist. expression ist ein nicht ausgewerteter Operand.
template<typename T> concept Addable = requires (T a, T b) { a + b; // "the expression “a + b” is a valid expression that will compile" }; 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 verschachtelte Anforderung interpretiert. Daher kann eine einfache Anforderung nicht mit einem nicht geklammerten requires-Ausdruck beginnen.
[bearbeiten] Typanforderungen
typename identifier ; |
|||||||||
| identifier | - | ein (möglicherweise qualifizierter) Identifikator (einschließlich einfachem Template-Identifikator) |
Eine Typanforderung besagt, dass der vom identifier benannte Typ gültig ist: Dies kann verwendet werden, um zu überprüfen, ob ein bestimmter benannter verschachtelter Typ existiert oder ob eine Klassen-/Alias-Template-Spezialisierung einen Typ benennt. Eine Typanforderung, die eine Klassen-Template-Spezialisierung benennt, erfordert nicht, dass der Typ vollständig ist.
template<typename T> using Ref = T&; template<typename T> concept C = requires { typename T::inner; // required nested member name typename S<T>; // required class template specialization typename Ref<T>; // required 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> is valid and names a type { CommonType<T, U>{std::forward<T>(t)} }; { CommonType<T, U>{std::forward<U>(u)} }; };
[bearbeiten] Zusammengesetzte Anforderungen
{ expression }; |
(1) | ||||||||
{ expression } noexcept ; |
(2) | ||||||||
{ expression } -> type-constraint ; |
(3) | ||||||||
{ expression } noexcept -> type-constraint ; |
(4) | ||||||||
| expression | - | ein Ausdruck |
| type-constraint | - | ein Constraint |
Eine zusammengesetzte Anforderung besagt Eigenschaften von expression . Substitution und Überprüfung semantischer Constraints erfolgen in folgender Reihenfolge
expression ist ein nicht ausgewerteter Operand.
template<typename T> concept C2 = requires(T x) { // the expression *x must be valid // AND the type T::inner must be valid // AND the result of *x must be convertible to T::inner {*x} -> std::convertible_to<typename T::inner>; // the expression x + 1 must be valid // AND std::same_as<decltype((x + 1)), int> must be satisfied // i.e., (x + 1) must be a prvalue of type int {x + 1} -> std::same_as<int>; // the expression x * 1 must be valid // AND its result must be convertible to T {x * 1} -> std::convertible_to<T>; };
[bearbeiten] Verschachtelte Anforderungen
requires constraint-expression ; |
|||||||||
| constraint-expression | - | ein Ausdruck, der Constraints darstellt |
Eine verschachtelte Anforderung kann verwendet werden, um zusätzliche Constraints in Bezug auf lokale Parameter anzugeben. constraint-expression muss von den substituierten Template-Argumenten (falls vorhanden) erfüllt werden. Die Substitution von Template-Argumenten in eine verschachtelte Anforderung führt nur so weit zur Substitution in constraint-expression, wie zur Bestimmung, ob constraint-expression erfüllt ist, erforderlich 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)>; // nested: "Same<...> evaluates to true" { a.~T() } noexcept; // compound: "a.~T()" is a valid expression that doesn't throw requires Same<T*, decltype(new T)>; // nested: "Same<...> evaluates to true" requires Same<T*, decltype(new T[n])>; // nested { delete new T }; // compound { delete new T[n] }; // compound };
[bearbeiten] Hinweis
Das Schlüsselwort requires wird auch verwendet, um requires-Klauseln einzuführen.
template<typename T> concept Addable = requires (T x) { x + x; }; // requires expression template<typename T> requires Addable<T> // requires clause, not requires expression T add(T a, T b) { return a + b; } template<typename T> requires requires (T x) { x + x; } // ad-hoc constraint, note keyword used twice T add(T a, T b) { return a + b; }
[bearbeiten] Schlüsselwörter
[bearbeiten] Defect reports
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 2560 | C++20 | Es war unklar, ob Parameter-Typen in requires-Ausdrücken angepasst werden. | auch angepasst |
| CWG 2911 | C++20 | alle Ausdrücke, die innerhalb von requires vorkommen Ausdrücke waren nicht ausgewertete Operanden |
nur einige Ausdrücke sind |
[bearbeiten] Referenzen
- C++23 Standard (ISO/IEC 14882:2024)
- 7.5.7 Requires expressions [expr.prim.req]
- C++20 Standard (ISO/IEC 14882:2020)
- 7.5.7 Requires expressions [expr.prim.req]
[bearbeiten] Siehe auch
| Constraints und Konzepte(C++20) | spezifiziert die Anforderungen an Template-Argumente |