Yes, you can use both constexpr
and consteval
with recursive functions. This is a powerful feature that allows you to perform complex compile-time computations. Let's explore this with some examples:
constexpr
FunctionHere's a classic example of a recursive factorial function using constexpr
. This function will be evaluated at compile-time when used in a constant expression.
#include <iostream>
constexpr int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
int main() {
constexpr int result = factorial(5);
std::cout << "5! = " << result;
}
5! = 120
consteval
FunctionYou can also use consteval
to ensure the function is always evaluated at compile-time:
#include <iostream>
consteval int fibonacci(int n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
int main() {
constexpr int result = fibonacci(10);
std::cout << "10th Fibonacci number: "
<< result << '\n';
}
10th Fibonacci number: 55
While you can use recursion in constexpr
and consteval
functions, be aware of compiler limitations. Most compilers have a limit on the depth of constexpr recursion:
This might result in a compiler error or warning about exceeding recursion limits.
constexpr long long very_deep_recursion(int n) {
if (n == 0) return 0;
return 1 + very_deep_recursion(n - 1);
}
int main() {
// Might exceed limits
constexpr int result = very_deep_recursion(1000);
}
error: expression did not evaluate to a constant
note: failure was caused by evaluation exceeding call depth limit of 512
Here's a more practical example using recursion to compute a string hash at compile-time:
This recursive function computes the FNV-1a hash of a string at compile-time, which could be useful for switch statements or other compile-time decisions based on strings.
#include <iostream>
#include <string_view>
constexpr uint32_t fnv1a_32(
std::string_view sv, size_t idx = 0) {
constexpr uint32_t FNV_offset_basis = 2166136261U;
constexpr uint32_t FNV_prime = 16777619U;
return idx == sv.size() ? FNV_offset_basis
: (fnv1a_32(sv, idx + 1) ^ sv[idx]) * FNV_prime;
}
int main() {
constexpr auto hash = fnv1a_32("Hello, World!");
std::cout << "Hash of 'Hello, World!': " << hash;
}
Hash of 'Hello, World!': 3644920852
Remember, when using recursion in constexpr
or consteval
functions, ensure that there's a clear base case to prevent infinite recursion. Also, be mindful of the potential for long compilation times with complex recursive computations.
Despite these considerations, recursive constexpr
and consteval
functions are powerful tools for compile-time metaprogramming in C++.
Answers to questions are automatically generated and may not have been reviewed.
Learn how to implement functionality at compile-time using constexpr
and consteval