Compile-Time Evaluation

constexpr and consteval with Lambdas

Can I use constexpr or consteval with lambda functions?

Illustration representing computer hardware

Yes, you can use both constexpr and consteval with lambda functions in C++20 and later. This feature allows you to create powerful compile-time computations with the convenience of lambda syntax. Let's explore how to use them:

constexpr Lambdas

By default, all lambda functions in C++17 and later are implicitly constexpr if possible. This means if all the operations inside the lambda are allowed in a constant expression, the lambda will be constexpr.

#include <iostream>

int main() {
  constexpr auto square = [](int x) {
    return x * x;
  };
  constexpr int result = square(5);
  std::cout << "5 squared is: " << result;
}
5 squared is: 25

You can also explicitly declare a lambda as constexpr:

constexpr auto cube = [](int x) constexpr {
  return x * x * x;
};

This example demonstrates two important points about constexpr and lambdas:

  1. The constexpr before auto tells the compiler that the lambda object itself should be a compile-time constant. This means the lambda can be used in contexts that require constant expressions, such as template arguments or array sizes.
  2. The constexpr after the parameter list ([](int x) constexpr) explicitly declares that the lambda's function call operator should be constexpr. This ensures that the lambda can be called in constant expressions.

While the second constexpr is often redundant (as lambdas are implicitly constexpr when possible), explicitly declaring it can serve as documentation and will cause a compilation error if the lambda body isn't actually eligible to be constexpr.

Here's an expanded example to illustrate these points:

#include <iostream>
#include <array>

int main() {
  // Lambda object is constexpr
  // function call operator is implicitly constexpr
  constexpr auto square = [](int x) {
    return x * x;
  };

  // Lambda object is constexpr
  // function call operator is explicitly constexpr
  constexpr auto cube = [](int x) constexpr {
    return x * x * x;
  };

  // Use in a constant expression (array size)
  std::array<int, square(3)> arr1;
  std::array<int, cube(3)> arr2;

  std::cout << "arr1 Size: " << arr1.size() << '\n';
  std::cout << "arr2 Size: " << arr2.size() << '\n';

  // Use in another constant expression
  constexpr int result1 = square(4);
  constexpr int result2 = cube(4);

  std::cout << "4 squared: " << result1 << '\n';
  std::cout << "4 cubed: " << result2 << '\n';
}
arr1 Size: 9
arr2 Size: 27
4 squared: 16
4 cubed: 64

In this example, both square() and cube() can be used in constant expressions, such as array sizes and constexpr variable initializations. The difference in their declaration is mostly a matter of style and explicitness.

consteval Lambdas

C++20 introduces the ability to create consteval lambdas. These are guaranteed to be evaluated at compile-time.

// A consteval lambda example
auto add = [](int a, int b) consteval {
  return a + b;
};

int main() {
  // This is fine
  constexpr int a{1}, b{2};
  add(5, 3);

  // This will be a compilation error
  int c{3}, d{4};
  add(c, d);
}
error: call to immediate function is not a constant expression
note: see usage of 'c'

Using Lambdas in Template Arguments

One powerful use of constexpr and consteval lambdas is in template arguments:

#include <iostream>

template <auto Func>
consteval int apply(int x) {
  return Func(x);
}

int main() {
  // constexpr lambda for squaring a number
  constexpr auto square = [](int x) constexpr {
    return x * x;
  };

  std::cout << "Square of 5: " << apply<square>(5);

  // consteval lambda for cubing a number
  constexpr auto cube = [](int x) consteval {
    return x * x * x;
  };
  std::cout << "\nCube of 3: " << apply<cube>(3);
}
Result: 25
Result: 27

Remember, when using constexpr or consteval with lambdas, all captured variables must be known at compile-time. Also, the lambda body must only contain operations that are allowed in a constant expression.

These features open up new possibilities for metaprogramming and compile-time computations, allowing you to write more expressive and efficient code.

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