Шаблон: Как выбрать наименьший тип int, который содержит n бит? - PullRequest
0 голосов
/ 11 декабря 2018

Для собственной реализации std::bitset (std запрещено) я использовал uint_fast32_t, поскольку он быстрее на 64-битных процессорах.Замечание было сделано для экономии места для небольших наборов, например, битовый набор <6> не должен использовать 8 байтов.Трата еще больше, если вы рассматриваете выравнивание в структуре.

Использовать C ++ 11 хорошо.Я хотел бы элегантно выбрать:

  • Размер <= 8: uint8_t </li>
  • Размер <= 16: uint16_t </li>
  • Размер <= 32: uint32_t </li>
  • Размер> 32: uint_fast32_t

в качестве типа хранилища в моем классе:

template<size_t Size>
struct BitSet {
    typedef <expression> StorageType;
    // an array of that storage type...
};

Я могу просто подумать о довольно неуклюжих вспомогательных шаблонах, но, возможно, есть что-то более элегантное вC ++ 11.

Редактировать: уточнить: uint_fast8_t подойдет для исходного класса, компилятор может выбрать все, что быстро.Представьте себе размер == 1000000.Но на некоторых машинах он будет 64-битным, и когда размер имеет значение в некоторых случаях использования, например, размер == 4, это означает, что будет потрачено 7 байтов.

Ответы [ 4 ]

0 голосов
/ 11 декабря 2018

Подробное решение с меньшим количеством волшебства.Ссылка: https://gcc.godbolt.org/z/P2AGZ8

#include<cstdint>

namespace helper { namespace internal {

enum class Size {
    Uint8,
    Uint16,
    Uint32,
    UintFast32,
};

constexpr Size get_size(int s) {
    return (s <= 8 ) ? Size::Uint8:
           (s <= 16) ? Size::Uint16:
           (s <= 32) ? Size::Uint32: Size::UintFast32;
}

template<Size s>
struct FindTypeH;

template<>
struct FindTypeH<Size::Uint8> {
    using Type = std::uint8_t;
};

template<>
struct FindTypeH<Size::Uint16> {
    using Type = std::uint16_t;
};

template<>
struct FindTypeH<Size::Uint32> {
    using Type = std::uint32_t;
};

template<>
struct FindTypeH<Size::UintFast32> {
    using Type = std::uint_fast32_t;
};
}

template<int S>
struct FindType {
    using Type = typename internal::FindTypeH<internal::get_size(S)>::Type;
};
}

template<int S>
struct Myclass {
    using Type = typename helper::FindType<S>::Type;
};
0 голосов
/ 11 декабря 2018

С помощником

namespace detail {

    template <int overload>
    struct StorageType;

    template <>
    struct StorageType<0>{ using type = uint8_t; };

    template <>
    struct StorageType<1>{ using type = uint16_t; };

    template <>
    struct StorageType<2>{ using type = uint32_t; };

    template <>
    struct StorageType<3>{ using type = uint_fast32_t; };
}

Затем мы можем сложить constexpr логические значения

template<size_t Size>
struct BitSet {
    typedef typename detail::StorageType<(Size > 8) + (Size > 16) + (Size > 32)>::type StorageType;
    // an array of that storage type...
};
0 голосов
/ 11 декабря 2018

Учитывая небольшой выбор возможных типов, я бы просто жестко прописал условия:

using StorageType = std::conditional_t<Size <=  8, uint8_t,
                    std::conditional_t<Size <= 16, uint16_t,
                    std::conditional_t<Size <= 32, uint32_t, uint_fast32_t>>>;

В качестве альтернативы, используя трюк, аналогичный трюку из ответа @ Caleth:

using StorageType = std::tuple_element_t<(Size > 8) + (Size > 16) + (Size > 32),
                        std::tuple<uint8_t, uint16_t, uint32_t, uint_fast32_t>>;
0 голосов
/ 11 декабря 2018

Вы можете использовать рекурсивный класс шаблона с нетиповым аргументом шаблона для ограничения по битам и псевдонимом типа члена для соответствующего целочисленного типа.

Вам не нужно писать такой шаблон самостоятельно, хотя, Boost покрыл: boost::uint_t<N>::least (или boost::uint_t<N>::fast, если вы ищете не самый маленький, но самый быстрый).


PS Если вы планируете внедрить шаблон самостоятельно, и вы хотите наименьший целочисленный тип (согласно вопросу в заголовке), тогда вы должны использовать std::uint_leastN_t вместо uint_fastN_t или uintN_t.Первый не обязательно является наименьшим типом, а последний не гарантированно существует во всех системах.

Более того, uint_fast32_t не гарантирует возможность представлять больше битов, чем 32, поэтому он довольно плохойвыбор за Size > 32.Я бы порекомендовал uint_least64_t вместо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...