C++ - const vs constexpr vs consteval vs constinit
TL;DR
const vs constexpr
const
:- runtime constant
- can only be used for non-static member functions, not functions in general.
constexpr
: Since C++11- compile-time constant
- can be used for both variables and functions.
All constexpr
variables are const
, constexpr
member functions are NOT implicitly const
.
These are equivalent:
const char* const
constexpr const char*
constexpr const char* const
constexpr vs consteval functions
constexpr
functions: introduced in C++11; MAY be evaluated at compile-time, but may be at runtime.consteval
functions: introduced in C++20, a.k.a. immediate functions; MUST be evaluated at compile-time; always produce a compile-time expression and always visible only at compile-time.consteval
can only be applied to the declaration of a function or function template- shall be applied only to the declaration of a function or function template
const
Declares an object as constant, i.e. once initialized, the value won't change.
Read-only, but not Immutable or always the same
A const
object is read-only but this does not imply that it is immutable nor does it imply that the value is always the same.
void f(const std::string& s) {
const int size = s.size();
// ...
}
f(""); // size = 0
f("foo"); // size = 3
Other ways to change a const: mutable
keyword and const_cast
Where to use const
TL;DR: 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, soconst
if forint
: 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
const
member function: not allowed to modify the object.
Compare:
const
function: can be called on any type of object.- Non-
const
function: can only be called by non-const
objects.
Best practice: make as many functions const
as possible so that accidental changes to objects are avoided.
Function parameters
The top-level, or outermost, const
qualifications of the parameter type specification are ignored.
void F(const int x); // 1: declares F(int)
void F(int* const x); // 2: declares F(int*)
void F(const int* const x); // 3: declares F(const int*)
constexpr
constexpr
= constant expression.
Using constexpr
= moving computation from runtime to compile time. (it is NOT metaprogramming) A good talk: https://www.youtube.com/watch?v=MdrfPSUtMVM
It can be applied to:
- variables: compile time constants.
constexpr
variables are implicitlyconst
, - functions: return value is computable at compile time, e.g.
constexpr int Foo() { return 42; }
.constexpr
member functions are NOT implicitlyconst
.
Define variables constexpr
in .cc
files or declare them extern const
in .h
files.
All constexpr
functions are implicitly inline
: a constexpr
function is just an inline
function that is allowed to execute at compile time when initializing constant values.
constinit
constinit
: Since C++20, asserts that a variable has static initialization (zero initialization or constant initialization).