Whyever * * not * * declare a function to be `constexpr`?


Cualquier función que consista en una sentencia return solo puede ser declarada constexpr y por lo tanto permitirá ser evaluado en tiempo de compilación si todos los argumentos son constexpr y solo las funciones constexpr son llamadas en su cuerpo. ¿Hay alguna razón para no declarar cualquier tal función 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 proporcionar un ejemplo donde declarar una función constexpr ¿haría algún daño?


Alguna inicial pensamientos:

Incluso si no debería haber una buena razón para declarar una función no constexpr Podría imaginar que la palabra clave constexpr tiene un función de transición: su ausencia en el código que no necesita tiempo de compilación las evaluaciones permitirían a los compiladores que no implementan el tiempo de compilación evaluaciones todavía para compilar ese código (pero para fallar confiablemente en el código que los necesita como se hace explícito mediante el uso de constexpr).

Pero lo que no entiendo: si no debe haber una buena razón para nunca declarando una función no constexpr, ¿por qué no es cada función en la biblioteca estándar declarada constexpr? (No puedes discutir que aún no se ha hecho porque todavía no había tiempo suficiente para hacerlo, porque hacerlo para todos es una obviedad contrary contrario a decidir para cada función si hacerlo constexpr o no.) --- Soy consciente de que N2976 deliberadamente no requiere cstrs para muchos tipos de biblioteca estándar tales como los contenedores como esto sería demasiado limitante para posible aplicación. Vamos a excluirlos del argumento y solo preguntarse: una vez que un tipo en la biblioteca estándar realmente tiene un constexpr cstr, ¿por qué no cada función que opera en él declaró constexpr?

En la mayoría de los casos tampoco puede argumentar que puede preferir no declarar una función constexpr simplemente porque no prevé ningún uso en tiempo de compilación: porque si otros evtl. usarán su código, pueden ver tal uso que no. (Pero concedido para tipos de rasgos y cosas por igual, por supuesto.)

Así que supongo que debe haber una buena razón y un buen ejemplo para deliberadamente no declarar una función constexpr?

(con "cada función" siempre quiero decir: cada función que cumple con el requisitos para ser constexpr, es decir, se define como un único return, toma solo argumentos de tipos con constexpr cstrs y solo llama a funciones constexpr.)

La pregunta ¿por Qué std::forward descartar constexpr-ness? es un caso especial de este.

Author: einpoklum, 2011-02-25

3 answers

Las funciones solo se pueden declarar constexpr si obedecen las reglas de constexpr - - - no hay casts dinámicos, 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 comprobar para cada función que puede ser implementado como constexpr, que es un trabajo largo.

En segundo lugar, esta es una gran restricción en las implementaciones, y prohibirá muchas depuración de implementaciones. Por lo tanto, solo vale la pena si los beneficios superan los costos, o los requisitos son lo suficientemente ajustados como para que la implementación tenga que obedecer las reglas constexpr de todos modos. Hacer esta evaluación para cada función es de nuevo un trabajo largo.

 31
Author: Anthony Williams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-25 10:59:16

Creo que a lo que se refiere se llama evaluación parcial. Lo que estás 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 ninguna información de tiempo de ejecución - y que en teoría se podría evaluar completamente la parte del programa que no necesita ninguna información de tiempo de ejecución antes de empezar a ejecutar el programa. Hay algunos lenguajes de programación que hacen esto. Por ejemplo, la D el lenguaje de programación 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.

Hay algunos desafíos principales para conseguir que la evaluación parcial funcione. Primero, complica dramáticamente la lógica del compilador porque el compilador necesitará tener la capacidad de simular todas las operaciones que usted podría poner en un programa ejecutable en tiempo de compilación. Esto, en el peor de los casos, requiere que tenga una completa intérprete dentro del compilador, haciendo un problema difícil (escribir un buen compilador de C++) y haciéndolo órdenes de magnitud más difícil de hacer.

Creo que la razón de la especificación actual sobre constexpr es simplemente limitar la complejidad de los compiladores. Los casos a los que se limita son bastante fáciles de verificar. No hay necesidad de implementar bucles en el compilador (lo que podría causar toda una serie de problemas, como lo que sucede si obtiene un bucle infinito dentro del compilador). Se también evita que el compilador potencialmente tenga que evaluar sentencias que podrían causar segfaults en tiempo de ejecución, como seguir un mal puntero.

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 se pueden optimizar en tiempo de compilación, ya que hacerlo requeriría conocimiento solo disponible en tiempo de ejecución.

Para resumir, no hay ninguna razón teórica por la que no puedas evaluar parcialmente los programas C++ en tiempo de compilación. De hecho, la gente hace esto todo el tiempo. Los compiladores de optimización, por ejemplo, son esencialmente programas que tratan de hacer esto tanto como sea posible. La metaprogramación de plantillas es una instancia en la que los programadores de C++ intentan ejecutar código dentro del compilador, y es posible hacer algunas cosas geniales con plantillas en parte porque las reglas para las plantillas forman un lenguaje funcional, que el compilador tiene un tiempo más fácil de implementar. Por otra parte, si usted piensa de la compensación entre las horas de autor del compilador y las horas de programación, la metaprogramación de plantillas muestra que si está bien hacer que los programadores hagan lo imposible para obtener lo que quieren, puede construir un lenguaje bastante débil (el sistema de plantillas) y mantener la complejidad del lenguaje simple. (Digo " débil "como en" no particularmente expresivo", no" débil " en el sentido de la teoría de la computabilidad).

Espero que esto ayude!

 12
Author: templatetypedef,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-25 08:51:11

Si la función tiene efectos secundarios, no querrá marcarla constexpr. Ejemplo

No puedo obtener ningún resultado inesperado de eso, en realidad parece que gcc 4.5.1 simplemente ignora constexpr

 2
Author: Ben Voigt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-25 05:15:41