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:
-
El libro que mencioné anteriormente ofrece una breve introducción a los conceptos.
-
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.