Studying about \"noexcept specifier(and operator)\", I wrote a simple code. And I am surprised that this piece of code:
v
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.