constexpr and consteval Functions in C++20
With C++20, constexpr
became way more powerful. Additionally, we have consteval
functions in C++20 that are quite similar to constexpr
functions.
Let me first describe a feature in C++20 that surprised me the most.
constexpr
Containers and Algorithms of the Standard Template Library
C++20 supports the constexpr
containers std::vector
and std::string
, where constexpr
means that the member functions of both containers can be applied at compile time. Additionally, more than
100 classical algorithms of the Standard Template Library are declared as constexpr
. Consequently, you can sort a std::vector
of ints at compile time.
Let’s see what this means:
// constexprVector.cpp #include <algorithm> #include <iostream> #include <vector> constexpr int maxElement() { std::vector myVec = {1, 2, 4, 3}; // (1) std::sort(myVec.begin(), myVec.end()); return myVec.back(); } int main() { std::cout << '\n'; constexpr int maxValue = maxElement(); std::cout << "maxValue: " << maxValue << '\n'; constexpr int maxValue2 = [] { std::vector myVec = {1, 2, 4, 3}; // (2) std::sort(myVec.begin(), myVec.end()) ; return myVec.back(); }(); std::cout << "maxValue2: " << maxValue2 << '\n'; std::cout << '\n'; }
The two containers std::vector
(lines (1) and (2)) are sorted at compile time using constexpr
-declared functions. In the first case, the function maxElement
returns the last element of the vector myVec
, which is its maximum value. In the second case, I use an immediately-invoked lambda that is declared constexpr.
Here is the output of the program:
Modernes C++ Mentoring
Do you want to stay informed: Subscribe.
The crucial idea for constexpr
containers is transient allocation.
Transient Allocation
Transient allocation means that memory allocated at compile time must also be released at compile time. Consequently, the compiler can detect a function’s mismatch of allocation and deallocation. The following example applies transient allocation.
// transientAllocation.cpp #include <memory> constexpr auto correctRelease() { auto* p = new int[2020]; delete [] p; return 2020; } constexpr auto forgottenRelease() { // (1) auto* p = new int[2020]; return 2020; } constexpr auto falseRelease() { // (3) auto* p = new int[2020]; delete p; // (2) return 2020; } int main() { constexpr int res1 = correctRelease(); constexpr int res2 = forgottenRelease(); constexpr int res3 = falseRelease(); }
The minor program has two serious issues. First, the memory in the constexpr
function forgottenRelease
(line (1)) is not released. Second, the non-array deallocation (line 3) in the constexpr
function falseRelease
(line (3)) does not match the array allocation. Consequentially, the compilation fails.
With C++20, we got consteval
functions that are pretty similar to contexpr
functions.
consteval
Functions
Often developers are irritated because they don’t know if a constexpr
function is executed at run time or compile time. Let’s consider the following code snippet.
constexpr int constexprFunction(int arg) { return arg * arg; } static_assert(constexprFunction(10) == 100); // (1) int arrayNewWithConstExpressiomFunction[constexprFunction(100)]; // (2) constexpr int prod = constexprFunction(100); // (3) int a = 100; int runTime = constexprFunction(a); // (4) int runTimeOrCompiletime = constexprFunction(100); // (5)
constexprFunction
is, as its name suggests, a constexpr
function.
- A constexpr function must run at compile time when used in a
constexpr
context, or the result is requested at compile time. line (1) and line (2) areconstexpr
contexts. Line (3), on the contrary, requires the function executionconstexprFuncion
on compile time. - The call
constexprFunction(a)
(line 4) must be executed at run time because a is not a constant expression. - Line 5 is an interesting case. There are no requirements for the function execution. Therefore, the call constexprFunction(100) (line 5) can be executed at run or compile times. From the C++ standard perspective, both are fine.
In contrast to a constexpr
function, a consteval
function can only be executed at compile time.
consteval
creates a so-called immediate function.
consteval int sqr(int n) { return n * n; }
Each invocation of an immediate function creates a compile-time constant. consteval
cannot be applied to destructors or functions that allocate or deallocate. A consteval
function is as a constexpr
function implicitly inline and has to fulfill the requirements for a constexpr
function.
The requirements of a constexpr
function in C++14 and, therefore, a consteval
function are:
- A
consteval
(constexpr
) can- have conditional jump instructions or loop instructions.
- have more than one instruction.
- invoke constexpr functions. A
consteval
function can only invoke aconstexpr
function but not the other way around. - use fundamental data types as variables that must be initialized with a constant expression.
- A
consteval
(constexpr
) function cannot- have static or
thread_local
data. - have a try block nor a goto instruction.
- invoke or use non-
consteval
functions or non-constexpr
data.
- have static or
There is one exciting use-case that consteval
enables. You can initialize a local non-constant variable at compile time.
// compileTimeInitializationLocal.cpp consteval auto doubleMe(auto val) { return 2 * val; } int main() { auto res = doubleMe(1010); // (1) ++res; // 2021 (2) }
The local res
is initialized at compile time (line 1) and modified at run time (line 2). On the contrary, if the function doubleMe
is declared as constexpr
, it could be executed at run time.
What’s next?
Before I dive into the new topic block design with templates, I want to present in the next post the C++17 feature constexpr if. constexpr if
enables it to compile source code conditionally and can be used for nice tricks at compile time.
Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Stephen Kelley, Kyle Dean, Tusar Palauri, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, Philipp Lenk, Charles-Jianye Chen, Keith Jeffery,and Matt Godbolt.
Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.
My special thanks to Embarcadero | |
My special thanks to PVS-Studio | |
My special thanks to Tipi.build | |
My special thanks to Take Up Code | |
My special thanks to SHAVEDYAKS |
Seminars
I’m happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.
Standard Seminars (English/German)
Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.
- C++ – The Core Language
- C++ – The Standard Library
- C++ – Compact
- C++11 and C++14
- Concurrency with Modern C++
- Design Pattern and Architectural Pattern with C++
- Embedded Programming with Modern C++
- Generic Programming (Templates) with C++
- Clean Code with Modern C++
- C++20
Online Seminars (German)
- Embedded
Programmierung mit modernem C++ (24. Sep. 2024 bis 26.
Sep. 2024)
Contact Me
- Mobil: +49 176 5506 5086
- Mail: schulung@ModernesCpp.de
- German Seminar Page: www.ModernesCpp.de
- Mentoring Page: www.ModernesCpp.org
Modernes C++ Mentoring,
Leave a Reply
Want to join the discussion?Feel free to contribute!