如何在编译时找出可以表示数字的最小整数类型

时间:2012-08-22 23:03:46

标签: c++ templates c++11 typetraits

我需要在编译时找出可以表示特定数字的最小无符号整数类型。像这样......

//////////////////////////////////////////////////////////////////////////
template<size_t Bits>
struct uint_least{};

template<>
struct uint_least<8>{ typedef std::uint8_t type; };

template<>
struct uint_least<16>{ typedef std::uint16_t type; };

//////////////////////////////////////////////////////////////////////////
template<size_t max>
struct uint_least_bits
{
    static const size_t value = 14; // just a placeholder
};

//////////////////////////////////////////////////////////////////////////
template<size_t max>
class A
{
    typedef typename uint_least<uint_least_bits<max>::value>::type underlying_type;

    underlying_type m_X;
};

uint_least旨在为您提供至少Bits大的最小无符号整数类型,它应该适用于任何高达64的值(不仅仅是8,16,32,64而且还可以1,4,13等)。

uint_least_bits旨在为您提供表示max所需的最少位数。

  • 如何实施uint_least
  • 如何实施uint_least_bits
  • bitsminmax应该是哪种类型?如果答案是模板类型,我该如何防范无效输入?

特征的确切结构无关紧要。随意废弃我提供的东西。我只需要提供一个数字并找回可以容纳它的最小无符号整数类型。

2 个答案:

答案 0 :(得分:8)

我昨天做了这件事,真是巧合。我会把它留在这里,即使它不是完全你需要的东西(无论如何它修复了最好的整体类型的东西):

#include <type_traits>
#include <stdint.h>

template<size_t i>
struct best_type {
    typedef typename std::conditional<
        (i <= 8),
        uint8_t,
        typename std::conditional<
            (i <= 16),
            uint16_t,
            typename std::conditional<
                (i <= 32),
                uint32_t,
                uint64_t
            >::type
        >::type
    >::type type;
};

然后,你会像这样使用它:

#include <type_traits>
#include <iostream>
#include <stdint.h>

template<size_t i>
struct best_type {
    typedef typename std::conditional<
        (i <= 8),
        uint8_t,
        typename std::conditional<
            (i <= 16),
            uint16_t,
            typename std::conditional<
                (i <= 32),
                uint32_t,
                uint64_t
            >::type
        >::type
    >::type type;
};   

int main() {
    std::cout << sizeof(best_type<2>::type) << std::endl;
    std::cout << sizeof(best_type<8>::type) << std::endl;
    std::cout << sizeof(best_type<15>::type) << std::endl;
    std::cout << sizeof(best_type<17>::type) << std::endl;
}

现场演示,here

答案 1 :(得分:4)

如果你有constexpr,这将有效:

#include <climits>
#include <cstdint>
#include <cstddef>

inline
constexpr
unsigned
clz(unsigned x)
{
    return x == 0 ? sizeof(x)*CHAR_BIT : x & 0x80000000 ? 0 : 1 + clz(x << 1);
}

inline
constexpr
unsigned
clp2(unsigned x)
{
    return x == 0 ? 0 : 1 << (sizeof(x)*CHAR_BIT - clz(x-1));
}

inline
constexpr
unsigned
at_least8(unsigned x)
{
    return x < 8 ? 8 : x;
}

template<size_t Bits>
struct uint_least{};

template<>
struct uint_least<8>{ typedef std::uint8_t type; };

template<>
struct uint_least<16>{ typedef std::uint16_t type; };

template<>
struct uint_least<32>{ typedef std::uint32_t type; };

template<>
struct uint_least<64>{ typedef std::uint64_t type; };

template<size_t max>
struct uint_least_bits
{
    static const size_t value = clp2(max);
};

template<size_t max>
class A
{
    typedef typename uint_least<at_least8(uint_least_bits<max>::value)>::type underlying_type;

    underlying_type m_X;
};

int main()
{
    A<3> a;
}

如果你没有constexpr,你可以将clp2翻译成模板元函数(这留给读者作为练习: - ))。

哦,免责声明:假设32位unsigned。如果需要,这也可以概括。