Step 4 of 8
constexpr
Templates run the type machinery at compile time. constexpr lets ordinary calculations run at compile time too. A constexpr function can be evaluated by the compiler whenever its arguments are compile-time constants, and the result is baked into the program as a number.
#include <array>
#include <iostream>
constexpr int factorial(int n) {
int result = 1;
for (int i = 2; i <= n; i++) result *= i;
return result;
}
constexpr int cube(int x) { return x * x * x; }
static_assert(factorial(5) == 120); // checked while compiling
static_assert(cube(3) == 27, "cube is broken");
int main() {
std::array<int, cube(2)> slots{}; // size 8, known at compile time
std::cout << slots.size() << "\n";
constexpr int f6 = factorial(6); // computed by the compiler
std::cout << f6 << "\n";
int n = 4; // a run-time value...
std::cout << factorial(n) << "\n"; // ...so this call runs normally
}
8
720
24
How it works
static_assert(condition)is checked by the compiler. If it's false, the program doesn't compile at all. It's a test that runs before your program exists.- Anything that needs a compile-time constant, like a
std::arraysize or a template argument, can use aconstexprfunction call. - The same function still works at run time with normal variables, as
factorial(n)shows. - Since C++14,
constexprfunctions can have loops, local variables andifstatements. They can't do things like I/O or (before C++20) heap allocation.
Your task: power
Multiply result by base, exp times, starting from result = 1. Mark the function constexpr; the tests use static_assert, so without it the tests won't even compile. Use long long for the result so big powers fit.
Your task
Write constexpr long long power(long long base, int exp). The tests include static_asserts, so if your function can't run at compile time, it won't even compile.
Challenge 2
Write constexpr bool is_prime(int n) (false below 2) and constexpr int count_primes_below(int n). The tests use static_assert, so both must work at compile time.
Challenge 3
Write template <std::size_t N> constexpr std::array<int, N> first_squares() returning {0, 1, 4, 9, ...}, the first N squares. It must work at compile time.