将函数指针转换为 noexcept 指定的函数指针

Casting a function pointer into a noexcept specified function pointer

假设我有这些声明:

using fp_type = void(*)();
using fp2_type = void(*)() noexcept;

void func(){}
fp_type fp(func);

演员表fp2_type(fp)是否合式?反过来(将 noexcept 指定的函数指针转换为没有 noexcept 说明符的函数指针)?

这在 C++14 和更早版本中是错误的:

using fp2_type = void(*)() noexcept;

由于 N4140 [except.spec]/2:

An exception-specification shall not appear in a typedef declaration or alias-declaration.

所以我假设问题是针对 C++1z 的,其中异常规范是类型系统的一部分。


[conv.fctptr]/1:

A prvalue of type “pointer to noexcept function” can be converted to a prvalue of type “pointer to function”. The result is a pointer to the function.

因此,void (*)() noexcept 可以(隐含地)转换为 void (*)()

[expr.static.cast]/7:

The inverse of any standard conversion sequence (Clause [conv]) not containing a [(various other cases omitted)] function pointer ([conv.fctptr]) conversion, can be performed explicitly using static_cast.

[expr.static.cast] 中的任何其他内容都不允许将 void (*)() 转换为 void (*)() noexcept,因此这不是 static_cast 可以执行的转换。

[expr.reinterpret.cast]/6:

A function pointer can be explicitly converted to a function pointer of a different type. The effect of calling a function through a pointer to a function type ([dcl.fct]) that is not the same as the type used in the definition of the function is undefined. Except that converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are function types) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified. [ Note: see also [conv.ptr] for more details of pointer conversions. — end note ]

因此 reinterpret_cast 可以执行此转换。

因为 fp2_type(fp) 等同于 C 风格的转换 (fp2_type) fp[expr.type.conv]/1), and since C-style casts do a reinterpret_cast when static_cast is not possible(为简单起见忽略 const_cast,因为它与此处无关),fp2_type(fp) 是一个格式正确的 reinterpret_cast。但是,这种类型转换的结果不能使用,除非将其转换回去。