Espacios de nombres
Variantes

Expresiones requires (desde C++20)

De cppreference.com

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:
  • requerimiento simple
  • requerimientos de tipo
  • requerimientos compuestos
  • requerimientos anidados

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:

1) Los argumentos de plantilla (si los hay) se sustituyen en la expresión;
2) Si se usa noexcept, la expresión no debe potencialmente lanzar excepciones;
3) Si requerimiento-de-tipo-de-retorno está presente, entonces:
a) Los argumentos de plantilla se sustituyen en requerimiento-de-tipo-de-retorno;
b) 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

requires

Véase también

Restricciones and conceptos(C++20) Especifica los requerimientos para argumentos de plantilla[editar]