首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >理解gsl::狭义实现

理解gsl::狭义实现
EN

Stack Overflow用户
提问于 2018-10-17 21:08:31
回答 2查看 6.6K关注 0票数 11

C++核心指南有一个narrow强制转换,如果转换更改值,它将抛出。查看库的microsoft实现

代码语言:javascript
复制
// 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

代码语言:javascript
复制
// 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就是它所宣传的:

代码语言:javascript
复制
template <class T, class U>
struct is_same_signedness
    : public std::integral_constant<bool,
        std::is_signed<T>::value == std::is_signed<U>::value>
{
};
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-10-17 21:28:29

这是检查溢出。让我们看看

代码语言:javascript
复制
auto foo = narrow<int>(std::numeric_limits<unsigned int>::max())

T将成为intU将成为unsigned int。所以

代码语言:javascript
复制
T t = narrow_cast<T>(u);

将给商店-1t。当你把它放回去的时候

代码语言:javascript
复制
if (static_cast<U>(t) != u)

-1将转换回std::numeric_limits<unsigned int>::max(),以便通过检查。但这不是一个有效的强制转换,因为std::numeric_limits<unsigned int>::max()溢出了一个int,并且是未定义的行为。所以我们继续讨论

代码语言:javascript
复制
if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{})))

既然迹象不一样,我们就会评估

代码语言:javascript
复制
(t < T{}) != (u < U{})

这就是

代码语言:javascript
复制
(-1 < 0) != (really_big_number < 0)
==  true != false
==  true

所以我们抛出一个例外。如果我们走得更远,使用t使其变为正数,那么第二次检查就会通过,但是第一次检查将失败,因为t将是正的,而返回到源类型的值仍然是与其原始值不相等的相同的正值。

票数 14
EN

Stack Overflow用户

发布于 2018-10-17 21:40:09

代码语言:javascript
复制
if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{})))  // <-- ???

上面的检查是为了确保不同的符号不会使我们误入歧途。

第一部分检查它是否可能是一个问题,并且包含在优化中,所以让我们来讨论一下。

例如,以UINT_MAX (有最大的unsigned int )为例,并将其转换为signed

假设INT_MAX == UINT_MAX / 2 (这很可能是标准所不能保证的),结果将是(signed)-1,或者只是-1,一个负数。

当将其转换回原来的值时,它将通过第一个检查,而它本身并不是相同的值,并且这个检查会捕获错误。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52863643

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档