Expresiones requires (desde C++20)
Produce una expresión prvalue de tipo bool que describe las restriciones.
Sintaxis
requires { secuencia-de-requerimientos }
|
|||||||||
requires ( lista-de-parámetros(opcional) ) { secuencia-de-requerimientos }
|
|||||||||
| lista-de-parámetros | - | Una lista de parámetros separados por comas como en una declaración de función, excepto que los argumentos por defecto no están permitidos y no puede terminar con puntos suspensivos (que no sea uno que signifique una expansión de paquete). Estos parámetros no tienen almacenamiento, enlace o duración, y solo se utilizan para ayudar a especificar requerimientos. Estos parámetros están en el ámbito hasta el cierre } de la secuencia-de-requerimientos.
|
| secuencia-de-requerimientos | - | Secuencia de requerimientos, cada requisito es uno de los siguientes:
|
Explicación
Los requerimientos pueden hacer referencia a los parámetros de plantilla que están dentro del ámbito, a los parámetros locales introducidos en la lista-de-parámetros y a cualquier otra declaración que sea visible desde el contexto circundante.
La sustitución de argumentos de plantilla en una expresión require usada en una declaración de una entidad emplantillada puede resultar en la formación
de tipos o expresiones no válidos en sus requerimientos, o la violación de las restricciones semánticas de esos requerimientos. En tales casos, la expresión requires se evalúa como false y no causa que el programa esté mal formado. La verificación de sustitución y restricción semántica procede en orden léxico y se detiene cuando se encuentra una condición que determina el resultado de la expresión require. Si la verificación de la sustitución (si la hay) y la restricción semántica tiene éxito, la expresión require se evalúa como true.
Si ocurriera un error de sustitución en una expresión require para cada argumento de plantilla posible, el programa está mal formado y no se requiere diagnóstico:
template<class T>
concept C = requires
{
new int[-(int)sizeof(T)]; // inválido para cada T:
}; // mal formado, no se requiere diagnóstico
Si una expresión requires contiene tipos o expresiones no válidos en sus requerimientos, y no aparece en la declaración de una entidad emplantillada, entonces el programa está mal formado.
Requerimientos simples
Un requerimiento simple es una declaración de expresión arbitraria que no comience con la palabra clave requires. Afirma que la expresión es válida. La expresión es un operando no evaluado; solo se verifica la corrección del lenguaje.
template<typename T>
concept Sumable = 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 Intercambiable = requires(T&& t, U&& u)
{
swap(std::forward<T>(t), std::forward<U>(u));
swap(std::forward<U>(u), std::forward<T>(t));
};
Un requerimiento que comienza con la palabra clave requires siempre se interpreta como un requerimiento anidado. Por lo tanto, un requerimiento simple no puede comenzar con una expresión requires sin paréntesis.
Requerimientos de tipo
Un requerimiento de tipo es la palabra clave typename seguida de un nombre de tipo, opcionalmente calificado. El requerimiento es que el tipo denominado sea válido: esto se puede usar para verificar que existe un cierto tipo anidado con nombre, o que una especialización de plantilla de clase denomina un tipo, o que una especialización de plantilla de alias denomina un tipo. Un requerimiento de tipo para denominar 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 denomina un tipo
{ CommonType<T, U>{std::forward<T>(t)} };
{ CommonType<T, U>{std::forward<U>(u)} };
};
Requerimientos compuestos
Un requerimiento compuesto tiene la forma
{ expresión } noexcept(opcional) requerimiento-de-tipo-de-retorno(opcional) ;
|
|||||||||
| requerimiento-de-tipo-de-retorno | - | -> restricción-de-tipo
|
y afirma las propiedades de la expresión nombrada. La comprobación de la restricción semántica y de sustitución se realiza en el siguiente orden:
decltype ((expresión)) debe satisfacer la restricción impuesta por la restricción-de-tipo. De lo contrario, la expresión require que la contiene es false.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
// por ejemplo, (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>;
};
Requerimientos anidados
Un requerimiento anidado tiene la forma
requires expresión-de-restricción ;
|
|||||||||
Se puede usar para especificar restricciones adicionales en términos de parámetros locales. La expresión-de-restricción debe cumplirse con los argumentos de la plantilla sustituidos, si los hubiera. La sustitución de argumentos de plantilla en un requisito anidado provoca la sustitución en la expresión-de-restricción solo en la medida necesaria para determinar si se cumple con la expresión-de-restricción.
template <class T>
concept Semiregular = DefaultConstructible<T> &&
CopyConstructible<T> && Destructible<T> && CopyAssignable<T> &&
requires(T a, size_t n)
{
requires Same<T*, decltype(&a)>; // anidado: "Same<...> se evalúa como true"
{ 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 true"
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 usa para introducir cláusulas requires.
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 para el caso, observa que la palabra
T add(T a, T b) { return a + b; } // clave se usa dos veces
Palabras clave
Véase también
| Restricciones and conceptos(C++20) | Especifica los requerimientos para argumentos de plantilla |