Using boost::numeric_cast<>

后端 未结 3 382
盖世英雄少女心
盖世英雄少女心 2021-01-08 00:11

When I want to convert between different integer types, it seems the best syntax is to use boost::numeric_cast<>():

int y = 99999;
short x         


        
3条回答
  •  孤街浪徒
    2021-01-08 00:43

    If you're okay with C++17 but don't want your casting algorithm throwing exceptions internally, you can use std::clamp with a bit of wrapping to handle out-of-bounds values.

    template 
    constexpr TTo clamp_cast(const TFrom& src) noexcept
    {
        using to_limits   = std::numeric_limits;
        using larger_type = std::conditional_t<(sizeof(TFrom) < sizeof(TTo)), TTo, TFrom>;
    
        if constexpr (std::is_same_v)
        {
            // don't bother if it is the same type
            return src;
        }
        else if constexpr (std::is_unsigned_v)
        {
            // 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)
        {
            // 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())
                                 )
                      );
        }
    }
    

    Usage is basically what you'd expect:

    static_assert(uint16_t(213)   == clamp_cast(213));
    static_assert(uint16_t(65535) == clamp_cast(9872431));
    static_assert(uint16_t(0)     == clamp_cast(-98721));
    

提交回复
热议问题