受Gsl::窄_投射的启发,我通过添加几个特性创建了自己的实现:
narrow_cast )#include <cassert>
#include <exception>
#include <iostream>
#include <type_traits>
namespace details {
template <typename T, typename U>
constexpr bool is_same_signedness = std::is_signed<T>::value == std::is_signed<U>::value;
template <typename T, typename U>
constexpr bool can_fully_represent =
std::is_same<T, U>::value ||
( std::is_integral<T>::value && std::is_integral<U>::value &&
( ( std::is_signed<T>::value && sizeof(T) > sizeof(U) ) ||
( is_same_signedness<T, U> && sizeof(T) >= sizeof(U) ) ) ) ||
( std::is_floating_point<T>::value && std::is_floating_point<U>::value && sizeof(T) >= sizeof(U) );
template <typename T, typename U>
constexpr bool static_cast_changes_value(U u) noexcept
{
const auto t = static_cast<T>(u);
// this should catch most cases, but may miss dodgy unsigned to signed conversion or vice-versa
if (static_cast<U>(t) != u)
return true;
if (std::is_signed<T>::value != std::is_signed<U>::value && ((t < T{}) != (u < U{})))
return true;
return false;
}
} // namespace details
// TODO: unchecked cast for types where some loss of precision (and therefore assertion failure) is expected?
template <typename T, typename U>
constexpr T narrow_cast(U&& u) noexcept
{
static_assert(!details::can_fully_represent<T, U>, "we shouldn't be using narrow_cast for casts that aren't actually narrowing");
assert(!details::static_cast_changes_value<T>(u));
return static_cast<T>(std::forward<U>(u));
}
struct narrowing_error : public std::exception {};
template <typename T, typename U>
constexpr T narrow_cast_checked(U u)
{
static_assert(!details::can_fully_represent<T, U>, "we shouldn't be using narrow_cast for casts that aren't actually narrowing");
if (details::static_cast_changes_value<T>(u))
throw narrowing_error();
return static_cast<T>(u);
}发布于 2019-10-20 09:42:12
我注意到的第一件事是:您只支持基本的算术类型(整数和浮点数)。这在narrow_cast这个名字中并不明显。要么使用静态断言强制执行,要么提供为用户定义类型提供扩展的机制。
以下是你所写的:
模板 constexpr bool can_fully_represent = std::is_same::value既要( std::is_integral::value && std::is_integral::value &)&(( std::is_signed::value &&SIZOF(T))> sizeof(U) )\x( is_same_signedness && sizeof(T) >= sizeof(U) )\x{e76f}\x{e76f}( std::is_floating_point::value & std::is_floating_point::value && sizeof(T) >= sizeof(U) );
以下是我认为应该足够的内容:
template <typename T, typename U>
constexpr bool can_fully_represent =
std::numeric_limits<T>::min() <= std::numeric_limits<U>::min()
&& std::numeric_limits<T>::max() >= std::numeric_limits<U>::max();好吧,也许我忽略了一些边缘案例,但这就是我的想法。
未检查的版本使用转发引用,而检查版本不使用。尽量保持界面的一致性。
std::is_same<T, U>::value可以简化为std::is_same_v<T, U>。
发布于 2021-12-03 20:55:25
除了@L.F.之外,S还回答说:您正在定义一个is_same_signedness值,但是--您没有在您的static_cast_changes_value()函数中使用它,尽管可以。
https://codereview.stackexchange.com/questions/230931
复制相似问题