const vs constexpr em variables

Existe uma diferença entre as seguintes definições?

const double PI = 3.141592653589793; constexpr double PI = 3.141592653589793; 

Se não, qual estilo é preferido no C ++ 11?

Eu acredito que há uma diferença. Vamos renomeá-los para que possamos falar sobre eles com mais facilidade:

 const double PI1 = 3.141592653589793; constexpr double PI2 = 3.141592653589793; 

Tanto o PI1 quanto o PI2 são constantes, o que significa que você não pode modificá-los. No entanto, apenas PI2 é uma constante de tempo de compilation. Deve ser inicializado em tempo de compilation. PI1 pode ser inicializado em tempo de compilation ou tempo de execução. Além disso, somente o PI2 pode ser usado em um contexto que requer uma constante de tempo de compilation. Por exemplo:

 constexpr double PI3 = PI1; // error 

mas:

 constexpr double PI3 = PI2; // ok 

e:

 static_assert(PI1 == 3.141592653589793, ""); // error 

mas:

 static_assert(PI2 == 3.141592653589793, ""); // ok 

Quanto ao que você deve usar? Use o que atender às suas necessidades. Você quer garantir que você tenha uma constante de tempo de compilation que possa ser usada em contextos onde uma constante de tempo de compilation é necessária? Você quer ser capaz de inicializá-lo com um cálculo feito em tempo de execução? Etc.

Nenhuma diferença aqui, mas é importante quando você tem um tipo que tem um construtor.

 struct S { constexpr S(int); }; const S s0(0); constexpr S s1(1); 

s0 é uma constante, mas não promete ser inicializada em tempo de compilation. s1 é marcado como constexpr , portanto, é uma constante e, como o construtor S também é marcado como constexpr , ele será inicializado em tempo de compilation.

Principalmente, isso é importante quando a boot em tempo de execução consumiria muito tempo e você desejasse enviar esse trabalho para o compilador, onde ele também consome tempo, mas não diminui o tempo de execução do programa compilado.

constexpr indica um valor constante e conhecido durante a compilation.
const indica um valor que é apenas constante; não é obrigatório saber durante a compilation.

 int sz; constexpr auto arraySize1 = sz; // error! sz's value unknown at compilation std::array data1; // error! same problem constexpr auto arraySize2 = 10; // fine, 10 is a compile-time constant std::array data2; // fine, arraySize2 is constexpr 

Note que const não oferece a mesma garantia que constexpr, porque os objects const não precisam ser inicializados com valores conhecidos durante a compilation.

 int sz; const auto arraySize = sz; // fine, arraySize is const copy of sz std::array data; // error! arraySize's value unknown at compilation 

Todos os objects constexpr são const, mas nem todos os objects const são constexpr.

Se você quiser que os compiladores garantam que uma variável tenha um valor que possa ser usado em contextos que exigem constantes de tempo de compilation, a ferramenta a ser alcançada é constexpr, não const.

Uma constante simbólica constexpr deve receber um valor que é conhecido em tempo de compilation. Por exemplo:

 constexpr int max = 100; void use(int n) { constexpr int c1 = max+7; // OK: c1 is 107 constexpr int c2 = n+7; // Error: we don't know the value of c2 // ... } 

Para lidar com casos em que o valor de uma “variável” é inicializado com um valor que não é conhecido em tempo de compilation, mas nunca é alterado após a boot, o C ++ oferece uma segunda forma de constante (a const ). Por exemplo:

 constexpr int max = 100; void use(int n) { constexpr int c1 = max+7; // OK: c1 is 107 const int c2 = n+7; // OK, but don't try to change the value of c2 // ... c2 = 7; // error: c2 is a const } 

Essas “variables const ” são muito comuns por dois motivos:

  1. C ++ 98 não tinha constexpr, então as pessoas usavam const .
  2. O item de lista “Variáveis” que não são expressões constantes (seu valor não é conhecido em tempo de compilation), mas não alteram valores após a boot, são amplamente úteis.

Referência: “Programação: Princípios e Práticas Usando C ++” por Stroustrup