Why immediate functions are not noexcept by default and why are they allowed to be noexcept(false)?

Viewed 270

As of c++20 we can define immediate functions by using the consteval specifier. When a function is declared consteval every call to that function must produce a compile-time constant otherwise the program is ill-formed. Also, since c++20 try-catch blocks are allowed in constant evaluated contexts but throwing exceptions is still disallowed. Because of this I initially thought that as consteval implies inline it also implies noexcept since throwing any exception is forbidden. As you can imagine at this point, this is not true: unless you specify noexcept, an immediate function is a potentially throwing function with all the negative sides that derive from that. Is there a reason for this I'm not aware of?

1 Answers

Some algorithms performs different actions depending on noexcept specification (see std::vector::resize() ). Also the compiler may remove exception handling code for a non-throwing function

Immediate functions are called at compile-time. While C++20 does in fact have compile-time containers now, their performance is kind of irrelevant to runtime code. And it would be easy enough for them to use different internal implementations based on if(is_constant_evaluated), which would benefit more than just noexcept queries.

But even then, one of the goals of constexpr coding is to make compile-time code be like runtime code. So if you have a class that should only exist at compile-time and has a consteval move constructor, then the user should think of it exactly like they would a runtime class. So if they would make the move constructor noexcept in a runtime class, it should be in a compile-time class too.

And that's doubly important, since it preserves the ability for compile-time code to be able to throw exceptions in future versions of the language. This is possible particularly if P0709: Static Exceptions gets into the standard.

Also, immediate functions only ever exist at compile time, which is a context that doesn't have exception handling. So whatever the compiler is doing to build code for a constexpr function, it doesn't involve exception handling machinery. So making them implicitly noexcept for code generation purposes makes no sense.

Lastly, consteval is ultimately built as a minor change from constexpr function declarations. Even the implicit inline comes from consteval meaning constexpr, rather than consteval itself. Adding a new semantic to consteval would be making a significant change.

Related