constexpr vs static const: cuál prefiere?
For defining compile-time constants of integral types like the following (at function and class scope), which syntax is best?
static const int kMagic = 64; // (1)
constexpr int kMagic = 64; // (2)
(1)
funciona también para compiladores de C++98/03, en cambio (2)
requiere al menos C++11. ¿Hay alguna otra diferencia entre los dos? ¿Debería preferirse uno u otro en el código C++ moderno, y por qué?
EDITAR
Probé este código de ejemplo con El CE de Godbolt :
int main()
{
#define USE_STATIC_CONST
#ifdef USE_STATIC_CONST
static const int kOk = 0;
static const int kError = 1;
#else
constexpr int kOk = 0;
constexpr int kError = 1;
#endif
return kOk;
}
Y para el caso static const
este es el ensamblado generado por GCC 6.2:
main::kOk:
.zero 4
main::kError:
.long 1
main:
push rbp
mov rbp, rsp
mov eax, 0
pop rbp
ret
Por otro lado, para constexpr
es:
main:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], 0
mov DWORD PTR [rbp-8], 1
mov eax, 0
pop rbp
ret
Aunque en -O3
en ambos casos obtengo el mismo ensamblaje (optimizado):
main:
xor eax, eax
ret
EDITAR #2
Probé este sencillo código (vivir en Ideone):
#include <iostream>
using namespace std;
int main() {
const int k1 = 10;
constexpr int k2 = 2*k1;
cout << k2 << '\n';
return 0;
}
Que muestra que const int k1
se evalúa en tiempo de compilación, como se usa para calcular constexpr int k2
.
Sin embargo, parece haber un diferente comportamiento para double
s. He creado una pregunta separada para eso aquí .
2 answers
Mientras estemos hablando de declarar constantes en tiempo de compilación de escalar enteros o enum, no hay absolutamente ninguna diferencia entre usar const
(static const
en el ámbito de la clase) o constexpr
.
Tenga en cuenta que los compiladores deben admitir objetos static const int
(declarados con inicializadores constantes) en expresiones constantes, lo que significa que no tienen otra opción que tratar dichos objetos como constantes en tiempo de compilación. Además, mientras tales objetos permanezcan sin usar, no requieren definición, que demuestra además que no se utilizarán como valores de tiempo de ejecución.
Además, las reglas de inicialización constante impiden que los objetos locales static const int
se inicialicen dinámicamente, lo que significa que no hay ninguna penalización de rendimiento por declarar dichos objetos localmente. Además, la inmunidad de los objetos integrales static
a los problemas de ordenación de la inicialización estática es una característica muy importante del lenguaje.
constexpr
es una extensión y generalización del concepto esto se implementó originalmente en C++ a través de const
con un inicializador constante. Para tipos enteros constexpr
no ofrece nada extra sobre lo que const
ya hizo. constexpr
simplemente realiza una comprobación temprana de la "constancia" del inicializador. Sin embargo, se podría decir que constexpr
es una característica diseñada específicamente para ese propósito, por lo que se ajusta mejor estilísticamente.
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
2016-12-14 15:15:21
constexpr
se garantiza que la variable tenga un valor disponible en tiempo de compilación. mientras que static const
miembros o const
variable podría significar un valor de tiempo de compilación o un valor de tiempo de ejecución. Escribiendo constexpr
exprese su intención de un valor de tiempo de compilación de una manera mucho más explícita que const
.
Una cosa más, en C++17, constexpr
las variables miembro de datos estáticos también estarán en línea. Eso significa que puede omitir la definición fuera de línea de las variables static constexpr
, pero no static const
.
Como una demanda en el sección de comentarios, aquí hay una explicación más detallada sobre static const
en el ámbito de la función.
Una variable static const
en el ámbito de la función es prácticamente la misma, pero en lugar de tener una duración de almacenamiento automática, tiene una duración de almacenamiento estático. Eso significa que es de alguna manera el equivalente de declarar la variable como global, pero solo accesible en la función.
Es cierto que una variable static
se inicializa en la primera llamada de la función, pero como es const
también, el compilador intente alinear el valor y optimizar la variable completamente. Así que en una función, si el valor se conoce en tiempo de compilación para esta variable en particular, entonces el compilador lo más probable es que lo optimice.
Sin embargo, si el valor no se conoce en tiempo de compilación para un static const
en el ámbito de la función, podría silenciosamente hacer que su función (un bit muy pequeño) sea más lenta, ya que tiene que inicializar el valor en tiempo de ejecución la primera vez que se llama a la función. Además, tiene para comprobar si el valor se inicializa cada vez que se llama a la función.
Esa es la ventaja de una variable constexpr
. Si el valor no se conoce en tiempo de compilación, es un error de compilación, no una función más lenta. Entonces si usted no tiene manera de determinar el valor de su variable en tiempo de compilación, entonces el compilador le dirá acerca de ella y usted puede hacer algo al respecto.
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
2017-08-04 11:44:21