Namespaces
Variants

requires expression (since C++20)

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

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 :

1) Les arguments de template (s'il y en a) sont substitués dans expression .
2) Si noexcept est présent, l'expression ne doit pas être potentiellement levée .
3) Si type-constraint est présent, alors :
a) Les arguments du modèle sont substitués dans type-constraint .
b) decltype ( ( expression  ) ) doit satisfaire la contrainte imposée par type-constraint . Sinon, l'expression requires englobante est false .

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

requires

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