c++ language-lawyer constexpr c++20 class-template

c++ - ¿Las funciones constevales permitirán parámetros de plantilla dependiendo de los argumentos de la función?



language-lawyer constexpr (3)

¿Significa que este código será legal?

consteval int foo(int i) { return std::integral_constant<int, i>::value; }

No. Esto todavía está mal formado. Si bien consteval requiere que la llamada en sí sea una expresión constante, para que sepa que el argumento que produce i debe ser una expresión constante, foo sí todavía no es una plantilla. ¿Modelo?

Una pequeña variación en tu ejemplo podría hacer esto más obvio:

consteval auto foo(int i) { return std::integral_constant<int, i>(); }

Si esto fuera válido, foo(1) y foo(2) devolverían diferentes tipos. Esta es una característica de lenguaje completamente diferente ( parámetros de función constexpr ), porque para que esto funcione, dichas funciones realmente deberían comportarse como plantillas.

Puede parecer un poco poco intuitivo. Después de todo, si el argumento que produjo i era una expresión constante, ¿seguramente también debería ser utilizable? Pero aún no lo es, no hay excepciones adicionales en [expr.const] que permitan parámetros para funciones inmediatas. Una función inmediata es solo una función, y sus parámetros aún no son expresiones constantes, de la misma manera que los constexpr función constexpr normal no son expresiones constantes.

Por supuesto, con int , solo podemos reescribir la función para elevar el parámetro de función a un parámetro de plantilla:

template <int i> consteval int foo() { return std::integral_constant<int, i>::value; }

Y C ++ 20 nos ofrece tipos de clase como parámetros de plantilla que no son de tipo, por lo que podemos hacer esto para muchos más tipos que antes. Pero todavía hay muchos tipos que podríamos usar como un parámetro para una función inmediata que no podemos usar como un parámetro de plantilla, por lo que esto no siempre funcionará (por ejemplo, std::optional o, más emocionante en C ++ 20, std::string ).

En C ++ 17, este código es ilegal:

constexpr int foo(int i) { return std::integral_constant<int, i>::value; }

Esto se debe a que incluso si foo se puede evaluar en tiempo de compilación, el compilador aún debe producir las instrucciones para ejecutarlo en tiempo de ejecución, lo que hace imposible la creación de instancias de la plantilla.

En C ++ 20 tendremos funciones consteval , que deben evaluarse en tiempo de compilación, por lo que se debe eliminar la restricción de tiempo de ejecución. ¿Significa que este código será legal?

consteval int foo(int i) { return std::integral_constant<int, i>::value; }


No.

Independientemente de los cambios que conlleve el papel, lo que es poco en este punto , no puede cambiar el hecho de que una definición de función no de plantilla solo se escribe una vez. Además, si su código propuesto fuera legal, probablemente podríamos encontrar una manera de declarar una variable de tipo std::integral_constant<int, i> , que parece muy prohibitiva en términos de la ODR.

El documento también indica que los parámetros no están diseñados para ser tratados como expresiones constantes centrales en uno de sus ejemplos;

consteval int sqrsqr(int n) { return sqr(sqr(n)); // Not a constant-expression at this point, } // but that''s okay.

En resumen, los parámetros de la función nunca serán expresiones constantes, debido a una posible discrepancia en la escritura.


Parece que esto no será legal en C ++ 20. Una buena explicación de por qué esto podría ser problemático para el soporte ya se ha dado en las respuestas por @Barry y @Columbo (realmente no funciona con el sistema de tipos). Simplemente agregaré lo que creo que son las citas relevantes del estándar aquí que realmente hacen esto ilegal.

Basado en [temp.arg.nontype]/2

Un argumento de plantilla para un parámetro de plantilla no tipo será una expresión constante convertida [...]

Una expresión constante convertida es una expresión constante que se convierte implícitamente a un tipo particular [expr.const]/7 (aquí, el tipo del parámetro de la plantilla). Entonces, su pregunta se reduce a la cuestión de si una variable dentro de una función constante es una expresión constante. Basado en [expr.const]/8

Una expresión constante es una expresión constante de glvalue core que se refiere a una entidad que es un resultado permitido de una expresión constante (como se define a continuación), o una expresión constante de núcleo prvalue cuyo valor satisface las siguientes restricciones: [...]

La expresión i es una expresión-expresión glvalue que es una expresión constante central (porque su evaluación no hace ninguna de las cosas enumeradas en [expr.const]/4 ). Sin embargo, la entidad a la que se refiere esta expresión constante central no es un resultado permitido de una expresión constante [expr.const]/8 :

Una entidad es un resultado permitido de una expresión constante si es un objeto con una duración de almacenamiento estática que no es un objeto temporal o es un objeto temporal cuyo valor satisface las restricciones anteriores, o si es una función no inmediata.

El objeto en cuestión no tiene una duración de almacenamiento estático ni es un objeto temporal ...