Как установить / проверить msb для обобщенного типа? - PullRequest
0 голосов
/ 05 февраля 2019

У меня есть следующие фрагменты где-то в моей текущей кодовой базе:

// uint32_t id; defined somewhere
bool msb_set = id & 0x80000000

И я хотел бы изменить это на что-то более гибкое:

using id_t = uint64_t;
id_t id;
bool msb_set = id & 0x80000000  // uh-oh, semantic change for any other differently sized inttype

Как мне проще всего генерироватьсоответствующий литерал в зависимости от конкретного используемого типа?Я ищу что-то вроде

numeric_constants<id_t>::int_with_msb_set();

Ответы [ 2 ]

0 голосов
/ 05 февраля 2019

Вот функция, которая возвращает нужные вам маски:

template<typename T>
constexpr T getMsbMask()
{
    if constexpr (std::is_unsigned_v<T>)
        return T(-1) - T(-1) / 2;
    else
        return std::numeric_limits<T>::min();
    // Unsigned branch computes 0b11111... - 0b01111...
    // Signed branch assumes two's complement, which will soon be the standard:
    // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0907r0.html
}

Демонстрация и тесты на Godbolt .

Компилятор, очевидно, может определить эти постоянные значенияво время компиляции, поэтому нет никакого снижения скорости вообще.

Другим очевидным решением будет просто структура со специализациями для каждого типа (сродни std::numeric_limits).

0 голосов
/ 05 февраля 2019

Вы можете использовать std::bitset, чтобы проверить, установлен ли старший значащий бит.Вы можете преобразовать число в std::bitset, а затем вернуть наиболее значимый бит, например

template<typename T> 
constexpr bool mb_set(T value)
{
    constexpr auto size = sizeof(T) * CHAR_BIT;
    return std::bitset<size>(value)[size - 1];
}

, при проверке этого на clang с помощью -O2 или -O3 оптимизирует функцию до инструкции shr.

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