c++ templates c++20 c++-concepts

c++ 20: Conceptos de múltiples tipos y su restricción, ¿sintaxis correcta?



templates c++20 (4)

Parece que en el próximo estándar c++20 , de acuerdo con este informe de reddit , podremos especificar el concept una plantilla y para cada plantilla de clase / función, podremos establecer constraints en sus tipos. Sin embargo, en las documentaciones y tutoriales (por ejemplo, constraints ), no pude encontrar la sintaxis correcta para el caso de uso de tipo múltiple.

Supongamos que tenemos un concepto multitipo:

template<typename T1, typename T2> concept AreEqComparable = requires(T1 a, T2 b) { { a == b } -> bool; };

Digamos, quiero definir una función de comparación simple entre dos tipos diferentes. ¿Cómo puedo hacer eso? Más específicamente, ¿qué debo escribir en el ??? parte del código de abajo:

??? bool are_equal(T1 a, T2 b) { return a == b; }

No pude encontrar ninguna referencia a este caso constraints , here e incluso concept . He intentado al azar algo como:

/* 1 */ template<AreEqComparable T1, T2> /* 2 */ AreEqComparable<T1, T2> /* 3 */ template<AreEqComparable<T1, T2>>

Pero todos ellos arrojan errores de sintaxis. Creo que la respuesta debería estar en algún lugar de la especificación P0557 de Bjarne Stroustrup , pero es demasiado larga para que la lea.


En GCC 8.2.0, los conceptos deben escribirse como:

concept bool ConceptName = /* ... */

Pero Plantillas de C ++: La Guía completa no menciona el bool . Dado que el estándar C ++ 20 no se lanza, es difícil decir cuál es el correcto.

Para los conceptos que necesitan un parámetro (no necesariamente el tipo), hay una abreviatura:

template <UnaryConceptName T>

Para aquellos que necesitan dos o más parámetros, no hay taquigrafía:

template <typename T1, typename T2> requires BinaryConceptName<T1, T2>

typename se puede reemplazar con un nombre de tipo específico.

Por cierto:

  1. El libro que mencioné anteriormente ofrece una breve introducción a los conceptos.

  2. Utilice -fconcepts en GCC para habilitar conceptos.


Otra sintaxis más que evita la introducción de parámetros de plantilla (a costa de agregar otra redundancia):

bool are_equal(auto x,auto y) requires AreEqComparable<decltype(x),decltype(y)> {return x==y;}


Puedes escribir:

template <typename T1, AreEqComparable<T1> T2> bool are_equal(T1, T2);

Esto es equivalente a:

template <typename T1, typename T2> requires AreEqComparable<T2, T1> bool are_equal(T1, T2);

Los tipos se invierten en la restricción aquí, AreEqComparable<T2, T1> lugar de AreEqComparable<T1, T2> . Esto ciertamente será importante para muchos conceptos, pero probablemente no sea éste en particular, ya que == se vuelve simétrico en C ++ 20 (menos casos patológicos que no deberían existir en el código real). Y si quiere estar realmente seguro de que esta simetría es válida, siempre puede hacerlo explícito en el concepto (ya que EqualityComparableWith está en el borrador de trabajo):

template<typename T1, typename T2> concept AreEqComparable = requires(T1 a, T2 b) { { a == b } -> bool; { b == a } -> bool; };

Puede obtener la restricción que desea en el orden correcto al cambiar el orden de los parámetros de la plantilla (h / t Matthieu M.):

template <typename T2, AreEqComparable<T2> T1> bool are_equal(T1, T2);


Puedes escribirlo así:

template <typename T1, typename T2> requires AreEqComparable<T1, T2> bool are_equal(T1 a, T2 b) { // ... }

Aquí, utilizamos una cláusula de requisitos para imponer un requisito en los parámetros de plantilla de tipo.