¿Cuál es la diferencia entre constexpr y const?

11 minutos de lectura

avatar de usuario
MBZ

Cuál es la diferencia entre constexpr y const?

  • ¿Cuándo puedo usar solo uno de ellos?
  • ¿Cuándo puedo usar ambos y cómo debo elegir uno?

  • constexpr crea una constante de tiempo de compilación; const simplemente significa que el valor no se puede cambiar.

    – David G.

    2 de enero de 2013 a las 1:44


  • Consulte también ¿Cuándo debería usar la capacidad constexpr en C++ 11?

    – jww

    3 de septiembre de 2016 a las 3:53

  • Puede ser este artículo de boost/hana la biblioteca puede iluminar algunos constexpr problemas en los que puede utilizar constexpr y donde no puedes: boost.org/doc/libs/1_69_0/libs/hana/doc/html/…

    – andry

    7 de febrero de 2019 a las 8:38


  • @0x499602D2 “simplemente significa que el valor no se puede cambiar” Para un escalar inicializado con un literal, un valor que no se puede cambiar es también una constante de tiempo de compilación.

    – chico curioso

    20 de enero de 2020 a las 23:09

  • @curiousguy Sí, mi comentario fue muy simplificado. Es cierto que era nuevo en constexpr entonces tambien 🙂

    – David G.

    20 de enero de 2020 a las 23:12


avatar de usuario
Karthik T

const aplica para Variablesy evita que se modifiquen en tu código.

constexpr le dice al compilador que esto expresión resulta en un valor constante de tiempo de compilaciónpor lo que se puede usar en lugares como longitudes de matrices, asignando a const variables, etc. El enlace proporcionado por Oli tiene muchos ejemplos excelentes.

Básicamente, son 2 conceptos diferentes en total, y pueden (y deben) usarse juntos.

  • uso de const y constexpr, por ejemplo: es.cppreference.com/w/cpp/container/array/get

    – Manohar Reddy Poreddy

    14 de mayo de 2017 a las 6:13


  • @ManoharReddyPoreddy creo es.cppreference.com/w/cpp/container/array/begin es un mejor ejemplo, tiene firmas con constexpr T f(x) constdonde ambos se aplican a la función, mientras que en constexpr const T f(x) (es decir, la matriz::obtener firma) la const es parte del tipo de devolución en lugar de la propiedad de la función (no estoy seguro del nombre para esto en estándar). Aunque este anunciante no reconoce el uso de const sobre las funciones de los miembros.

    – Ted

    28 de diciembre de 2020 a las 22:49


  • @ted Cambié mi lenguaje de programación de C ++ a javascript desde hace algún tiempo, por lo que apenas recuerdo lo publicado anteriormente :), y por lo tanto no puedo comentar por la misma razón.

    – Manohar Reddy Poreddy

    29 de diciembre de 2020 a las 14:17

  • Gracias por el excelente código de ejemplo que muestra las diferentes situaciones. Por muy buenas que sean algunas de las otras explicaciones, encontré que ver el código en acción es mucho más útil y comprensible. Realmente ayudó a solidificar mi comprensión de lo que está pasando.

    – RTHarston

    9 de febrero de 2019 a las 8:56

  • Gracias, esto me ayudó a entender mejor que la respuesta seleccionada.

    – AndreiToroplean

    8 de noviembre de 2020 a las 11:49

avatar de usuario
Timmy_A

Ambas cosas const y constexpr se puede aplicar a variables y funciones. Aunque son similares entre sí, en realidad son conceptos muy diferentes.

Ambas cosas const y constexpr significa que sus valores no se pueden cambiar después de su inicialización. Así por ejemplo:

const int x1=10;
constexpr int x2=10;

x1=20; // ERROR. Variable 'x1' can't be changed.
x2=20; // ERROR. Variable 'x2' can't be changed.

La principal diferencia entre const y constexpr es el momento en que se conocen (evaluan) sus valores de inicialización. Mientras que los valores de const las variables se pueden evaluar tanto en tiempo de compilación como en tiempo de ejecución, constexpr siempre se evalúan en tiempo de compilación. Por ejemplo:

int temp=rand(); // temp is generated by the the random generator at runtime.

const int x1=10; // OK - known at compile time.
const int x2=temp; // OK - known only at runtime.
constexpr int x3=10; // OK - known at compile time.
constexpr int x4=temp; // ERROR. Compiler can't figure out the value of 'temp' variable at compile time so `constexpr` can't be applied here.

