首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >缩小数值转换的显式转换

缩小数值转换的显式转换
EN

Code Review用户
提问于 2019-10-18 02:54:54
回答 2查看 645关注 0票数 10

Gsl::窄_投射的启发,我通过添加几个特性创建了自己的实现:

  • 类型上的静态断言,以确保强制转换实际上正在缩小(如果将来对代码的更改意味着转换不再缩小,我们不希望在那里仍然有一个narrow_cast )
  • 没有运行时检查的版本仍然有一个断言,所以它是在调试模式下签入的
代码语言:javascript
复制
#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);
}
EN

回答 2

Code Review用户

回答已采纳

发布于 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) );

以下是我认为应该足够的内容:

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

票数 4
EN

Code Review用户

发布于 2021-12-03 20:55:25

除了@L.F.之外,S还回答说:您正在定义一个is_same_signedness值,但是--您没有在您的static_cast_changes_value()函数中使用它,尽管可以。

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

https://codereview.stackexchange.com/questions/230931

复制
相关文章

相似问题

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