c++ - 理解 gsl::narrow 实现
问题描述
C++ 核心指南有一个narrow
转换,如果转换更改了值,则抛出该转换。查看该库的microsoft 实现:
// narrow() : a checked version of narrow_cast() that throws if the cast changed the value
template <class T, class U>
T narrow(U u) noexcept(false)
{
T t = narrow_cast<T>(u);
if (static_cast<U>(t) != u)
gsl::details::throw_exception(narrowing_error());
if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{}))) // <-- ???
gsl::details::throw_exception(narrowing_error());
return t;
}
if
第二个没看懂 它检查什么特殊情况,为什么还static_cast<U>(t) != u
不够?
为了完整性:
narrow_cast
只是一个static_cast
:
// narrow_cast(): a searchable way to do narrowing casts of values
template <class T, class U>
constexpr T narrow_cast(U&& u) noexcept
{
return static_cast<T>(std::forward<U>(u));
}
details::is_same_signdess
它的广告是这样的:
template <class T, class U>
struct is_same_signedness
: public std::integral_constant<bool,
std::is_signed<T>::value == std::is_signed<U>::value>
{
};
解决方案
这是检查溢出。让我们看看
auto foo = narrow<int>(std::numeric_limits<unsigned int>::max())
T
将是int
并且U
将是unsigned int
。所以
T t = narrow_cast<T>(u);
将给予商店-1
。t
当你把它放回去时
if (static_cast<U>(t) != u)
将-1
转换回,std::numeric_limits<unsigned int>::max()
因此检查将通过。尽管std::numeric_limits<unsigned int>::max()
溢出int
并且是未定义的行为,但这不是有效的强制转换。那么我们继续
if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{})))
由于符号不同,我们评估
(t < T{}) != (u < U{})
这是
(-1 < 0) != (really_big_number < 0)
== true != false
== true
所以我们抛出一个异常。如果我们走得更远并回绕 using 以使其t
变为正数,那么第二次检查将通过,但第一次检查将失败,因为t
它将是正数,并且转换回源类型仍然是相同的正值,而不是等于它的原始值。
推荐阅读
- integromat - 在自定义 Integromat 应用程序中无需连接的即时触发
- reactjs - 为什么我的数据没有显示在反应表中
- angular - Angular:如何使用子路由主到详细视图并返回?
- javascript - 如何清理 expo (android/ios) 应用程序中的应用程序缓存
- html - 图像不向右浮动
- nginx - 在 Nginx 上设置 RTP
- javascript - 使用Javascript返回范围内数字的倍数
- robotframework - 由于 XML-RPC,消息不可见,因此将 robots.api.logger 调用重定向到文件
- azure - 从持久存储安装到 azure 多容器应用程序
- angular - 输入类型数字无法用数字管道格式化值