constexpr
objects are const
and are initialized with values known during compilation; constexpr
functions can produce copmile-time results when called with arguments whose values are know during compilations.
constexpr
objects
Values known during compmilation are privileged: they may be placed in read-only memory (important for embedded systems), and part of them with constant integral values can be used in contexts where C++ requires an integral constant expression1. Thuse, if we want the compilers to ensure that a variable is constant with a value know at compile time, we declare it constexpr
:
|
|
All constexpr
objects are const
, but not all const
objects are constexpr
, because const
objects need not be initialized with values known during compilations:
|
|
constexpr
functions
constexpr
is part of a functions’s interface, which proclaims “I can be used in a context where C++ requires a constant expression.” In other words:
- if the values of the arguments we pass to a
constexpr
function are known during compilation, the result will be computed during compilation - when a
constexpr
function is called with one or more values that are not known during compilation, it acts like a normal function, computing its result at runtime: so that we don’t need two functions to perform the same operation.
For example, we want to initialize a std::array
with the size of 3^n, wher n is a known integer (or can be computed) during compilation. std::pow
doesn’t help here, because
std::pow
works on floating-point types, while we need an integral resultstd::pow
isn’t constexpr
Thus, we write the pow we need:
|
|
In C++11, there’re some restrictions on constexpr
functions:
- they may only contain a single return statement
- they are limited to taking and returning literal types2
so the implementation goes like this:
|
|
For C++14, the restrictions are substantially looser:
|
|
constexpr
functions can work with user-defined literal types, too:
|
|
By introducing constexpr
, we can maximize the range of situation our objects and functions may be used - the traditionally fairly strict line between work done during compilation and work done at runtime begins to blur after we use constexpr
constructors, constexpr
getters, constexpr
setters, constepxr
non-member functions, and create objects in read-only memory:
|
|
As a result, the more code taking part in the compilation time, the faster our software will run3.
-
Such contexts include specification of array sizes, integral template arguments, enumerator values, alignment specifiers, etc. ↩︎
-
Literal types: types that can have values determined during compilation. In C++11, all built-in types except
void
qualify, plus some user-defined types whose constructors and other member functions areconstexpr
. ↩︎ -
Compilation may take longer, however. ↩︎