requires
expression
(since C++20)
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:
- Un parámetro local tiene un argumento predeterminado .
- La lista de parámetros termina con puntos suspensivos.
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:
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
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 |