Studying about "noexcept specifier(and operator)", I wrote a simple code. And I am surprised that this piece of code:
void asdf() noexcept {}
int main()
{
auto f = asdf;
std::cout << std::boolalpha << noexcept(f()) << std::endl;
}
prints false
, even function "asdf" is noexcept-specified.
So while searching why this mysterious phenomenon is happening, I found C++17's "exception specifier type system"- P0012R1.
According to this (accepted) proposal, since C++17; as noexcept
is part of function type, will the code above print true
?
And one more, in this question's one line:
std::function<void() noexcept> f
The noexcept
specifying seems ignored in C++14 or 11.
Will this code work as intended in C++17?
According to this (accepted) proposal, since C++17; as noexcept is part of function type, will the code above print
true
?
Yes.
The type of f
will be deduced to void(*)() noexcept
since the function-to-pointer conversion applied to asdf
will preserve the noexcept
property. A call to a noexcept
function pointer certainly cannot throw an exception, unless one of its subexpressions does.
For the exact wording, see [expr.unary.noexcept]/3 and [expect.spec]/13. Note that the new wording in the latter paragraph from the C++17 draft comes from P0012R1, which is linked in the OP.
The result of the
noexcept
operator istrue
if the set of potential exceptions of the expression ([except.spec]) is empty, andfalse
otherwise....
- If
e
is a function call ([expr.call]):
- If its postfix-expression is a (possibly parenthesized) id-expression ([expr.prim.id]), class member access ([expr.ref]), or pointer-to-member operation ([expr.mptr.oper]) whose cast-expression is an id-expression, S is the set of types in the exception specification of the entity selected by the contained id-expression (after overload resolution, if applicable). ...
So the set of potential exceptions of f()
is the same as the set of types in the exception specification of f
, which is empty since f
is declared noexcept
.
Let's move on to the second question:
The
noexcept
specifying seems ignored in C++14 or 11. Will this code work as intended in C++17?
Your question seems to be: will std::function<void() noexcept>
refuse to hold a function that can throw exceptions?
I would say that it's unclear. In the present wording of the standard, std::function<void() noexcept>
is not actually defined, just as std::function<double(float) const>
is not defined. This was of course not an issue in C++14, since noexcept
was not considered part of a function's type.
Will std::function<void() noexcept>
simply break in C++17? That's uncertain to me. Let's take a look at the current wording to guess what the behaviour "should" be.
The standard requires the argument to the constructor of std::function<R(ArgTypes..)>
to be "Lvalue-Callable" for argument types ArgTypes...
and return type R
, which means:
A callable type ([func.def])
F
is Lvalue-Callable for argument typesArgTypes
and return typeR
if the expressionINVOKE(declval<F&>(), declval<ArgTypes>()..., R)
, considered as an unevaluated operand (Clause [expr]), is well formed ([func.require]).
Perhaps there should be an additional requirement that if the function type is noexcept
, then noexcept(INVOKE(...))
must be true as well. Nonetheless, this wording is not present in the current draft.
In P0012R1, there is a comment that:
It is an open issue how to propagate "noexcept" through
std::function
.
My guess is that they mean that it is not clear how std::function
could be implemented if this additional requirement were imposed. Hopefully, someone else can provide more details.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With