c++ - 比较任意类型的整数

  显示原文与译文双语对照的内容
0 0

什么是完全类型安全且最灵活的( 根据 constexpr通常unexpected ( ) 方法,用于比较两个整数的两个不同) 类型?

时间:原作者:7个回答

0 0

我有个建议: 我们需要使用" 常见算术转换" :

  • 如果两个类型是unsigned,只是比较。

  • 如果这两种类型都是有符号的,只是比较。

  • 如果signedness不同和有符号的值为负数,我们就完了

  • 实际工作应用其中两个值都为非负数,使用各种signedness 。 当无符号值大于最大有符号signed类型的值,我们就完了 否则,可以将无符号值转换为有符号类型,而不更改值和比较的。

下面是一个尝试:

#include <type_traits>
#include <limits>
template <bool SameSignedness> struct IntComparerImpl;
template <typename T, typename U>
constexpr bool IntCompare(T x, U y)
{
    return IntComparerImpl<std::is_signed<T>::value ==
                           std::is_signed<U>::value>::compare(x, y);
}
// same signedness case:
template <> struct IntComparerImpl<true>
{
    template<typename T, typename U>
    static constexpr bool compare(T t, U u)
    {
        return t < u;
    } 
};
// different signedness case:
template <> struct IntComparerImpl<false>
{
    // I1 is signed, I2 is unsigned
    template <typename I1, typename I2>
    static constexpr typename std::enable_if<std::is_signed<I1>::value, bool>::type
    compare(I1 x, I2 y)
    {
        return x < 0
            || y > std::numeric_limits<I1>::max()
            || x < static_cast<I1>(y);
    }
    // I1 is unsigned, I2 is signed
    template <typename I1, typename I2>
    static typename std::enable_if<std::is_signed<I2>::value, bool>::type
    compare(I1 x, I2 y)
    {
        return !(y < 0)
            || !(x > std::numeric_limits<I2>::max())
            || static_cast<I2>(y) < x;
    }
};
原作者:
0 0

My自己的解决方案这是( 基于 N3485 。pdf §5 ) :

#include <type_traits>
#include <limits>
#include <utility>
#include <cstdint>
#include <cstdlib>
template< typename L, typename R >
inline constexpr
typename std::enable_if< (std::is_signed< L >::value && !std::is_signed< R >::value), bool >::type
less(L const & lhs, R const & rhs)
{
    static_assert(std::is_integral< L >::value,
                  "lhs value must be of integral type");
    static_assert(std::is_integral< R >::value,
                  "rhs value must be of integral type");
    using T = typename std::common_type< L, R >::type;
    return (lhs < static_cast< L >(0)) || (static_cast< T const & >(lhs) < static_cast< T const & >(rhs));
}
template< typename L, typename R >
inline constexpr
typename std::enable_if< (!std::is_signed< L >::value && std::is_signed< R >::value), bool >::type
less(L const & lhs, R const & rhs)
{
    static_assert(std::is_integral< L >::value,
                  "lhs value must be of integral type");
    static_assert(std::is_integral< R >::value,
                  "rhs value must be of integral type");
    using T = typename std::common_type< L, R >::type;
    return !(rhs < static_cast< R >(0)) && (static_cast< T const & >(lhs) < static_cast< T const & >(rhs));
}
template< typename L, typename R >
inline constexpr
typename std::enable_if< (std::is_signed< L >::value == std::is_signed< R >::value), bool >::type
less(L const & lhs, R const & rhs)
{
    static_assert(std::is_integral< L >::value,
                  "lhs value must be of integral type");
    static_assert(std::is_integral< R >::value,
                  "rhs value must be of integral type");
    return lhs < rhs;
}
namespace
{
static_assert(less(1, 2), "0");
static_assert(less(-1, std::numeric_limits< std::uintmax_t >::max()), "1");
static_assert(less< std::int8_t, std::uintmax_t >(-1, std::numeric_limits< std::uintmax_t >::max()), "2");
static_assert(less< std::intmax_t, std::uint8_t >(-1, std::numeric_limits< std::uint8_t >::max()), "3");
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
static_assert(!(-1 < std::numeric_limits< unsigned long >::max()), "4");
#pragma GCC diagnostic pop
static_assert(less(-1, std::numeric_limits< unsigned long >::max()), "5");
}
int main()
{
        return EXIT_SUCCESS;
}
原作者:
...