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 doubles. He creado una pregunta separada para eso aquí .

Author: Community, 2016-12-13

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.

 10
Author: AnT,
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.

 24
Author: Guillaume Racicot,
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