1. Background
[P3068] applied the specifier to the functions in the header .
is one of these functions, however at runtime its return value depends on mutable global state.
It is impossible to implement to return a constexpr value that is consistent with the runtime state. When evaluated in a constant expression, the current implementations of [P3068] return the number of uncaught exceptions in the current constant evaluation instead of the current thread.
The inconsistency of the semantics of depending on whether it is called from a constant expression or at runtime causes a breaking change when the function is called in trial constant evaluation.
integer variables are usable in constant expressions when they are constant-initialized, so when initializing them the initializer is constant evaluated first, and if that fails then the variable is initialized at runtime. Consider:
#include <exception>int i = 1 ; int main () { try { struct S { ~ S () { // x is initialized to 0 in trial constant evaluation const int x = std :: uncaught_exceptions (); i = x ; } }; S s ; throw 0 ; } catch (...) { return i ; } }
The program returns 0, which is a breaking change compared to C++23, where it returns 1.
2. Proposal
-
Remove the
specifier fromconstexpr .uncaught_exceptions () -
Add a
function with similar semantics toconsteval int consteval_uncaught_exceptions () noexcept ; , but counting exceptions within the current constant evaluation.uncaught_exceptions ()
3. Motivation
is useful to write scope guards and other patterns to conditionally execute code when normally exiting a scope or due to stack unwinding.
Now that we have exception facilities available in constant evaluation, this functionality is similarly useful in that context.
Putting the functionality in a separate function makes this functionality available in constant evaluation without a breaking change.
4. Implementation experience
There is previous implementation experience for [P3068] including . Splitting the functionality into separate runtime and functions is a trivial change.
5. Wording
Wording is relative to [N5013].
5.1. [exception.syn]
constexprint uncaught_exceptions() noexcept; consteval int consteval_uncaught_exceptions() noexcept;
5.2. [uncaught.exceptions]
constexprint uncaught_exceptions() noexcept;
Returns: The number of uncaught exceptions ([except.throw]) in the current thread.
Remarks: When , throwing an exception can result in a call of the function .
Returns: The number of uncaught exceptions ([except.throw]) in the current constant evaluation.
Remarks: When , throwing an exception can result in a call of the function .