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
.