bol*_*lov 6 c++ casting narrowing c++11 cpp-core-guidelines
在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;
}
Run Code Online (Sandbox Code Playgroud)
我不明白第二个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));
}
Run Code Online (Sandbox Code Playgroud)
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>
{
};
Run Code Online (Sandbox Code Playgroud)
这正在检查溢出。让我们来看看
auto foo = narrow<int>(std::numeric_limits<unsigned int>::max())
Run Code Online (Sandbox Code Playgroud)
T将会int并且U将会unsigned int。所以
T t = narrow_cast<T>(u);
Run Code Online (Sandbox Code Playgroud)
将存放-1在t。当您将其投射回去时
if (static_cast<U>(t) != u)
Run Code Online (Sandbox Code Playgroud)
在-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{})))
Run Code Online (Sandbox Code Playgroud)
由于符号不同,我们评估
(t < T{}) != (u < U{})
Run Code Online (Sandbox Code Playgroud)
这是
(-1 < 0) != (really_big_number < 0)
== true != false
== true
Run Code Online (Sandbox Code Playgroud)
所以我们抛出一个异常。如果我们走得更远并回绕使用,以使它t成为正数,则第二次检查将通过,但是第一个检查将失败,因为t它将是正数,并且强制转换回源类型的正值仍然是相同的正值,这不是等于其原始值。
| 归档时间: |
|
| 查看次数: |
1399 次 |
| 最近记录: |