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>
{
};发布于 2018-10-17 21:28:29
这是检查溢出。让我们看看
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所以我们抛出一个例外。如果我们走得更远,使用t使其变为正数,那么第二次检查就会通过,但是第一次检查将失败,因为t将是正的,而返回到源类型的值仍然是与其原始值不相等的相同的正值。
发布于 2018-10-17 21:40:09
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,一个负数。
当将其转换回原来的值时,它将通过第一个检查,而它本身并不是相同的值,并且这个检查会捕获错误。
https://stackoverflow.com/questions/52863643
复制相似问题