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

Produce una expresión prvalue de tipo bool que describe las restricciones.

Contenidos

Sintaxis

requires { requirement-seq } (1)
requires ( parameter-list  (opcional) ) { requirement-seq } (2)
parameter-list - una lista de parámetros
requirement-seq - secuencia de requisitos , cada requisito es uno de los siguientes:

Explicación

Los requisitos pueden referirse a los parámetros de plantilla que están en alcance, a los parámetros de parameter-list , y a cualquier otra declaración que sea visible desde el contexto envolvente.

La sustitución de argumentos de plantilla en una expresión requires utilizada en una declaración de una entidad con plantilla puede resultar en la formación de tipos o expresiones inválidos en sus requisitos, o la violación de restricciones semánticas de esos requisitos. En tales casos, la expresión requires se evalúa como false y no provoca que el programa esté mal formado. La sustitución y verificación de restricciones semánticas procede en orden léxico y se detiene cuando se encuentra una condición que determina el resultado de la expresión requires . Si la sustitución (si existe) y la verificación de restricciones semánticas tienen éxito, la expresión requires se evalúa como true .

Si ocurriera un fallo de sustitución en una requires expresión para cada posible argumento de plantilla, el programa está mal formado, no se requiere diagnóstico:

template<class T>
concept C = requires
{
    new int[-(int)sizeof(T)]; // inválido para todo T: mal formado, no se requiere diagnóstico
};

Si una requires expresión contiene tipos o expresiones inválidos en sus requisitos, y no aparece dentro de la declaración de una entidad con plantillas , entonces el programa está mal formado.

Parámetros locales

Una requires expresión puede introducir parámetros locales utilizando una lista de parámetros . Estos parámetros no tienen vinculación, almacenamiento o duración; solo se utilizan como notación para definir requisitos.

El tipo de cada parámetro se determina de la misma manera que determinar el tipo real de los parámetros de función:

template<typename T>
concept C = requires(T p[2])
{
    (decltype(p))nullptr; // OK, p tiene tipo T*
};

Si se satisface cualquiera de las siguientes condiciones, el programa está mal formado:

template<typename T>
concept C1 = requires(T t = 0)  // Error: t tiene un argumento por defecto
{
    t;
};
template<typename T>
concept C2 = requires(T t, ...) // Error: termina con una elipsis
{
    t;
};

Requisitos simples

expresión ;
expresión - una expresión que no comienza con requires


Un requisito simple afirma que expression es válida. expression es un unevaluated operand .

template<typename T>
concept Addable = requires (T a, T b)
{
    a + b; // "la expresión 'a + b' es una expresión válida que compilará"
};
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));
};

Un requisito que comienza con la palabra clave requires siempre se interpreta como un requisito anidado. Por lo tanto, un requisito simple no puede comenzar con una expresión requires sin paréntesis.

Requisitos de tipo

typename identificador ;
identifier - un (posiblemente calificado) identifier (incluyendo simple template identifier )


Un requisito de tipo afirma que el tipo nombrado por identifier es válido: esto puede utilizarse para verificar que existe cierto tipo anidado con nombre, o que una especialización de plantilla de clase/alias nombra un tipo. Un requisito de tipo que nombra una especialización de plantilla de clase no requiere que el tipo esté completo.

template<typename T>
using Ref = T&;
template<typename T>
concept C = requires
{
    typename T::inner; // nombre de miembro anidado requerido
    typename S<T>;     // especialización de plantilla de clase requerida
    typename Ref<T>;   // sustitución de plantilla de alias requerida
};
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> es válido y nombra un tipo
    { CommonType<T, U>{std::forward<T>(t)} }; 
    { CommonType<T, U>{std::forward<U>(u)} }; 
};

Requisitos compuestos

{ expresión }; (1)
{ expresión } noexcept ; (2)
{ expresión } -> restricción-de-tipo ; (3)
{ expresión } noexcept -> restricción-de-tipo ; (4)
expression - una expresión
type-constraint - una constraint


Un requisito compuesto afirma propiedades de expression . La sustitución y verificación de restricciones semánticas procede en el siguiente orden:

1) Los argumentos de plantilla (si los hay) se sustituyen en expression .
2) Si noexcept está presente, expression no debe ser potencialmente lanzadora .
3) Si type-constraint está presente, entonces:
a) Los argumentos de plantilla se sustituyen en type-constraint .
b) decltype ( ( expresión  ) ) debe satisfacer la restricción impuesta por type-constraint . De lo contrario, la expresión requires envolvente es false .

expression es un operando no evaluado .

template<typename T>
concept C2 = requires(T x)
{
    // la expresión *x debe ser válida
    // Y el tipo T::inner debe ser válido
    // Y el resultado de *x debe ser convertible a T::inner
    {*x} -> std::convertible_to<typename T::inner>;
    // la expresión x + 1 debe ser válida
    // Y std::same_as<decltype((x + 1)), int> debe satisfacerse
    // es decir, (x + 1) debe ser un prvalue de tipo int
    {x + 1} -> std::same_as<int>;
    // la expresión x * 1 debe ser válida
    // Y su resultado debe ser convertible a T
    {x * 1} -> std::convertible_to<T>;
};

Requisitos anidados

requires expresión-de-restricción ;
constraint-expression - una expresión que representa constraints


Un requisito anidado puede utilizarse para especificar restricciones adicionales en términos de parámetros locales. constraint-expression debe ser satisfecho por los argumentos de plantilla sustituidos, si los hay. La sustitución de argumentos de plantilla en un requisito anidado causa sustitución en constraint-expression solo en la medida necesaria para determinar si constraint-expression está satisfecho.

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)>; // anidado: "Same<...> se evalúa como verdadero"
    { a.~T() } noexcept; // compuesto: "a.~T()" es una expresión válida que no lanza excepciones
    requires Same<T*, decltype(new T)>; // anidado: "Same<...> se evalúa como verdadero"
    requires Same<T*, decltype(new T[n])>; // anidado
    { delete new T }; // compuesto
    { delete new T[n] }; // compuesto
};

Nota

La palabra clave requires también se utiliza para introducir requires clauses .

template<typename T>
concept Addable = requires (T x) { x + x; }; // expresión requires
template<typename T> requires Addable<T> // cláusula requires, no expresión requires
T add(T a, T b) { return a + b; }
template<typename T>
    requires requires (T x) { x + x; } // restricción ad-hoc, observe que la palabra clave se usa dos veces
T add(T a, T b) { return a + b; }

Palabras clave

requires

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.

DR Aplicado a Comportamiento publicado Comportamiento correcto
CWG 2560 C++20 no estaba claro si los tipos de parámetros se ajustan en requires expressions también se ajustan
CWG 2911 C++20 todas las expresiones que aparecen dentro de requires
expressions eran operandos no evaluados
solo algunas
expressions son

Referencias

  • Estándar C++23 (ISO/IEC 14882:2024):
  • 7.5.7 Expresiones requires [expr.prim.req]
  • Estándar C++20 (ISO/IEC 14882:2020):
  • 7.5.7 Expresiones requires [expr.prim.req]

Véase también

Restricciones y conceptos (C++20) especifica los requisitos para los argumentos de plantilla