La ventaja clave para saber si el valor se conoce en tiempo de compilación o en tiempo de ejecución es el hecho de que las constantes de tiempo de compilación se pueden usar siempre que se necesiten constantes de tiempo de compilación. Por ejemplo, C ++ no le permite especificar matrices C con longitudes variables.

int temp=rand(); // temp is generated by the the random generator at runtime.

int array1[10]; // OK.
int array2[temp]; // ERROR.

Entonces significa que:

const int size1=10; // OK - value known at compile time.
const int size2=temp; // OK - value known only at runtime.
constexpr int size3=10; // OK - value known at compile time.


int array3[size1]; // OK - size is known at compile time.
int array4[size2]; // ERROR - size is known only at runtime time.
int array5[size3]; // OK - size is known at compile time.

Asi que const las variables pueden definir ambos compilar constantes de tiempo me gusta size1 que se puede utilizar para especificar tamaños de matriz y constantes de tiempo de ejecución me gusta size2 que solo se conocen en tiempo de ejecución y no se pueden usar para definir tamaños de matrices. Por otro lado constexpr Siempre defina constantes de tiempo de compilación que puedan especificar tamaños de matriz.

Ambas cosas const y constexpr también se puede aplicar a funciones. UN const función debe ser una función miembro (método, operador) donde la aplicación de const palabra clave significa que el método no puede cambiar los valores de sus campos miembros (no estáticos). Por ejemplo.

class test
{
   int x;

   void function1()
   {
      x=100; // OK.
   }

   void function2() const
   {
      x=100; // ERROR. The const methods can't change the values of object fields.
   }
};

UN constexpr es un concepto diferente. Marca una función (miembro o no miembro) como la función que se puede evaluar en tiempo de compilación si las constantes de tiempo de compilación se pasan como sus argumentos. Por ejemplo, puedes escribir esto.

constexpr int func_constexpr(int X, int Y)
{
    return(X*Y);
}

int func(int X, int Y)
{
    return(X*Y);
}

int array1[func_constexpr(10,20)]; // OK - func_constexpr() can be evaluated at compile time.
int array2[func(10,20)]; // ERROR - func() is not a constexpr function.

int array3[func_constexpr(10,rand())]; // ERROR - even though func_constexpr() is the 'constexpr' function, the expression 'constexpr(10,rand())' can't be evaluated at compile time.

por cierto el constexpr Las funciones son las funciones regulares de C++ que se pueden llamar incluso si se pasan argumentos no constantes. Pero en ese caso, obtendrá los valores no constexpr.

int value1=func_constexpr(10,rand()); // OK. value1 is non-constexpr value that is evaluated in runtime.
constexpr int value2=func_constexpr(10,rand()); // ERROR. value2 is constexpr and the expression func_constexpr(10,rand()) can't be evaluated at compile time.

Él constexpr también se puede aplicar a las funciones miembro (métodos), operadores e incluso constructores. Por ejemplo.

class test2
{
    static constexpr int function(int value)
    {
        return(value+1);
    }

    void f()
    {
        int x[function(10)];


    }
};

Una muestra más ‘loca’.

class test3
{
    public:

    int value;

    // constexpr const method - can't chanage the values of object fields and can be evaluated at compile time.
    constexpr int getvalue() const
    {
        return(value);
    }

    constexpr test3(int Value)
        : value(Value)
    {
    }
};


constexpr test3 x(100); // OK. Constructor is constexpr.

int array[x.getvalue()]; // OK. x.getvalue() is constexpr and can be evaluated at compile time.

  • Además, en C, constexpr int existe pero se escribe const int

    – chico curioso

    18 de enero de 2019 a las 22:22

No creo que ninguna de las respuestas aclare exactamente qué efectos secundarios tiene o, de hecho, qué es.

constexpr y const at namespace/file-scope son idénticos cuando se inicializan con un literal o una expresión; pero con una función, const puede ser inicializado por cualquier función, pero constexpr inicializado por una expresión no constexpr (una función que no está marcada con constexpr o una expresión no constexpr) generará un error de compilación. Ambas cosas constexpr y const son enlaces implícitamente internos para las variables (bueno, en realidad, no sobreviven para llegar a la etapa de enlace si se compila -O1 y más fuerte, y static no obliga al compilador a emitir un símbolo de enlace interno (local) para const o constexpr cuando está en -O1 o más fuerte; la única vez que hace esto es si toma la dirección de la variable. const y constexpr será un símbolo interno a menos que se exprese con extern es decir extern constexpr/const int i = 3; necesita ser usado). En una función, constexpr hace que la función de forma permanente nunca llegue a la etapa de vinculación (independientemente de extern o inline en la definición o -O0 o -Ofast), mientras que const nunca lo hace, y static y inline solo tiene este efecto en -O1 y superiores. Cuando un const/constexpr variable es inicializada por un constexpr función, la carga siempre se optimiza con cualquier bandera de optimización, pero nunca se optimiza si la función es solo static o inlineo si la variable no es una const/constexpr.

