const, constexpr, consteval and constinit - C++20
As of c++20 there are 4 keywords begginning with const
. What do they mean?
Are they similar? Let's look at them.
Contents
const
Declares an object as a runtime constant, once initialized the value won't change.
A const
object is read-only but this does not imply that it is
immutable nor does imply that the value is always the same.
You can change the value of a const object with mutable
keyword and
const_cast
.
Where to use
const
applies to the thing left of it, if there's nothing on the left, then
it applies to the thing right of it.
const int *
: nothing on the left, so const if for int: a pointer to a constant integer. equivalent toint const *
.int* const
: a constant pointer to an integer, the pointer cannot point to other address, the content can be changed.const int* const
: a constant pointer to a constant integer, both content and the address are read-only, equivalent toint const* const
.int const* const*
: a pointer to a const pointer to a constant integer.int const* const* const
: a constant pointer to a constnat pointer to a constant integer.
const object
const Foo foo
- needs to be initialized at the time of declaration.
- attempt to change the data member of const objects results in a compile-time error.
const member function
Not allowed to modify the object.
class Foo() {
// ...
void bar() const;
};
Function parameters
The top-level, or outermost, const qualifications of the parameter type specification are ignored.
void Foo(const int n); // 1: declares F(int)
void Foo(int* const n); // 2: declares F(int*)
void Foo(const int* const n); // 3: declares F(const int*)
constexpr
Constant expressions are used to move computation from runtime to compile time. But it is not metaprogramming.
It can be applied to:
- variables: compile time constants, thus
constexpr
variables are implicitlyconst
. - functions: return value is computable at compile time, but member functions are not implicitly
const
.
Example of a constexpr
function:
// it can be computable at compile time
constexpr int Foo() {
return 42;
}
constexpr
functions are implicitly inline
, a constexpr
function in just
an inline
function that is allowed to execute at compile time when
initializing constant values (but it can also run on runtime).
Note even constructors can be constexpr
.
consteval
This specifier is only for functions, and it's like constexpr
,
but you are not allowed to call that function in a non-constant expression
context, its utility is to force the function to be called at
compile time only.
Someone once said this about consteval
functions: "its utility is in
allowing you to write an abysmally slow function without the risk of you
calling it at runtime".
constinit
Asserts that a variable has static initialization, if initialization uses a
function it must be constexpr
or consteval
.
It doesn't imply const
.
constinit int foo = 42;
constinit Bar bar = create_bar(); // create_bar() must be constexpr or consteval
Most useful application is to be able to declare a static local variable
without paying for the mutex that guards that variable's initialization (and
this variables are not usually const
).
Note that if a type has constexpr
or consteval
constructors,
you can declare a variable of that type as constinit
, as long
as the constructor it uses has one of the previous specifiers of course.