ggulgulia
ggulgulia

Reputation: 3080

C++ usage of constexpr with lambda expression

I was reading book C++17 - The Complete Guide and in the section 6.1 on constexpr lambda the author gives two examples:

auto squared1 = [](auto val) constexpr { // example 1. compile-time lambda calls
  return val * val;
};

and

constexpr auto squared2 = [](auto val) { // example 2. compile-time initialization
  return val * val;
};

and says that these two are different from each other in the sense that example 1 is evaluated at compile time and example 2 is initialized at compile time.


The author then makes the following statements which I don't understand completely:

If (only) the lambda is constexpr it can be used at compile time, but If the (closure) object initialized by the lambda is constexpr, the object is initialized when the program starts but the lambda might still be a lambda that can only be used at run time (e.g., using static variables). Therefore, you might consider declaring:

constexpr auto squared = [](auto val) constexpr { // example 3
  return val * val;
};

What does the above statement mean exactly?

It is obvious that the constexpr keyword appears on initialization statement of squared2 lambda object and on the lambda expression itself in example 3 but I don't understand what is the advantage of this over example 1 .

Upvotes: 13

Views: 3186

Answers (1)

einpoklum
einpoklum

Reputation: 132260

The thing is, that an auto-declared object does not adopt the constexpr'ness of its initializing expression, only its type; and constexpr is not part of that type. See:

Why does `auto` not adopt the constexpr'ness of its initializing expression?

So, suppose I had:

auto five_squared = 25;

the value 25 is very much constexpr, i.e. it can be used at compile-time. And yet - five_squared will not be usable at compile-time. You would still need to indicate it is constexpr (*).

It's essentially the same with your lambda. A lambda is an instance of an on-the-spot-defined class with an operator(). Nothing about that would make squared be a constexpr variable if you don't make it one yourself.


(*) - Note that because of a special rule in the C++ language, const integers that are initialized with a constant-expression are automatically constexpr, so you could just write const auto and get the constexpr implicitly. However, this is a tricky special-case to have to remember, so if you want to make a variable constexpr I recommend being explicit about it. Thanks goes to @cigien for bringing up this point.

Upvotes: 10

Related Questions