Как определить наименьший целочисленный тип данных, который может вместить число n?

Как получить наименьший тип, который будет хранить массив чисел, не превышающих заданное значение n? Текущее решение, которое я нашел, не работает в моем случае, возможно, потому что мое число не является константным. Вот код решения, который я нашел:

```cpp
template<unsigned long long Max>
struct RequiredBits
{
    enum {
        value =
        Max <= 0xff ? 8 :
        Max <= 0xffff ? 16 :
        Max <= 0xffffffff ? 32 :
        64
    };
};

template<int bits> struct SelectInteger_;
template<> struct SelectInteger_ <8> { typedef uint8_t type; };
template<> struct SelectInteger_<16> { typedef uint16_t type; };
template<> struct SelectInteger_<32> { typedef uint32_t type; };
template<> struct SelectInteger_<64> { typedef uint64_t type; };

template<unsigned long long Max>
struct SelectInteger : SelectInteger_<RequiredBits<Max>::value> {};
```

Моя проблема в том, что этот код не работает для моего случая, которым является число, не являющееся константой. Как я могу изменить этот код, чтобы он работал для неконстантного числа?
  • 23 ноября 2023 г. 14:00
Ответы на вопрос 3
Чтобы изменить код, чтобы он работал для неконстантного числа, вы можете использовать шаблонные параметры вместо константных значений. Вам потребуется перегрузить шаблон "SelectInteger" для неконстантного числа и передать его в качестве аргумента шаблона "RequiredBits". Вот пример кода:

```cpp
template<unsigned long long Max>
struct RequiredBits
{
    enum {
        value =
        Max <= static_cast<unsigned long long>(std::numeric_limits<uint8_t>::max()) ? 8 :
        Max <= static_cast<unsigned long long>(std::numeric_limits<uint16_t>::max()) ? 16 :
        Max <= static_cast<unsigned long long>(std::numeric_limits<uint32_t>::max()) ? 32 :
        64
    };
};

template<unsigned long long Max> struct SelectInteger_;

template<unsigned long long Max>
struct SelectInteger
{
    typedef typename SelectInteger_<RequiredBits<Max>::value>::type type;
};

template<>
struct SelectInteger<0>
{
    typedef uint8_t type; // наименьший тип, если Max = 0
};

template<>
struct SelectInteger_<8>
{
    typedef uint8_t type;
};

template<>
struct SelectInteger_<16>
{
    typedef uint16_t type;
};

template<>
struct SelectInteger_<32>
{
    typedef uint32_t type;
};

template<>
struct SelectInteger_<64>
{
    typedef uint64_t type;
};
```

Вы можете вызвать SelectInteger с неконстантным значением, например:

```cpp
unsigned long long n = 12345;
typedef SelectInteger<n>::type SmallestType; // SmallestType будет наименьшим типом, вмещающим число n
```

Теперь код должен работать для неконстантных чисел.
Совет: Выделите массив байт и кастуйте указатель к нужному типу, используя union. Убедитесь, что alignment массива соответствует требованиям (например, кратен 8 байтам), чтобы избежать замедления. 
 Если выделите массив байт и приведете указатель к нужному типу, используя union, то замедления не будет, при условии, что alignment массива соответствует требованиям (например, кратен 8 байтам).
Похожие вопросы