首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用boost::numeric_cast<>

使用boost::numeric_cast<>
EN

Stack Overflow用户
提问于 2010-12-13 05:34:56
回答 3查看 7.4K关注 0票数 15

当我想在不同的整数类型之间进行转换时,似乎最好的语法是使用boost::numeric_cast<>()

代码语言:javascript
复制
int y = 99999;
short x = boost::numeric_cast<short>(y); // will throw an exception if y is too large

我从来没有用过它;但是它的语法非常简单,所以一切都很好。

现在假设我想做一些更高级的事情:我希望它返回目标类型(饱和度)的最小或最大值,而不是抛出异常。我想不出一种方式来表达这一点,但documentation建议(可能使用RawConverter策略)。我能想到的就是下面这些难看的东西:

代码语言:javascript
复制
short x = numeric_cast<short>(max(min(y, SHORT_MAX), SHORT_MIN);

那么,如何使用boost的numeric_cast来表示“饱和类型转换”呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-12-13 05:41:47

您可能会这样做:

代码语言:javascript
复制
#include <limits>

template<typename Target, typename Source>
Target saturation_cast(Source src) {
   try {
      return boost::numeric_cast<Target>(src);
   }
   catch (const boost::negative_overflow &e) {
      return std::numeric_limits<Target>::lowest();
      /* Or, before C++11:
      if (std::numeric_limits<Target>::is_integer)
         return std::numeric_limits<Target>::min();
      else
         return -std::numeric_limits<Target>::max();
      */
   }
   catch (const boost::positive_overflow &e) {
      return std::numeric_limits<Target>::max();
   }
}

(对于支持它的类型,错误情况也可能返回-inf/+inf)。

这样,您可以让Boost的numeric_cast确定该值是否越界,然后可以做出相应的反应。

票数 15
EN

Stack Overflow用户

发布于 2010-12-13 05:41:38

嗯..。如果上面的方法行得通,一般的解决方案可能是这样:

代码语言:javascript
复制
template<typename TypeFrom, typename TypeTo>
TypeTo saturated_cast(TypeFrom value) {
    TypeTo valueMin = std::numeric_limits<TypeTo>::min();
    TypeTo valueMax = std::numeric_limits<TypeTo>::max();
    return boost::numeric_cast<TypeTo>( std::max(std::min(value,valueMax),valueMin) );
}

希望我没记错..。无论如何,您已经了解了以下概念:)

……顺便说一下:我认为你可以在这里使用static_cast,因为在执行限制之后,你不能再溢出范围,所以你不需要额外的numeric_cast检查。

票数 1
EN

Stack Overflow用户

发布于 2019-09-25 13:44:29

如果您对C++17没有意见,但又不希望强制转换算法在内部抛出异常,那么您可以使用带有一些包装的std::clamp来处理越界的值。

代码语言:javascript
复制
template <typename TTo, typename TFrom>
constexpr TTo clamp_cast(const TFrom& src) noexcept
{
    using to_limits   = std::numeric_limits<TTo>;
    using larger_type = std::conditional_t<(sizeof(TFrom) < sizeof(TTo)), TTo, TFrom>;

    if constexpr (std::is_same_v<TTo, TFrom>)
    {
        // don't bother if it is the same type
        return src;
    }
    else if constexpr (std::is_unsigned_v<TFrom>)
    {
        // if source is unsigned, we only need to worry about upper bound
        return TTo(std::min(larger_type(src), larger_type(to_limits::max())));
    }
    else if constexpr (std::is_unsigned_v<TTo>)
    {
        // source is signed, but destination is not
        if (src < TFrom(0))
            return TTo(0);
        else
            return TTo(std::min(larger_type(src), larger_type(to_limits::max())));
    }
    else
    {
        // both are signed -- use regular clamping rules
        return TTo(std::clamp(larger_type(src),
                              larger_type(to_limits::min()),
                              larger_type(to_limits::max())
                             )
                  );
    }
}

使用率基本上是您所期望的:

代码语言:javascript
复制
static_assert(uint16_t(213)   == clamp_cast<uint16_t>(213));
static_assert(uint16_t(65535) == clamp_cast<uint16_t>(9872431));
static_assert(uint16_t(0)     == clamp_cast<uint16_t>(-98721));
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4424168

复制
相关文章

相似问题

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