cpp-ru / ideas

Идеи по улучшению языка C++ для обсуждения
https://cpp-ru.github.io/proposals
Creative Commons Zero v1.0 Universal
89 stars 0 forks source link

std::bitset to any integral conversion #134

Open apolukhin opened 3 years ago

apolukhin commented 3 years ago

Перенос предложения: голоса +16, -0 Aвтор идеи: mrgordonfreman

Текущей реализации std::bitset не достает гибкости в преобразовании к целым числам.

Пример типичного использования.

При объявлении bitset знаем точное число бит.

std::bitset<16> flags;

Здесь тоже знаем точное число бит.

uint16_t flags_register;

А дальше получаем проблемный код.

flags_register = flags.to_ulong();

Размер unsigned long может быть 4 или 8 байт на разных платформах. Но нам не нужно ни 4, ни 8 байт, а только 2. Более того, to_ulong() может кидать исключения, но мы точно знаем, что исключений не будет.

Но код работает, и вроде бы ничего страшного. Потом решили запускать компилятор с флагом -Wconversion и получаем предупреждение

Warning: conversion to ‘uint16_t {aka short unsigned int}’ from ‘long unsigned int’ may alter its value [-Wconversion]
flags_register = flags.to_ulong();
                 ~~~~~~~~~~~~~~^~

Тогда в коде придется использовать сужающее преобразование

flags_register = static_cast<uint16_t>(flags.to_ulong());

Проблему решит добавление следующего метода

#include <type_traits>

template<std::size_t N>
class bitset
{
    // ...
    template<typename T>
    T as_integral() const noexcept
    {
        static_assert(std::is_integral<T>::value && N <= sizeof(T) * 8);
        //...
    }
    // ...
};

Также станет невозможным преобразовать bitset в число с меньшим количеством бит, и узнаем это на этапе компиляции

std::bitset<16> bs;
bs.as_integral<uint16_t>();
bs.as_integral<uint8_t>(); // COMPILATION ERROR HERE!
apolukhin commented 3 years ago

Antervis, 8 марта 2017, 19:06 Возможно, тогда стоит добавить метод integral_t to_integral() const noexcept;, где integral_t определен как беззнаковый целочисленный тип минимального достаточного размера, чтобы вместить все биты, или unsigned long long.