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?

- 449,505
- 63
- 781
- 982

- 1,559
- 9
- 15
-
1"*with all the negative sides that derive from that*" Such as? – Nicol Bolas May 23 '20 at 15:00
-
@JesperJuhl: You cannot "language-lawyer" a "why" question, because the specification doesn't state "why" any particular feature is the way it is. You can't demand spec citations for something the spec defines. – Nicol Bolas May 23 '20 at 15:06
-
some algorithms perform different actions depending on noexcept specification (see std::vector::resize() ). Also the compiler may remove exception handling code for a non-throwing function – user7769147 May 23 '20 at 15:07
-
I would say coherency with regular function, and as you said *"throwing exceptions is still disallowed"* so that allow to change that more intuitively. – Jarod42 May 23 '20 at 15:41
-
2Why _should_ a `consteval` function be `noexcept`? What are the benefits you would even get from breaking orthogonality like that? – Barry May 23 '20 at 15:53
-
@Barry _"Why should a consteval function be noexcept?"_ because it never throws – user7769147 May 23 '20 at 16:43
-
1@user7769147 That's true, but it also doesn't answer the question. – Barry May 23 '20 at 17:12
-
Back in C++11, `constexpr` implied `const` for member functions. Look at where that ended up. – T.C. May 23 '20 at 20:51
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.

- 449,505
- 63
- 781
- 982
-
"it preserves the ability for compile-time code to be able to throw exceptions in the future" those exceptions would result in compile time error, they wouldn't propagate out of the functions anyway. " immediate functions only ever exist at compile time, which is a context that doesn't have exception handling" consider ```consteval int foo() {return 42; } void bar(int = foo()) noexcept;``` in this case bar() is not noexcept! – user7769147 May 23 '20 at 15:25
-
"*those exceptions would result in compile time error, they wouldn't propagate out of the functions anyway.*" I'm talking about a future language change, where they remove the prohibition on compile-time exception throwing. – Nicol Bolas May 23 '20 at 15:30
-
2@user7769147: "*in this case bar() is not noexcept!*" Yes, it is. `noexcept` doesn't verify if the code within it cannot cause an exception to be emitted. It is merely a statement that this function will not emit exceptions, and if it tries to, `std::terminate` will be called. – Nicol Bolas May 23 '20 at 15:31
-
_"I'm talking about a future language change, where they remove the prohibition on compile-time exception throwing"_ it doesn't make any sense at all, throwing an exception in a compile-time context should be like using a static_assert, compilation should stop instead of handling the exception at runtime. _""in this case bar() is not noexcept!" Yes, it is"_ you are right, my bad – user7769147 May 23 '20 at 15:42
-
@user7769147: "*throwing an exception in a compile-time context should be like using a static_assert, compilation should stop instead of handling the exception at runtime.*" I didn't say anything about handling the exception "at runtime"; a compile-time exception would be handled *at compile-time*. Exception handling is, at its core, a control flow mechanism. So long as the compile-time exception doesn't escape into runtime code, it's fine. This would allow `consteval` functions to give errors using standard mechanisms, rather than returning an `optional` that you have to explicitly check. – Nicol Bolas May 23 '20 at 16:29
-
"compile time exceptions" in that sense already exist, `if(condition) throw "....";` in an immediate function will stop compilation if and only if `condition` is true – user7769147 May 23 '20 at 16:42
-
@user7769147: When I say "compile-time exception", I don't mean "compilation stops when an exception is throw". I mean "exception propagation happens ***at compile-time***", just like all of the rest of C++ that's allowable at compile time. – Nicol Bolas May 23 '20 at 17:42
-
-
1@user7769147: Not every exception means that the world is broken and the application must terminate. Exceptions can be recoverable states, and exception propagation allows for communicating that information to its destination without having a lot of intermediary code checking the return value of every function. – Nicol Bolas May 23 '20 at 19:45
-
That makes sense at runtime, I can't see a valid usage of exceptions at compile-time – user7769147 May 23 '20 at 21:29