Ambos son constantes en tiempo de compilación. Pero puedes hacer un const_cast del primero y escribirle. Pero cualquier compilador lo optimizará, ya que esto no influye en las "lecturas" como suceden en tiempo de compilación.
Bonita Montero
Respuestas:
347
Creo que hay una diferencia. Cambiemos el nombre para que podamos hablar sobre ellos más fácilmente:
Ambos PI1y PI2son constantes, lo que significa que no puede modificarlos. Sin embargo, soloPI2 es una constante de tiempo de compilación. Se deberá ser inicializado en tiempo de compilación. PI1puede inicializarse en tiempo de compilación o en tiempo de ejecución. Además, soloPI2 se puede usar en un contexto que requiere una constante de tiempo de compilación. Por ejemplo:
¿Cuál debería usar? Use el que satisfaga sus necesidades. ¿Desea asegurarse de tener una constante de tiempo de compilación que pueda usarse en contextos donde se requiere una constante de tiempo de compilación? ¿Desea poder inicializarlo con un cálculo realizado en tiempo de ejecución? Etc.
¿Estás seguro? Porque const int N = 10; char a[N];funciona, y los límites de la matriz deben ser constantes de tiempo de compilación.
fredoverflow
10
Estoy seguro de que los ejemplos que escribí van (probé cada uno de ellos antes de publicarlos). Sin embargo, mi compilador me permite convertir PI1a una constante integral en tiempo de compilación para usar en una matriz, pero no para usar como un parámetro de plantilla integral sin tipo. Entonces, la convertibilidad en tiempo de compilación de PI1un tipo integral me parece un poco impredecible.
Howard Hinnant
34
@FredOverflow: los índices de matriz no constantes han "funcionado" durante aproximadamente una década (por ejemplo, hay una extensión de g ++ para eso), pero eso no significa que sea estrictamente legal C ++ (aunque algunos estándares más recientes de C o C ++ lo hicieron legal , I olvidé cuál) En cuanto a las diferencias en las constantes de tiempo de compilación, los parámetros de plantilla y el uso como enuminicializador son las dos únicas diferencias notables entre consty constexpr(y ninguno funciona de doubletodos modos).
Damon
17
El párrafo 4 de 5.19 Expresiones constantes [expr.const] también es una nota (no normativa) que destaca que una implementación puede hacer aritmética de punto flotante de manera diferente (por ejemplo, con respecto a la precisión) en tiempo de compilación que en tiempo de ejecución. Entonces, 1 / PI1y 1 / PI2puede dar resultados diferentes. Sin embargo, no creo que este tecnicismo sea tan importante como el consejo de esta respuesta.
Luc Danton el
44
Pero constexpr double PI3 = PI1;funciona correctamente para mí. (MSVS2013 CTP). ¿Qué estoy haciendo mal?
NuPagadi
77
No hay diferencia aquí, pero es importante cuando tienes un tipo que tiene un constructor.
struct S {constexpr S(int);};const S s0(0);constexpr S s1(1);
s0es una constante, pero no promete ser inicializada en tiempo de compilación. s1está marcado constexpr, por lo que es una constante y, dado que Sel constructor también está marcado constexpr, se inicializará en tiempo de compilación.
Principalmente, esto es importante cuando la inicialización en tiempo de ejecución lleva mucho tiempo y desea llevar ese trabajo al compilador, donde también lleva mucho tiempo, pero no ralentiza el tiempo de ejecución del programa compilado
Estoy de acuerdo: la conclusión a la que llegué fue que constexprconduciría a un diagnóstico si el cálculo en tiempo de compilación del objeto fuera imposible. Lo que está menos claro es si una función que espera un parámetro constante podría ejecutarse en tiempo de compilación si el parámetro se declara como consty no como constexpr: es decir, ¿ constexpr int foo(S)se ejecutaría en tiempo de compilación si llamo foo(s0)?
Matthieu M.
44
@MatthieuM: Dudo si foo(s0)se ejecutaría en tiempo de compilación, pero nunca se sabe: un compilador puede hacer tales optimizaciones. Ciertamente, ni gcc 4.7.2 ni clang 3.2 me permiten compilarconstexpr a = foo(s0);
rici
50
constexpr indica un valor constante y conocido durante la compilación. const indica un valor que solo es constante; No es obligatorio saberlo durante la compilación.
int sz;constexprauto arraySize1 = sz;// error! sz's value unknown at compilation
std::array<int, sz> data1;// error! same problemconstexprauto arraySize2 =10;// fine, 10 is a compile-time constant
std::array<int, arraySize2> data2;// fine, arraySize2 is constexpr
Tenga en cuenta que const no ofrece la misma garantía que constexpr, porque los objetos const no necesitan inicializarse con valores conocidos durante la compilación.
int sz;constauto arraySize = sz;// fine, arraySize is const copy of sz
std::array<int, arraySize> data;// error! arraySize's value unknown at compilation
Todos los objetos constexpr son const, pero no todos los objetos const son constexpr.
Si desea que los compiladores garanticen que una variable tiene un valor que se puede usar en contextos que requieren constantes de tiempo de compilación, la herramienta para alcanzar es constexpr, no const.
Me gustó mucho tu explicación ... ¿puedes comentar más sobre dónde están los casos en que podríamos necesitar usar constantes de tiempo de compilación en escenarios de la vida real?
A una constante simbólica constexpr se le debe dar un valor que se conoce en tiempo de compilación. Por ejemplo:
constexprint max =100;void use(int n){constexprint c1 = max+7;// OK: c1 is 107constexprint c2 = n+7;// Error: we don’t know the value of c2// ...}
Para manejar casos en los que el valor de una "variable" que se inicializa con un valor que no se conoce en el momento de la compilación pero que nunca cambia después de la inicialización, C ++ ofrece una segunda forma de constante (una constante ). Por ejemplo:
constexprint max =100;void use(int n){constexprint c1 = max+7;// OK: c1 is 107constint c2 = n+7;// OK, but don’t try to change the value of c2// ...
c2 =7;// error: c2 is a const}
Tales " variables constantes " son muy comunes por dos razones:
C ++ 98 no tenía constexpr, por lo que las personas usaban const .
Enumere el elemento "Variables" que no son expresiones constantes (su valor no se conoce en el momento de la compilación) pero que no cambian los valores después de la inicialización son en sí mismas ampliamente útiles.
Referencia: "Programación: Principios y práctica usando C ++" por Stroustrup
Tal vez debería haber mencionado que el texto en su respuesta está tomado literalmente de "Programación: Principios y práctica usando C ++" por Stroustrup
Respuestas:
Creo que hay una diferencia. Cambiemos el nombre para que podamos hablar sobre ellos más fácilmente:
Ambos
PI1
yPI2
son constantes, lo que significa que no puede modificarlos. Sin embargo, soloPI2
es una constante de tiempo de compilación. Se deberá ser inicializado en tiempo de compilación.PI1
puede inicializarse en tiempo de compilación o en tiempo de ejecución. Además, soloPI2
se puede usar en un contexto que requiere una constante de tiempo de compilación. Por ejemplo:pero:
y:
pero:
¿Cuál debería usar? Use el que satisfaga sus necesidades. ¿Desea asegurarse de tener una constante de tiempo de compilación que pueda usarse en contextos donde se requiere una constante de tiempo de compilación? ¿Desea poder inicializarlo con un cálculo realizado en tiempo de ejecución? Etc.
fuente
const int N = 10; char a[N];
funciona, y los límites de la matriz deben ser constantes de tiempo de compilación.PI1
a una constante integral en tiempo de compilación para usar en una matriz, pero no para usar como un parámetro de plantilla integral sin tipo. Entonces, la convertibilidad en tiempo de compilación dePI1
un tipo integral me parece un poco impredecible.enum
inicializador son las dos únicas diferencias notables entreconst
yconstexpr
(y ninguno funciona dedouble
todos modos).1 / PI1
y1 / PI2
puede dar resultados diferentes. Sin embargo, no creo que este tecnicismo sea tan importante como el consejo de esta respuesta.constexpr double PI3 = PI1;
funciona correctamente para mí. (MSVS2013 CTP). ¿Qué estoy haciendo mal?No hay diferencia aquí, pero es importante cuando tienes un tipo que tiene un constructor.
s0
es una constante, pero no promete ser inicializada en tiempo de compilación.s1
está marcadoconstexpr
, por lo que es una constante y, dado queS
el constructor también está marcadoconstexpr
, se inicializará en tiempo de compilación.Principalmente, esto es importante cuando la inicialización en tiempo de ejecución lleva mucho tiempo y desea llevar ese trabajo al compilador, donde también lleva mucho tiempo, pero no ralentiza el tiempo de ejecución del programa compilado
fuente
constexpr
conduciría a un diagnóstico si el cálculo en tiempo de compilación del objeto fuera imposible. Lo que está menos claro es si una función que espera un parámetro constante podría ejecutarse en tiempo de compilación si el parámetro se declara comoconst
y no comoconstexpr
: es decir, ¿constexpr int foo(S)
se ejecutaría en tiempo de compilación si llamofoo(s0)
?foo(s0)
se ejecutaría en tiempo de compilación, pero nunca se sabe: un compilador puede hacer tales optimizaciones. Ciertamente, ni gcc 4.7.2 ni clang 3.2 me permiten compilarconstexpr a = foo(s0);
constexpr indica un valor constante y conocido durante la compilación.
const indica un valor que solo es constante; No es obligatorio saberlo durante la compilación.
Tenga en cuenta que const no ofrece la misma garantía que constexpr, porque los objetos const no necesitan inicializarse con valores conocidos durante la compilación.
Todos los objetos constexpr son const, pero no todos los objetos const son constexpr.
Si desea que los compiladores garanticen que una variable tiene un valor que se puede usar en contextos que requieren constantes de tiempo de compilación, la herramienta para alcanzar es constexpr, no const.
fuente
A una constante simbólica constexpr se le debe dar un valor que se conoce en tiempo de compilación. Por ejemplo:
Para manejar casos en los que el valor de una "variable" que se inicializa con un valor que no se conoce en el momento de la compilación pero que nunca cambia después de la inicialización, C ++ ofrece una segunda forma de constante (una constante ). Por ejemplo:
Tales " variables constantes " son muy comunes por dos razones:
Referencia: "Programación: Principios y práctica usando C ++" por Stroustrup
fuente