C++是否有与boost::numeric_cast< DestType>(SourceType)等效的代码?

lokaqttq  于 2023-08-09  发布在  其他
关注(0)|答案(2)|浏览(117)

我正在做一堆应用数学/信号处理/算法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()并抛出异常)。

wqnecbli

wqnecbli1#

**正如@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
  • -Werror
    • W转换
  • -c
  • -fmessage-length=0
    • Wsign转换
  • -fPIC
  • -MMD
  • -MP
  • 对于浮点类型,不能使用std::numeric_limits<float>::min(),而必须使用std::numeric_limits<Dst>::lowest(),因为::min返回的是1 e-38而不是负浮点值
  • 许多std::numeric_limits是const表达式,因此编译器将能够在编译时大大简化它(即N个if语句将在编译时减少为一个if语句或没有)
jmo0nnb3

jmo0nnb32#

没有直接的模拟,但是你可以用C++20的std::in_range很容易地改变量程

if constexpr (std::in_range<Dst>(value)) {
    // ...
} else {
    throw std::range_error(__PRETTY_FUNCTION__ ": out of range");
}

字符串
还有std::cmp_* in intcmp可以自己做比较。请注意,std::in_rangestd::cmp_*只允许您检查范围,而不是检查值是否可以在目标类型中表示,例如,像9'007'199'254'740'993这样的大uint64_t值可以完全在double的范围内,但不能完全由double表示。如果需要,您需要手动检查

if constexpr (std::cmp_greater(val, std::numeric_limits<Dst>::max()))
{
    throw std::overflow_error(__PRETTY_FUNCTION__ ": overflow");
}
else if constexpr (std::cmp_less(val, std::numeric_limits<Dst>::min()))
{
    throw std::underflow_error(__PRETTY_FUNCTION__ ": underflow");
}
else
{
    auto value = static_cast<Dst>(val);
    if (value != val)
        throw std::domain_error("in-range value not representable in Dst");
    else
        // Do something with `value`
}

相关问题