requires
expression
(since C++20)
Produit une expression prvalue de type bool qui décrit les contraintes.
Table des matières |
Syntaxe
requires
{
requirement-seq
}
|
(1) | ||||||||
requires
(
parameter-list
(optionnel)
)
{
requirement-seq
}
|
(2) | ||||||||
| parameter-list | - | une liste de paramètres |
| requirement-seq | - | séquence d' exigences , chaque exigence étant l'une des suivantes : |
Explication
Les exigences peuvent faire référence aux paramètres de modèle qui sont dans la portée, aux paramètres de la parameter-list , et à toute autre déclaration visible depuis le contexte englobant.
La substitution des arguments de template dans une requires expression utilisée dans une déclaration d'une entité template peut résulter en la formation de types ou d'expressions invalides dans ses exigences, ou la violation de contraintes sémantiques de ces exigences. Dans de tels cas, l'expression requires s'évalue à false et ne rend pas le programme mal formé. La substitution et la vérification des contraintes sémantiques procèdent dans l'ordre lexical et s'arrêtent lorsqu'une condition qui détermine le résultat de l'expression requires est rencontrée. Si la substitution (le cas échéant) et la vérification des contraintes sémantiques réussissent, l'expression requires s'évalue à true .
Si un échec de substitution se produisait dans une requires expression pour chaque argument de template possible, le programme est mal formé, aucun diagnostic requis :
template<class T> concept C = requires { new int[-(int)sizeof(T)]; // invalide pour tout T : mal formé, aucun diagnostic requis };
Si une requires expression contient des types ou expressions non valides dans ses exigences, et qu'elle n'apparaît pas dans la déclaration d'une entité template , alors le programme est mal formé.
Paramètres locaux
Une requires expression peut introduire des paramètres locaux en utilisant une liste de paramètres . Ces paramètres n'ont pas de liaison, de stockage ou de durée de vie ; ils sont uniquement utilisés comme notation pour définir des exigences.
Le type de chaque paramètre est déterminé de la même manière que la détermination du type réel des paramètres de fonction :
template<typename T> concept C = requires(T p[2]) { (decltype(p))nullptr; // OK, p a le type T* };
Si l'une des conditions suivantes est satisfaite, le programme est mal formé :
- Un paramètre local possède un argument par défaut .
- La liste de paramètres se termine par des points de suspension.
template<typename T> concept C1 = requires(T t = 0) // Erreur : t a un argument par défaut { t; }; template<typename T> concept C2 = requires(T t, ...) // Erreur : se termine par des points de suspension { t; };
Exigences simples
expression
;
|
|||||||||
| expression | - | une expression qui ne commence pas par requires |
Une simple exigence affirme que
expression
est valide.
expression
est un
opérande non évalué
.
template<typename T> concept Addable = requires (T a, T b) { a + b; // "l'expression « a + b » est une expression valide qui sera compilée" }; 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)); };
Une exigence qui commence par le mot-clé requires est toujours interprétée comme une exigence imbriquée. Ainsi, une exigence simple ne peut pas commencer par une expression requires non parenthésée.
Exigences de type
typename
identifiant
;
|
|||||||||
| identifier | - | un (éventuellement qualifié) identifiant (incluant les identifiants de template simples ) |
Une exigence de type affirme que le type nommé par
identifier
est valide : cela peut être utilisé pour vérifier qu'un certain type imbriqué nommé existe, ou qu'une spécialisation de modèle de classe/alias désigne un type. Une exigence de type nommant une spécialisation de modèle de classe ne nécessite pas que le type soit complet.
template<typename T> using Ref = T&; template<typename T> concept C = requires { typename T::inner; // nom de membre imbriqué requis typename S<T>; // spécialisation de modèle de classe requise typename Ref<T>; // substitution de modèle d'alias requise {; 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> est valide et désigne un type { CommonType<T, U>{std::forward<T>(t)} }; { CommonType<T, U>{std::forward<U>(u)} }; };
Exigences composées
{
expression
};
|
(1) | ||||||||
{
expression
}
noexcept
;
|
(2) | ||||||||
{
expression
} ->
type-constraint
;
|
(3) | ||||||||
{
expression
}
noexcept ->
type-constraint
;
|
(4) | ||||||||
| expression | - | une expression |
| type-constraint | - | une contrainte |
Une exigence composée affirme des propriétés de
expression
. La substitution et la vérification des contraintes sémantiques procèdent dans l'ordre suivant :
expression est un opérande non évalué .
template<typename T> concept C2 = requires(T x) { // l'expression *x doit être valide // ET le type T::inner doit être valide // ET le résultat de *x doit être convertible en T::inner {*x} -> std::convertible_to<typename T::inner>; // l'expression x + 1 doit être valide // ET std::same_as<decltype((x + 1)), int> doit être satisfaite // c'est-à-dire que (x + 1) doit être une prvalue de type int {x + 1} -> std::same_as<int>; // l'expression x * 1 doit être valide // ET son résultat doit être convertible en T {x * 1} -> std::convertible_to<T>; };
Exigences imbriquées
requires
expression-de-contrainte
;
|
|||||||||
| constraint-expression | - | une expression représentant constraints |
Une exigence imbriquée peut être utilisée pour spécifier des contraintes supplémentaires en termes de paramètres locaux.
constraint-expression
doit être satisfaite par les arguments de template substitués, le cas échéant. La substitution des arguments de template dans une exigence imbriquée provoque la substitution dans
constraint-expression
uniquement dans la mesure nécessaire pour déterminer si
constraint-expression
est satisfaite.
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)>; // imbriqué : "Same<...> évalue à true" { a.~T() } noexcept; // composé : "a.~T()" est une expression valide qui ne lève pas d'exception requires Same<T*, decltype(new T)>; // imbriqué : "Same<...> évalue à true" requires Same<T*, decltype(new T[n])>; // imbriqué { delete new T }; // composé { delete new T[n] }; // composé };
Remarque
Le mot-clé requires est également utilisé pour introduire les requires clauses .
template<typename T> concept Addable = requires (T x) { x + x; }; // expression requires template<typename T> requires Addable<T> // clause requires, pas expression requires T add(T a, T b) { return a + b; } template<typename T> requires requires (T x) { x + x; } // contrainte ad hoc, notez le mot-clé utilisé deux fois T add(T a, T b) { return a + b; }
Mots-clés
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Appliqué à | Comportement publié | Comportement corrigé |
|---|---|---|---|
| CWG 2560 | C++20 | il n'était pas clair si les types de paramètres sont ajustés dans les requires expressions | également ajustés |
| CWG 2911 | C++20 |
toutes les expressions apparaissant dans les
requires
expressions étaient des opérandes non évalués |
seulement certaines
expressions le sont |
Références
- Norme C++23 (ISO/IEC 14882:2024) :
-
- 7.5.7 Expressions requires [expr.prim.req]
- Norme C++20 (ISO/IEC 14882:2020) :
-
- 7.5.7 Expressions requires [expr.prim.req]
Voir aussi
| Contraintes et concepts (C++20) | spécifie les exigences sur les arguments de template |