No hace mucho tiempo, las expresiones obligatorias (la frase introducida por el segundo requerimiento) no estaban permitidas en las expresiones de restricción (la frase introducida por el primero requiere). Solo podría aparecer en definiciones de conceptos. De hecho, esto es exactamente lo que se propone en la sección de ese documento donde aparece ese reclamo.
Sin embargo, en 2016, hubo una propuesta para relajar esa restricción [Nota del editor: P0266 ]. Obsérvese el tachado del párrafo 4 en la sección 4 del documento. Y así nació nació requiere requiere.
A decir verdad, nunca había implementado esa restricción en GCC, por lo que siempre había sido posible. Creo que Walter pudo haber descubierto eso y lo encontró útil, lo que lleva a ese documento.
Para que nadie piense que no era sensible a la escritura requiere dos veces, pasé algún tiempo tratando de determinar si eso podría simplificarse. Respuesta corta: no.
El problema es que hay dos construcciones gramaticales que deben introducirse después de una lista de parámetros de plantilla: muy comúnmente, una expresión de restricción (like P && Q
) y, en ocasiones, requisitos sintácticos (like requires (T a) { ... }
). Eso se llama una expresión obligatoria.
El primero requiere introduce la restricción. El segundo requiere introduce la expresión requerida. Así es como se compone la gramática. No lo encuentro confuso en absoluto.
Traté, en un punto, de colapsar esto a una sola necesidad. Desafortunadamente, eso lleva a algunos problemas de análisis muy difíciles. No se puede decir fácilmente, por ejemplo, si un (
after the require denota una subexpresión anidada o una lista de parámetros. No creo que haya una desambiguación perfecta de esas sintaxis (vea la justificación de la sintaxis de inicialización uniforme; este problema también está ahí).
Por lo tanto, elija: make requiere introducir una expresión (como lo hace ahora) o hacer que presente una lista parametrizada de requisitos.
Elegí el enfoque actual porque la mayoría de las veces (como en casi el 100% de las veces), quiero algo más que una expresión obligatoria. Y en el caso extremadamente raro que quería una expresión obligatoria para restricciones ad hoc, realmente no me importa escribir la palabra dos veces. Es un indicador obvio de que no he desarrollado una abstracción suficientemente sólida para la plantilla. (Porque si lo tuviera, tendría un nombre).
Podría haber elegido hacer que los requisitos introduzcan una expresión de requisitos. Eso es realmente peor, porque prácticamente todas sus limitaciones comenzarían a verse así:
template<typename T>
requires { requires Eq<T>; }
void f(T a, T b);
Aquí, el segundo requerimiento se llama requisito anidado; evalúa su expresión (no se evalúa otro código en el bloque de la expresión requerida). Creo que esto es mucho peor que el status quo. Ahora, puedes escribir requiere dos veces en todas partes.
También podría haber usado más palabras clave. Este es un problema en sí mismo, y no se trata solo de arrojar bicicletas. Puede haber una forma de "redistribuir" palabras clave para evitar la duplicación, pero no he pensado mucho en eso. Pero eso realmente no cambia la esencia del problema.
noexcept(noexcept(...))
.