【问题标题】:How to express "the minimum integral type larger than T"?如何表示“大于 T 的最小整数类型”?
【发布时间】:2016-12-01 10:46:03
【问题描述】:

假设我有一个整数类型 T(有符号或无符号)。我想(在编译时)引用最小的整数类型(有符号或无符号),例如,std::numeric_limits<T>::max() 加 1(我的意思是在非溢出意义上)。

什么是一个很好的通用方法?

【问题讨论】:

  • ammm... 不是T的两倍大小的无符号整数类型吗?
  • @NathanOliver 我认为 OP 意味着所有类型中可以保持该值的最小的类型。即,如果您可以在 uint32_t 和 uint64_t 之间进行选择,请选择 uint32_t。
  • @Borgleader 这是有道理的。谢谢。
  • 如果T是无符号的(即std::numeric_limits<T>::min() == 0),那么它是T的两倍大小的有符号(或无符号)类型,否则,它是unsigned整数类型与T 大小相同
  • @NathanOliver:错字;我的意思是“最小的”。

标签: c++ templates generic-programming idioms


【解决方案1】:

对于无符号类型,这可以解决问题:

template <typename T>
constexpr unsigned size_in_bits() { return  sizeof(T) * CHAR_BIT; }

template <typename T>
using smallest_larger_uint_t = 
    typename boost::uint_t<size_in_bits<T>() + 1>::least;

如果我们想让某些东西适用于任何整数类型:

template <typename T, int NumBits>
using boost_integer_type = 
    typename std::conditional<
        std::is_unsigned<T>::value,
        boost::uint_t<NumBits>, 
        boost::int_t<NumBits>
    >::type;

template <typename T>
constexpr unsigned size_in_bits() { return sizeof(T) * CHAR_BIT; }

template <typename T>
using smallest_larger_integral_t = 
    typename boost_integer_type<T, size_in_bits<T>() + 1>::least;

有关int_t&lt;N&gt;uint_t&lt;N&gt; 的详细信息,请参阅documentation for Boost.Integer

