Date: Sun, 27 Apr 2025 00:16:59 +0100
The whole 'noexcept' thing has gotten a bit hairy in C++. We've
already thrown 'throw' specifiers out the window, but even now in
C++26 the situation isn't ideal, given that people are now writing
code as follows:
template<typename T>
bool Func(T &arg) noexcept ( noexcept(++arg) && noexcept((bool)!!arg) )
{
++arg;
return !!arg;
}
. . .which is why some people are now asking for:
template<typename T>
bool Func(T &arg) noexcept(auto)
{
++arg;
return !!arg;
}
But anyway let's bring it back to basics for a minute. Consider the
following program:
int Func1(int const arg)
{
throw -1;
}
int Func2(int const arg) noexcept
{
return Func1(arg);
}
int main(int const argc, char **const argv)
{
Func2(42);
}
I don't know about the rest of you, but I wouldn't want this program
to compile successfully. I would like a compiler error for the line
"Func1(arg)" because you're calling a "noexcept(false)" function from
a "noexcept(true)" function. To force the compiler to reject this
program, you can add one line to the body of "Func2" as follows:
int Func2(int const arg) noexcept
{
static_assert( noexcept( Func1(arg) ) );
return Func1(arg);
}
but similar to the first example I gave in this post, things gets a
bit hairy when you have to duplicate lines of code, something like:
int Func2(int const arg) noexcept
{
static_assert( noexcept( Func1(arg & global1 | global2) ) );
return Func1(arg & global1 | global2);
}
I think we should have a way of marking a function so that the
compiler will refuse to compile it if it:
(1) throws an exception (e.g. by using 'throw' or 'std::rethrow_exception')
or
(2) calls another function that isn't marked as 'noexcept'
I think this would also allow the compiler to optimise more aggressively.
Now this is the part where I would suggest a new syntax or a new
keyword, but I don't want to get too caught up in the little things
just yet as I'm afraid JW will tear apart my new syntax or new keyword
without giving much consideration to the essence of the new feature
I'm trying to invent. But anyway . . . how about the following:
int Func2(int const arg) noexcept(explicit)
{
return Func1(arg & global1 | global2);
}
When the compiler encounters "noexcept(explicit)" tagged onto a
function definition, it will refuse to compile the function if the
function satisfies any of the two criteria I mentioned above.
Then there would be a few more little things to consider, such as:
(a) Should we allow the throwing of an exception so long as it's
caught before leaving the function? (This would have implications for
the optimiser)
(b) What happens if 'Func1' is in a 3rd party library compiled by a
different compiler which has produced a function which _can_ actually
throw an exception even though it's marked as noexcept? Should this
just be undefined behaviour?
(c) Will the name mangling systems have to be extended?
(d) What happens if the function is given C linkage with extern "C"?
Or what if some of the called functions have C linkage?
(e) What about functions like "std::strcmp" that are really "noexcept"
but aren't marked as such?
But the main thing I'm talking about here is as follows:
In some instances we want to see a compiler error rather than see
a runtime error to say that std::terminate was called, in particular
when writing template functions.
I fed my idea in ChatGPT and asked it to produce one concise paragraph
describing the benefits this new feature could bring, and it gave me
back:
"This new feature would be invaluable for writing highly reliable,
high-performance C++ code by allowing developers to enforce at compile
time that certain critical functions are truly exception-free. It
would eliminate hidden runtime risks caused by unexpected exceptions,
enabling better compiler optimizations, more predictable program
behavior, and safer use of noexcept functions in performance-sensitive
contexts like real-time systems, embedded programming, and low-latency
applications. By making exception guarantees explicit and enforceable,
it would significantly strengthen the trustworthiness and
maintainability of large, complex C++ codebases."
Sounds good to me.
already thrown 'throw' specifiers out the window, but even now in
C++26 the situation isn't ideal, given that people are now writing
code as follows:
template<typename T>
bool Func(T &arg) noexcept ( noexcept(++arg) && noexcept((bool)!!arg) )
{
++arg;
return !!arg;
}
. . .which is why some people are now asking for:
template<typename T>
bool Func(T &arg) noexcept(auto)
{
++arg;
return !!arg;
}
But anyway let's bring it back to basics for a minute. Consider the
following program:
int Func1(int const arg)
{
throw -1;
}
int Func2(int const arg) noexcept
{
return Func1(arg);
}
int main(int const argc, char **const argv)
{
Func2(42);
}
I don't know about the rest of you, but I wouldn't want this program
to compile successfully. I would like a compiler error for the line
"Func1(arg)" because you're calling a "noexcept(false)" function from
a "noexcept(true)" function. To force the compiler to reject this
program, you can add one line to the body of "Func2" as follows:
int Func2(int const arg) noexcept
{
static_assert( noexcept( Func1(arg) ) );
return Func1(arg);
}
but similar to the first example I gave in this post, things gets a
bit hairy when you have to duplicate lines of code, something like:
int Func2(int const arg) noexcept
{
static_assert( noexcept( Func1(arg & global1 | global2) ) );
return Func1(arg & global1 | global2);
}
I think we should have a way of marking a function so that the
compiler will refuse to compile it if it:
(1) throws an exception (e.g. by using 'throw' or 'std::rethrow_exception')
or
(2) calls another function that isn't marked as 'noexcept'
I think this would also allow the compiler to optimise more aggressively.
Now this is the part where I would suggest a new syntax or a new
keyword, but I don't want to get too caught up in the little things
just yet as I'm afraid JW will tear apart my new syntax or new keyword
without giving much consideration to the essence of the new feature
I'm trying to invent. But anyway . . . how about the following:
int Func2(int const arg) noexcept(explicit)
{
return Func1(arg & global1 | global2);
}
When the compiler encounters "noexcept(explicit)" tagged onto a
function definition, it will refuse to compile the function if the
function satisfies any of the two criteria I mentioned above.
Then there would be a few more little things to consider, such as:
(a) Should we allow the throwing of an exception so long as it's
caught before leaving the function? (This would have implications for
the optimiser)
(b) What happens if 'Func1' is in a 3rd party library compiled by a
different compiler which has produced a function which _can_ actually
throw an exception even though it's marked as noexcept? Should this
just be undefined behaviour?
(c) Will the name mangling systems have to be extended?
(d) What happens if the function is given C linkage with extern "C"?
Or what if some of the called functions have C linkage?
(e) What about functions like "std::strcmp" that are really "noexcept"
but aren't marked as such?
But the main thing I'm talking about here is as follows:
In some instances we want to see a compiler error rather than see
a runtime error to say that std::terminate was called, in particular
when writing template functions.
I fed my idea in ChatGPT and asked it to produce one concise paragraph
describing the benefits this new feature could bring, and it gave me
back:
"This new feature would be invaluable for writing highly reliable,
high-performance C++ code by allowing developers to enforce at compile
time that certain critical functions are truly exception-free. It
would eliminate hidden runtime risks caused by unexpected exceptions,
enabling better compiler optimizations, more predictable program
behavior, and safer use of noexcept functions in performance-sensitive
contexts like real-time systems, embedded programming, and low-latency
applications. By making exception guarantees explicit and enforceable,
it would significantly strengthen the trustworthiness and
maintainability of large, complex C++ codebases."
Sounds good to me.
Received on 2025-04-26 23:17:07