【问题标题】:does c++ have an equivalent boost::numeric_cast<DestType>(SourceType)?c++ 是否有等效的 boost::numeric_cast<DestType>(SourceType)?
【发布时间】:2018-09-14 10:32:16
【问题描述】:

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

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

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

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

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

boost::numeric_cast<DestType>(SourceType)

但是我想在没有boost 的情况下做同样的事情。

直接的 C++ 是否有等价的 boost::numeric_cast&lt;DestType&gt;(SourceType)?

如果直接的 C++ 没有等价物,那么什么是可比较的非boost 实现?

我认为有点可比的检查基本上是一个模板函数,它有一个 if 语句来检查输入参数的正或负溢出(通过使用 std::numeric_limits&lt;DestType&gt; ::max() 和 ::min() 并引发异常)。

【问题讨论】:

  • 不,标准库中没有数字转换。至于非 boost 实现,boost 是开源的,你可以从 boost 中获取实现并按原样使用。
  • 当然,如果您确实从 boost 中获取实现并像 @SergeyA 建议的那样使用它,您仍然需要遵守 Boost 使用的开源许可证。
  • @SergeyA 我检查了 Boost 的实现,不幸的是它不像复制头文件那么简单。

标签: c++ templates boost floating-point integer-overflow


【解决方案1】:

As @SergeyA stated,不,标准 C++ 规范目前没有等效于 Boost 的 boost::numeric_cast&lt;typename Destination&gt;(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
    • -迂腐
    • -pedantic-错误
    • -墙
    • -Wextra
    • -错误
    • -W转换
    • -c
    • -fmessage-length=0
    • -Wsign-转换
    • -fPIC
    • -MMD
    • -MP
  • 对于浮点类型,您不能使用 std::numeric_limits&lt;float&gt;::min(),而是必须使用 std::numeric_limits&lt;Dst&gt;::lowest(),因为 ::min 返回的是 1e-38 而不是负浮点值
  • 很多 std::numeric_limits 是 const 表达式,因此编译器将能够在编译时大大简化这一点(即 N 个 if 语句将在编译时减少为一个 if 语句或没有)

【讨论】:

  • 如前所述,这在 g++ 中使用 -Wconversion 进行编译,但在 clang 中没有。见godbolt.org/z/MMaFny
  • 另外g++ > 4.8.5由于-Wsign-compare添加了-Wall也可以警告。
  • 不应该negative_overflow_possible 只是std::numeric_limits&lt;Dst&gt;::lowest() &gt; std::numeric_limits&lt;Src&gt;::lowest()?我不明白需要 std::numeric_limits&lt;Src&gt;::is_signed or 部分。
  • 我认为你的意思是 and 不是 or,所以negative_overflow_possible = std::numeric_limits&lt;Src&gt;::is_signed and ... 我认为std::numeric_limits&lt;Src&gt;::is_signed and 部分是为了短路评估以下std::numeric_limits&lt;Dst&gt;::lowest() &gt; std::numeric_limits&lt;Src&gt;::lowest() 表达式。
  • 除非我错过了什么,我还注意到四个外部 if..else if 子句是多余的。逻辑可以大大简化。
猜你喜欢
  • 2012-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-30
  • 2017-01-01
  • 2023-03-30
  • 1970-01-01
相关资源
最近更新 更多