Compilación estándar (-O0)

#include<iostream>
constexpr int multiply (int x, int y)
{

  return x * y;
}

extern const int val = multiply(10,10);
int main () {
  std::cout << val;
} 

compila a

val:
        .long   100  //extra external definition supplied due to extern

main:
        push    rbp
        mov     rbp, rsp
        mov     esi, 100 //substituted in as an immediate
        mov     edi, OFFSET FLAT:_ZSt4cout
        call    std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
        mov     eax, 0
        pop     rbp
        ret

__static_initialization_and_destruction_0(int, int):
        . 
        . 
        . 

Sin embargo

#include<iostream>
const int multiply (int x, int y)
{

  return x * y;
}

const int val = multiply(10,10); //constexpr is an error
int main () {
  std::cout << val;
}

Compila a

multiply(int, int):
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], edi
        mov     DWORD PTR [rbp-8], esi
        mov     eax, DWORD PTR [rbp-4]
        imul    eax, DWORD PTR [rbp-8]
        pop     rbp
        ret

main:
        push    rbp
        mov     rbp, rsp
        mov     eax, DWORD PTR val[rip]
        mov     esi, eax
        mov     edi, OFFSET FLAT:_ZSt4cout
        call    std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
        mov     eax, 0
        pop     rbp
        ret

__static_initialization_and_destruction_0(int, int):
        . 
        . 
        . 
        mov     esi, 10
        mov     edi, 10
        call    multiply(int, int)
        mov     DWORD PTR val[rip], eax

Esto muestra claramente que constexpr provoca la inicialización del const/constexpr La variable de alcance de archivo se produce en el momento de la compilación y no produce ningún símbolo global, mientras que no usarla hace que la inicialización se produzca antes main en tiempo de ejecución.

Compilando usando -Ofast

¡Incluso -Ofast no optimiza la carga! https://godbolt.org/z/r-mhifvos tambien necesidad constexpr


constexpr Las funciones también se pueden llamar desde dentro de otros constexpr funciones para el mismo resultado. constexpr on a function también evita el uso de cualquier cosa que no se pueda hacer en tiempo de compilación en la función; por ejemplo, una llamada al << operador en std::cout.

constexpr en el alcance del bloque se comporta igual en el sentido de que produce un error si se inicializa mediante una función que no es constexpr; el valor también se sustituye inmediatamente.

Al final, su propósito principal es como la función en línea de C, pero solo es efectiva cuando la función se usa para inicializar variables de ámbito de archivo (que las funciones no pueden hacer en C, pero sí en C++ porque permite la inicialización dinámica de archivos). variables de alcance), excepto que la función tampoco puede exportar un símbolo global/local al enlazador, incluso usando extern/staticcon el que podrías inline en C; Las funciones de asignación de variables de alcance de bloque se pueden incorporar simplemente usando una optimización -O1 sin constexpr en C y C++.

  • Además, en C, constexpr int existe pero se escribe const int

    – chico curioso

    18 de enero de 2019 a las 22:22

UN const int var se puede establecer dinámicamente en un valor en tiempo de ejecución y una vez que se establece en ese valor, ya no se puede cambiar.

UN constexpr int var no se puede configurar dinámicamente en tiempo de ejecución, sino en tiempo de compilación. Y una vez que se establece en ese valor, ya no se puede cambiar.

Aquí hay un ejemplo sólido:

int main(int argc, char*argv[]) {
    const int p = argc; 
    // p = 69; // cannot change p because it is a const
    // constexpr int q = argc; // cannot be, bcoz argc cannot be computed at compile time 
    constexpr int r = 2^3; // this works!
    // r = 42; // same as const too, it cannot be changed
}

El fragmento de código anterior compila bien y he comentado aquellos que causan el error.

Las nociones clave aquí para tomar nota son las nociones de compile time y run time. Se han introducido nuevas innovaciones en C++ con la intención de, en la medida de lo posible, ** know ** ciertas cosas en tiempo de compilación para mejorar el rendimiento en tiempo de ejecución.

Cualquier intento de explicación que no involucre las dos nociones clave anteriores es una alucinación.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad