c++ 是否有等效的 boost::numeric_cast<DestType>(SourceType)?

问题描述 投票:0回答:2

我正在编写一堆应用数学/信号处理/算法 C++ 代码。

我启用了

-Wconversion
编译器警告来捕获诸如运行时将
double
类型的数字转换为
int32_t
类型的问题。

显然,在这些转换过程中我总是很担心,因为:

  • 数字小数值丢失
  • 可能的正溢出或负溢出(“正溢出”是指 double 的值大于 INT32_MAX 并尝试将该值存储在目标类型中(在本例中为
    int32_t
    ))

每当我担心这样的转换时,我通常会使用单行检查:

boost::numeric_cast<DestType>(SourceType)

但是我想在没有

boost
的情况下做同样的事情。

直接 C++ 是否有等效的

boost::numeric_cast<DestType>(SourceType)

如果直接 C++ 没有等效项,那么可比较的非

boost
实现是什么?

我认为有点类似的检查基本上是一个模板函数,它有一个 if 语句来检查输入参数是否存在正溢出或负溢出(通过使用

std::numeric_limits<DestType>
::max()
::min()
并抛出异常)。

c++ templates boost floating-point integer-overflow
2个回答
3
投票

正如 @SergeyA 所说,标准 C++ 规范目前没有相当于 Boost 的

boost::numeric_cast<typename Destination>(Source value)

这是一个仅使用标准 C++ 的直接实现:

template<typename Dst, typename Src>
inline Dst numeric_cast(Src value)
{
    typedef std::numeric_limits<Dst> DstLim;
    typedef std::numeric_limits<Src> SrcLim;

    const bool positive_overflow_possible = DstLim::max() < SrcLim::max();
    const bool negative_overflow_possible =
            SrcLim::is_signed
            or
            (DstLim::lowest() > SrcLim::lowest());

    // unsigned <-- unsigned
    if((not DstLim::is_signed) and (not SrcLim::is_signed)) {
        if(positive_overflow_possible and (value > DstLim::max())) {
            throw std::overflow_error(__PRETTY_FUNCTION__ +
                                      std::string(": positive overflow"));
        }
    }
    // unsigned <-- signed
    else if((not DstLim::is_signed) and SrcLim::is_signed) {
        if(positive_overflow_possible and (value > DstLim::max())) {
            throw std::overflow_error(__PRETTY_FUNCTION__ +
                                      std::string(": positive overflow"));
        }
        else if(negative_overflow_possible and (value < 0)) {
            throw std::overflow_error(__PRETTY_FUNCTION__ +
                                      std::string(": negative overflow"));
        }

    }
    // signed <-- unsigned
    else if(DstLim::is_signed and (not SrcLim::is_signed)) {
        if(positive_overflow_possible and (value > DstLim::max())) {
            throw std::overflow_error(__PRETTY_FUNCTION__ +
                                      std::string(": positive overflow"));
        }
    }
    // signed <-- signed
    else if(DstLim::is_signed and SrcLim::is_signed) {
        if(positive_overflow_possible and (value > DstLim::max())) {
            throw std::overflow_error(__PRETTY_FUNCTION__ +
                                      std::string(": positive overflow"));
        } else if(negative_overflow_possible and (value < DstLim::lowest())) {
            throw std::overflow_error(__PRETTY_FUNCTION__ +
                                      std::string(": negative overflow"));
        }
    }

    // limits have been checked, therefore safe to cast
    return static_cast<Dst>(value);
} 

备注:

  • 编译器是g++版本4.8.5。
  • 编译器标志:
    • -std=c++0x
    • -O0
    • -g3
    • -迂腐
    • -迂腐的错误
    • -墙
    • -Wextra
    • -错误
    • -W转换
    • -c
    • -f消息长度=0
    • -Wsign-转换
    • -fPIC
    • -MMD
    • -MP
  • 对于浮点类型,您不能使用
    std::numeric_limits<float>::min()
    ,而必须使用
    std::numeric_limits<Dst>::lowest()
    ,因为
    ::min
    返回的是 1e-38 而不是负浮点值
  • 很多
    std::numeric_limits
    都是 const 表达式,因此编译器将能够在编译时大大简化它(即 N 个 if 语句将在编译时减少为一个 if 语句或没有)

0
投票

没有直接模拟,但您可以使用 C++20 中的

std::in_range

轻松更改范围
if constexpr (std::in_range<Dst>(value)) {
    // ...
} else {
    throw std::overflow_error(__PRETTY_FUNCTION__ ": out of range");
}

还有intcmp可以自己做比较

if constexpr (std::cmp_greater(val, std::numeric_limits<char>::max()))
{
    throw std::overflow_error(__PRETTY_FUNCTION__ ": overflow");
}
else if constexpr (std::cmp_less(val, std::numeric_limits<char>::min()))
{
    throw std::overflow_error(__PRETTY_FUNCTION__ ": underflow");
}
else
{
    // ...
}
© www.soinside.com 2019 - 2024. All rights reserved.