c++ - Whyever** not** declara que una función es `constexpr`?
c++11 function-declaration (3)
Creo que a lo que te refieres se lo llama evaluación parcial . Lo que está tocando es que algunos programas se pueden dividir en dos partes, una pieza que requiere información de tiempo de ejecución, y una pieza que se puede hacer sin información de tiempo de ejecución, y que en teoría podría simplemente evaluar completamente la parte del programa que no necesita ninguna información de tiempo de ejecución incluso antes de comenzar a ejecutar el programa. Hay algunos lenguajes de programación que hacen esto. Por ejemplo, el lenguaje de programación D tiene un intérprete integrado en el compilador que le permite ejecutar código en tiempo de compilación, siempre que cumpla con ciertas restricciones.
Existen algunos desafíos principales para lograr que la evaluación parcial funcione. En primer lugar, complica enormemente la lógica del compilador porque el compilador necesitará tener la capacidad de simular todas las operaciones que podría poner en un programa ejecutable en tiempo de compilación. Esto, en el peor de los casos, requiere que tengas un intérprete completo dentro del compilador, lo que hace un problema difícil (escribir un buen compilador de C ++) y hacer que los órdenes de magnitud sean más difíciles de hacer.
Creo que la razón de la especificación actual sobre constexpr
es simplemente limitar la complejidad de los compiladores. Los casos en los que está limitado son bastante simples de verificar. No es necesario implementar bucles en el compilador (lo que podría causar muchos otros problemas, como lo que sucede si se obtiene un bucle infinito dentro del compilador). También evita que el compilador tenga que evaluar sentencias que podrían causar segfaults en tiempo de ejecución, como seguir un puntero malo.
Otra consideración a tener en cuenta es que algunas funciones tienen efectos secundarios, como leer desde cin
o abrir una conexión de red. Funciones como estas fundamentalmente no pueden optimizarse en tiempo de compilación, ya que hacerlo requeriría conocimiento solo disponible en tiempo de ejecución.
En resumen, no hay ninguna razón teórica por la que no pueda evaluar parcialmente los programas C ++ en tiempo de compilación. De hecho, la gente hace esto todo el tiempo. La optimización de los compiladores, por ejemplo, son esencialmente programas que intentan hacer esto tanto como sea posible. La metaprogramación de plantillas es una instancia donde los programadores de C ++ intentan ejecutar código dentro del compilador, y es posible hacer algunas cosas estupendas con las plantillas parcialmente porque las reglas para las plantillas forman un lenguaje funcional, que el compilador tiene más fácil de implementar. Además, si piensas en la compensación entre las horas del autor del compilador y las horas de programación, la metaprogramación de plantillas muestra que si estás bien haciendo que los programadores se desanimen para obtener lo que quieren, puedes construir un lenguaje bastante débil (el sistema de plantillas) y mantener la complejidad del lenguaje simple. (Digo "débil" como "no particularmente expresivo", no "débil" en el sentido de la teoría de computabilidad).
¡Espero que esto ayude!
Cualquier función que consista en una instrucción return solamente podría declararse constexpr
y, por lo tanto, permitirá ser evaluada en tiempo de compilación si todos los argumentos son constexpr
y solo se constexpr
funciones constexpr
en su cuerpo. ¿Hay alguna razón para no declarar ninguna función de este constexpr
?
Ejemplo:
constexpr int sum(int x, int y) { return x + y; }
constexpr i = 10;
static_assert(sum(i, 13) == 23, "sum correct");
¿Podría alguien dar un ejemplo en el que declarar un constexpr
función constexpr
algún daño?
Algunos pensamientos iniciales:
Incluso si no hubiera una buena razón para declarar alguna función no constexpr
, podría imaginarse que la palabra clave constexpr
tiene una función de transición: su ausencia en el código que no necesita evaluaciones en tiempo de compilación permitiría a los compiladores que no implementan evaluaciones en tiempo de compilación aún para compilar ese código (pero fallar confiablemente en el código que los necesita como hecho explícito usando constexpr
).
Pero lo que no entiendo: si no debería haber una buena razón para declarar una función que no constexpr
, ¿por qué no todas las funciones de la biblioteca estándar son constexpr
? (No se puede argumentar que aún no se ha hecho porque aún no había tiempo suficiente para hacerlo, porque hacerlo para todos es una tarea obvia, contrario a la decisión de cada función para constexpr
o no). - Soy consciente de que N2976 deliberadamente no requiere cstrs para muchos tipos de bibliotecas estándar, como los contenedores, ya que esto sería demasiado limitado para posibles implementaciones. Vamos a excluirlos del argumento y solo preguntarnos: una vez que un tipo en la biblioteca estándar realmente tiene un constexto, ¿por qué no todas las funciones que operan en él son constexpr
?
En la mayoría de los casos, tampoco puede argumentar que prefiera no declarar una función simplemente porque no prevé ningún uso en tiempo de compilación: porque si otros evtl. usará su código, pueden ver tal uso que usted no. (Pero concedido para tipos de rasgos tipo y cosas por el estilo, por supuesto).
Así que supongo que debe haber una buena razón y un buen ejemplo para no declarar deliberadamente un constexpr
funciones.
(con "cada función" siempre me refiero a: cada función que cumple los requisitos para ser constexpr
, es decir, se define como una declaración de retorno única, toma solo argumentos de tipos con constexpr cstrs y llama solo a constexpr
funciones constexpr
.)
La pregunta ¿Por qué std::forward
descarta constexpr
? es un caso especial de este.
Las funciones solo se pueden declarar constexpr
si obedecen las reglas para constexpr
--- no hay constexpr
dinámicas, no hay asignación de memoria, no hay llamadas a funciones no constexpr
, etc.
Declarar una función en la biblioteca estándar como constexpr
requiere que TODAS las implementaciones obedezcan esas reglas.
En primer lugar, esto requiere verificar para cada función que se puede implementar como constexpr
, que es un trabajo largo.
En segundo lugar, esta es una gran restricción para las implementaciones y prohibirá muchas implementaciones de depuración. Por lo tanto, solo vale la pena si los beneficios superan los costos, o si los requisitos son lo suficientemente estrictos como para que la implementación tenga que obedecer las reglas constexpr
todos modos. Hacer esta evaluación para cada función es nuevamente un trabajo largo.
Si la función tiene efectos secundarios, no querrá marcarla constexpr
. Example
No puedo obtener resultados inesperados de eso, en realidad parece que gcc 4.5.1 simplemente ignora constexpr