为什么在 gcc 的 is_nothrow_constructible 实现中需要 static_cast?

Joã*_*res 11 c++ libstdc++ static-cast type-traits

取自 GCC 实现type_traits为什么static_cast需要这里?

template <typename _Tp, typename... _Args>
struct __is_nt_constructible_impl
    : public integral_constant<bool, noexcept(_Tp(declval<_Args>()...))> {};

template <typename _Tp, typename _Arg>
struct __is_nt_constructible_impl<_Tp, _Arg>
    : public integral_constant<bool,
                               // Why is `static_cast` needed here?
                               noexcept(static_cast<_Tp>(declval<_Arg>()))> {};
Run Code Online (Sandbox Code Playgroud)

eca*_*mur 12

如果发明的变量声明,则类型不能从参数列表构造

T t(declval<Args>()...);
Run Code Online (Sandbox Code Playgroud)

将是格式良好的,并且不会抛出异常。在复数参数情况下,这等效于(模 noexcept 可破坏性,参见LWG 2116类型转换表达式的格式良好和不抛出

T(declval<Args>()...)
Run Code Online (Sandbox Code Playgroud)

然而,在单参数情况下,表达式T(declval<Args>())被视为一个cast-expression,它可以调用const_castandreinterpret_cast ; 显式使用static_cast恢复了声明形式的等效性。

作为一个具体的例子,考虑以下类型:

struct D;
struct B { operator D&&() const; };
struct D : B {};
Run Code Online (Sandbox Code Playgroud)

这里static_castfrom B consttoD&&必须使用转换运算符,但强制转换表达式可以绕过转换运算符,因此 noexcept 也是如此。因此,省略static_cast将给出错误的结果is_nothrow_constructible<D&&, B const>