Compile-Time Evaluation

constexpr with Recursive Functions

Can I use constexpr or consteval with recursive functions?

Illustration representing computer hardware

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:

Basic Recursive constexpr Function

Here'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

Recursive consteval Function

You 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

Compile-Time Limitations

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

Practical Use Case - Compile-Time String Hashing

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.

A computer programmer
Part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, unlimited access

This course includes:

  • 125 Lessons
  • 550+ Code Samples
  • 96% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved