const, constexpr, consteval and constinit - C++20

27 January 2023

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 object

const Foo foo

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:

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.

Sources