为什么在 gcc 的 is_nothrow_constructible 实现中需要 static_cast?
Why is static_cast needed in the gcc's implementation of is_nothrow_constructible?
摘自 type_traits
的 GCC 实现,为什么这里需要 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>()))> {};
如果发明的变量声明
,则类型不可从参数列表中构造
T t(declval<Args>()...);
将是 well-formed and is known not to throw exceptions. In the plural argument case this is equivalent (modulo noexcept destructibility, see LWG 2116) to the well-formedness and nothrow of the type conversion expression
T(declval<Args>()...)
然而,在单参数情况下,表达式 T(declval<Args>())
被视为 cast-expression, which can invoke const_cast
and reinterpret_cast
; static_cast
的显式使用恢复了声明形式的等价性。
作为 concrete example,考虑以下类型:
struct D;
struct B { operator D&&() const; };
struct D : B {};
这里从B const
到D&&
的static_cast
必须使用转换运算符,但是强制转换表达式可以绕过转换运算符,noexcept也是如此。所以省略 static_cast
会给 is_nothrow_constructible<D&&, B const>
.
错误的结果
摘自 type_traits
的 GCC 实现,为什么这里需要 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>()))> {};
如果发明的变量声明
,则类型不可从参数列表中构造T t(declval<Args>()...);
将是 well-formed and is known not to throw exceptions. In the plural argument case this is equivalent (modulo noexcept destructibility, see LWG 2116) to the well-formedness and nothrow of the type conversion expression
T(declval<Args>()...)
然而,在单参数情况下,表达式 T(declval<Args>())
被视为 cast-expression, which can invoke const_cast
and reinterpret_cast
; static_cast
的显式使用恢复了声明形式的等价性。
作为 concrete example,考虑以下类型:
struct D;
struct B { operator D&&() const; };
struct D : B {};
这里从B const
到D&&
的static_cast
必须使用转换运算符,但是强制转换表达式可以绕过转换运算符,noexcept也是如此。所以省略 static_cast
会给 is_nothrow_constructible<D&&, B const>
.