La respuesta corta es que no solo es static
útil, sino que siempre va a ser deseable.
Primero, tenga en cuenta que static
y constexpr
son completamente independientes entre sí. static
define la vida útil del objeto durante la ejecución; constexpr
especifica que el objeto debe estar disponible durante la compilación. La compilación y la ejecución son disjuntas y no contiguas, tanto en el tiempo como en el espacio. Entonces, una vez que se compila el programa, constexpr
ya no es relevante.
Cada variable declarada constexpr
es implícita const
, pero const
y static
son casi ortogonal (a excepción de la interacción con static const
números enteros).
El C++
modelo de objetos (§1.9) requiere que todos los objetos que no sean campos de bits ocupen al menos un byte de memoria y tengan direcciones; además, todos esos objetos observables en un programa en un momento dado deben tener direcciones distintas (párrafo 6). Esto no requiere que el compilador cree una nueva matriz en la pila para cada invocación de una función con una matriz const local no estática, porque el compilador podría refugiarse en el as-if
principio siempre que pueda probar que ningún otro objeto puede ser observado.
Desafortunadamente, eso no será fácil de probar, a menos que la función sea trivial (por ejemplo, no llama a ninguna otra función cuyo cuerpo no sea visible dentro de la unidad de traducción) porque las matrices, más o menos por definición, son direcciones. Por lo tanto, en la mayoría de los casos, la const(expr)
matriz no estática tendrá que recrearse en la pila en cada invocación, lo que frustra el punto de poder calcularla en el momento de la compilación.
Por otro lado, un static const
objeto local es compartido por todos los observadores, y además puede inicializarse incluso si la función en la que se define nunca se llama. Por lo tanto, nada de lo anterior se aplica, y un compilador es libre no solo para generar solo una sola instancia; es libre de generar una sola instancia en el almacenamiento de solo lectura.
Así que definitivamente deberías usarlo static constexpr
en tu ejemplo.
Sin embargo, hay un caso en el que no querrás usar static constexpr
. A menos que un constexpr
objeto declarado sea utilizado o declarado por ODRstatic
, el compilador es libre de no incluirlo en absoluto. Eso es bastante útil, porque permite el uso de constexpr
matrices temporales en tiempo de compilación sin contaminar el programa compilado con bytes innecesarios. En ese caso, claramente no querrá usar static
, ya que static
es probable que obligue al objeto a existir en tiempo de ejecución.
const
de unconst
objeto, solo desde un puntoconst X*
que apunta a unX
. Pero ese no es el punto; El punto es que los objetos automáticos no pueden tener direcciones estáticas. Como ya he dicho,constexpr
deja de ser significativa una vez finalizada la compilación, por lo que no hay nada de esparcir (y, posiblemente, nada en absoluto, porque el objeto no está garantizada incluso de existir en tiempo de ejecución.)static
yconstexpr
explicas que son ortogonales e independientes, que hacen cosas diferentes. Luego mencionas una razón para NO combinar los dos, ya que ignoraría el uso de ODR (lo que parece útil). Ah, y todavía no entiendo por qué static debería usarse con constexpr ya que static es para cosas de tiempo de ejecución. Nunca explicaste por qué la estática con constexpr es importante.static constexpr
(evita que la matriz constante tenga que recrearse en cada llamada de función), pero modifiqué algunas palabras que podrían aclararlo. Gracias.constexpr
variable constante solo se usa en contextos de tiempo de compilación y nunca se necesita en el tiempo de ejecución, entoncesstatic
no tiene sentido, ya que para el momento en que se llega al tiempo de ejecución, el valor ha sido efectivamente "en línea". Sin embargo, siconstexpr
se usa en contextos de tiempo de ejecución (en otras palabras,constexpr
sería necesario convertirloconst
implícitamente y estar disponible con una dirección física para el código de tiempo de ejecución) querrástatic
garantizar el cumplimiento de ODR, etc. Eso es lo que entiendo, al menos.static constexpr int foo = 100;
. No hay ninguna razón por la cual el compilador no pueda sustituir el uso defoo
todas partes por literal100
, a menos que el código esté haciendo algo así&foo
. Así questatic
elfoo
no tiene ninguna utilidad en este caso, yafoo
no existe en tiempo de ejecución. Nuevamente todo depende del compilador.Además de la respuesta dada, vale la pena señalar que no se requiere que el compilador inicialice la
constexpr
variable en el momento de la compilación, sabiendo que la diferencia entreconstexpr
ystatic constexpr
usarlastatic constexpr
garantiza que la variable se inicialice solo una vez.El siguiente código demuestra cómo la
constexpr
variable se inicializa varias veces (aunque con el mismo valor), mientrasstatic constexpr
que seguramente solo se inicializa una vez.Además, el código compara la ventaja de
constexpr
contraconst
en combinación constatic
.Posible salida del programa:
Como puede ver,
constexpr
se inicia varias veces (la dirección no es la misma), mientras que lastatic
palabra clave garantiza que la inicialización se realice solo una vez.fuente
constexpr const short constexpr_short
para dar error si constexpr_short se inicializa de nuevoconstexpr const
no tiene sentido porqueconstexpr
ya lo esconst
, elconst
compilador ignora agregar una o varias veces. Estás intentando detectar un error, pero este no es un error, así es como funciona la mayoría de los compiladores.