【讨论】:

    【解决方案2】:

    如果您希望某些东西在每种整数类型上都能正常工作,您可以将其嵌入到通过几个步骤构建的特征中。我们首先将整数类型映射到它们的位大小:

    #define CREATE_SIGNED_META_OBJ(x) template <>\
        struct signed_integer_type<x> {\
            typedef int##x##_t type;\
        };
    
    #define CREATE_UNSIGNED_META_OBJ(x) template <>\
        struct unsigned_integer_type<x> {\
            typedef uint##x##_t type;\
        };
    
    template <std::size_t length>
    struct signed_integer_type;
    
    template <std::size_t len>
    struct unsigned_integer_type;
    
    CREATE_SIGNED_META_OBJ(8)
    CREATE_SIGNED_META_OBJ(16)
    CREATE_SIGNED_META_OBJ(32)
    CREATE_SIGNED_META_OBJ(64)
    
    CREATE_UNSIGNED_META_OBJ(8)
    CREATE_UNSIGNED_META_OBJ(16)
    CREATE_UNSIGNED_META_OBJ(32)
    CREATE_UNSIGNED_META_OBJ(64)
    

    然后,可以构建特征本身。我们想将我们的二分法应用于断言std::numeric_limits&lt;Int&gt;::min() == 0...

    template <typename Int, bool>
    struct get_smallest_for_max_plus_one;
    
    template <typename Int>
    struct get_smallest_for_max_plus_one<Int, true> {
        typedef typename signed_integer_type<2*sizeof(Int)*8>::type type;
    };
    
    template <typename Int>
    struct get_smallest_for_max_plus_one<Int, false> {
        typedef typename unsigned_integer_type<sizeof(Int)*8>::type type;
    };
    
    template <typename Int>
    using get_fittest_int_type = get_smallest_for_max_plus_one<Int, std::numeric_limits<Int>::min() == 0>;
    

    现在我们可以直接将get_fittest_int_type 与任何整数一起使用...运行示例可以在Coliru 上找到。

    不过,为了保持一致性,我想您想保留 signedunsigned 属性...如果是这种情况,您可以将 get_smallest_for_max_plus_one 的特化替换为以下内容:

    // Unsigned type, we want to get the smallest unsigned type that can hold max + 1
    template <typename Int>
    struct get_smallest_for_max_plus_one<Int, true> {
        typedef typename unsigned_integer_type<2*sizeof(Int)*8>::type type;
    };
    
    // Signed type, we want the smallest signed type that can hold max + 1
    template <typename Int>
    struct get_smallest_for_max_plus_one<Int, false> {
        typedef typename signed_integer_type<2*sizeof(Int)*8>::type type;
    };
    

    【讨论】:

    • ...但是 C++ 标准真的保证不能有大小为 3 或 6 的整数类型吗?
    • @einpoklum 你的怀疑对我来说似乎是合法的,我没有检查这个事实。我只是提供了一个常见整数类型的最小示例。在这方面,您基于 boost 的解决方案似乎更加通用!
    【解决方案3】:

    您可以按所需大小指定整数并进行相应选择:

    #include <cstdint>
    
    namespace Detail {
        template <std::size_t> struct integer_of_size_undefined {};
        template <> struct integer_of_size_undefined<sizeof(int8_t)> {
            typedef int8_t type;
        };
        template <> struct integer_of_size_undefined<sizeof(int16_t)> {
            typedef int16_t type;
        };
        template <> struct integer_of_size_undefined<sizeof(int32_t)> {
            typedef int32_t type;
        };
        template <> struct integer_of_size_undefined<sizeof(int64_t)> {
            typedef int64_t type;
        };
    
        template <std::size_t> struct unsigned_integer_of_size_undefined {};
        template <> struct unsigned_integer_of_size_undefined<sizeof(int8_t)> {
            typedef uint8_t type;
        };
        template <> struct unsigned_integer_of_size_undefined<sizeof(int16_t)> {
            typedef uint16_t type;
        };
        template <> struct unsigned_integer_of_size_undefined<sizeof(int32_t)> {
            typedef uint32_t type;
        };
        template <> struct unsigned_integer_of_size_undefined<sizeof(int64_t)> {
            typedef uint64_t type;
        };
    }
    
    template <std::size_t N>
    struct integer_of_size {
        typedef typename Detail::integer_of_size_undefined<N>::type type;
    };
    
    template <std::size_t N>
    struct unsigned_integer_of_size {
        typedef typename Detail::unsigned_integer_of_size_undefined<N>::type type;
    };
    
    
    #include <type_traits>
    
    template <typename T>
    struct next_integer {
        typedef typename std::conditional<std::is_signed<T>::value,
            typename std::make_unsigned<T>::type,
            typename integer_of_size<2*sizeof(T)>::type>::type
            type;
    };
    
    int main ()
    {
        static_assert(std::is_same<next_integer<std::int16_t>::type, uint16_t>::value,
            "Should be a unsigned 16 bit");
        static_assert(std::is_same<next_integer<std::uint16_t>::type, int32_t>::value,
            "Should be a signed 32 bit");
    
        return 0;
    }
    

    【讨论】:

    • 标准是否保证不能有大小为 3 或 6 的整数类型?
    • ... 在这种情况下,我不希望 my 代码成为做出该假设的代码,我宁愿依赖标准库中已经表达的内容(或至多 Boost,如我的回答)对于这些知识......
    【解决方案4】:

    你可以这样做,使用来自cstdint的类型:

    template <typename T>
    struct next_type {
        typedef error_type type;
    };
    
    template <>
    struct next_type<std::int32_t> {
        typedef std::uint32_t type;
    }
    
    template <>
    struct next_type<std::uint32_t> {
        typedef std::int64_t type;
    }
    
    // Add more...
    

    为每种类型添加专业化。然后使用它:

    typename next_type<T>::type
    

    因此,如果您已经使用了最大可能的类型,那么您将获得error_type,您必须以某种方式自己定义它是什么,否则它需要专门化。

    使用cstdint 中的_least 类型可能会更好,例如std::int_least32_t 转到std::uint_least32_t

    【讨论】:

    • 但是你怎么知道哪个类型更大呢?例如,不能保证 int 的最大值大于 unsigned short
    • 我认为使用 中的类型应该注意这一点,否则你是对的。
    • 甚至可能使用其中的 _least 类型,例如 int_least8_t 到 uint_least8t
    • 是的,您必须将其限制为固定宽度类型。
    • @Byteventurer:我认为 Boost 已经为我完成了大部分工作,请看我的回答...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-06
    • 2021-05-06
    • 2013-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-17
    相关资源
    最近更新 更多