2 minutes
C++: const vs constexpr
Constants
C++ supports two notions of immutability:
const:
- meaning roughly “I promise not to change this value.”
- This is used primarily to specify interfaces so that data can be passed to functions using pointers and references without fear of it being modified.
- The compiler enforces the promise made by const.
- The value of a const can be calculated at run time
constexpr:
- meaning roughly “to be evaluated at compile time.”
- This is used primarily to specify constants, to allow placement of data in read-only memory (where it is unlikely to be corrupted), and for performance.
- The value of a constexpr must be calculated by the compiler
Since the value of constexpr is calculated at compile-time instead of run-time, the program performs better during run-time.
constexpr Functions
A function must be of the type constexpr if its result is to be assigned to a constexpr.
For example:
constexpr double square(double x) { return x∗x; }
constexpr double max1 = 1.4∗square(17); // OK 1.4*square(17) is a constant expression
const double max3 = 1.4∗square(var); // OK, may be evaluated at run time
In the last line above, we see that a constexpr function can be used for non-constant arguments, but the result will no longer be a constexpr and will not be calculated at compile-time. This is merely a feature of the language, so that the constexpr function must not be defined twice: once for constant expressions and once for variables.
To be constexpr, a function must be rather simple and cannot have side effects and can only use information passed to it as arguments. In particular, it cannot modify non-local variables, but it can have loops and use its own local variables. For example:
constexpr double nth(double x, int n) // assume 0<=n
{
double res = 1;
int i = 0;
while (i<n) {
res∗=x;
++i;
}
return res;
}
In a few places, constant expressions are required by language rules (e.g., array bounds, case labels, template value arguments, and constants declared using constexpr). In other cases, compile-time evaluation is important for performance. Independently of performance issues, the notion of immutability (an object with an unchangeable state) is an important design concern.