Язык программирования C++. Пятое издание - Стенли Липпман
Шрифт:
Интервал:
Закладка:
Упражнение 17.6. Перепишите функцию findBook() так, чтобы она не использовала кортеж или пару.
Упражнение 17.7. Объясните, какую версию функции findBook() вы предпочитаете и почему.
Упражнение 17.8. Что будет, если в качестве третьего параметра алгоритма accumulate() в последнем примере кода этого раздела передать объект класса Sales_data?
17.2. Тип bitset
В разделе 4.8 приводились встроенные операторы, рассматривающие целочисленный операнд как коллекцию битов. Для облегчения использования битовых операций и обеспечения возможности работы с коллекциями битов, размер которых больше самого длинного целочисленного типа, стандартная библиотека определяет класс bitset (набор битов). Класс bitset определен в заголовке bitset.
17.2.1. Определение и инициализация наборов битов
Список конструкторов типа bitset приведен в табл. 17.2. Тип bitset — это шаблон класса, который, подобно классу array, имеет фиксированный размер (см. раздел 3.3.6). При определении набора битов следует указать в угловых скобках количество битов, которые он будет содержать:
bitset<32> bitvec(1U); // 32 бита; младший бит 1, остальные биты 0
Размер должен быть указан константным выражением (см. раздел 2.4.4). Этот оператор определяет набор битов bitvec, содержащий 32 бита. Подобно элементам вектора, биты в наборе битов не имеют имен. Доступ к ним осуществляется по позиции. Нумерация битов начинается с 0. Таким образом, биты набора bitvec пронумерованы от 0 до 31. Биты, расположенные ближе к началу (к 0), называются младшими битами (low-order), а ближе к концу (к 31) — старшими битами (high-order).
Таблица 17.2. Способы инициализации набора битов
bitset<n> b; Набор b содержит n битов, каждый из которых содержит значение 0. Это конструктор constexpr (см. раздел 7.5.6) bitset<n> b(u); Набор b содержит копию n младших битов значения u типа unsigned long long. Если значение n больше размера типа unsigned long long, остальные старшие биты устанавливаются на нуль. Это конструктор constexpr (см. раздел 7.5.6) bitset<n> b(s, рos, m, zero, one); Набор b содержит копию m символов из строки s, начиная с позиции pos. Строка s может содержать только символы для нулей и единиц; если строка s содержит любой другой символ, передается исключение invalid_argument. Символы хранятся в наборе b как нули и единицы соответственно. По умолчанию параметр pos имеет значение 0, параметр m — string::npos, zero — '0' и one — '1' bitset<n> b(cp, pos, m, zero, one); Подобен предыдущему конструктору, но копируется символьный массив, на который указывает cp. Если значение m не предоставлено, cp должен указывать на строку в стиле С. Если m предоставлено, то начиная с позиции cp в массиве должно быть по крайней мере m символов, соответствующих нулям или единицам Конструкторы, получающие строку или символьный указатель, являются явными (см. раздел 7.5.4). В новом стандарте была добавлена возможность определять альтернативные символы для 0 и 1. Инициализация набора битов беззнаковым значениемПри использовании для инициализации набора битов целочисленного значения оно преобразуется в тип unsigned long long и рассматривается как битовая схема. Биты в наборе битов являются копией этой схемы. Если размер набора битов превосходит количество битов в типе unsigned long long, то остальные старшие биты устанавливаются в нуль. Если размер набора битов меньше количества битов, то будут использованы только младшие биты предоставленного значения, а старшие биты вне размера объекта набора битов отбрасываются:
// bitvec1 меньше инициализатора; старшие биты инициализатора
// отбрасываются
bitset<13> bitvec1(0xbeef); // биты 1111011101111
// bitvec2 больше инициализатора; старшие биты bitvec2
// устанавливаются в нуль
bitset<20> bitvec2(0xbeef); // биты 00001011111011101111
// на машинах с 64-битовым long long, 0ULL - это 64 бита из 0,
// a ~0ULL - 64 единицы
bitset<128> bitvec3(~0ULL); // биты 0...63 - единицы; 63...121 - нули
Инициализация набора битов из строкиНабор битов можно инициализировать из строки или указателя на элемент в символьном массиве. В любом случае символы непосредственно представляют битовую схему. Как обычно, при использовании строки для представления числа символы с самыми низкими индексами в строке соответствуют старшим битам, и наоборот:
bitset<32> bitvec4("1100"); // биты 2 и 3 - единицы, остальные - 0
Если строка содержит меньше символов, чем битов в наборе, старшие биты устанавливаются в нуль.
Соглашения по индексации строк и наборов битов прямо противоположны: символ строки с самым высоким индексом (крайний правый символ) используется для инициализации младшего бита в наборе битов (бит с индексом 0). При инициализации набора битов из строки следует помнить об этом различии.
Необязательно использовать всю строку в качестве исходного значения для набора битов, вполне можно использовать часть строки:
string str("1111111000000011001101");
bitset<32> bitvec5(str, 5, 4); // четыре бита, начиная с str[5] - 1100
bitset<32> bitvec6(str, str.size()-4); // использует четыре последних
// символа
Здесь набор битов bitvec5 инициализируется подстрокой str, начиная с символа str[5], и четырьмя символами далее. Как обычно, крайний справа символ подстроки представляет бит самого низкого порядка. Таким образом, набор bitvec5 инициализируется битами с позиции 3 до 0 и получает значение 1100, а остальные биты — 0. Инициализатор набора битов bitvec6 передает строку и отправную точку, поэтому он инициализируется символами строки str, начиная с четвертого и до конца строки str. Остаток битов набора bitvec6 инициализируется нулями. Эти инициализации можно представить так:
Упражнения раздела 17.2.1Упражнение 17.9. Объясните битовую схему, которую содержит каждый из следующих объектов bitset:
(a) bitset<64> bitvec(32);
(b) bitset<32> bv(1010101);
(c) string bstr; cin >> bstr; bitset<8> bv(bstr);
17.2.2. Операции с наборами битов
Операции с наборами битов (табл. 17.3) определяют различные способы проверки и установки одного или нескольких битов. Класс bitset поддерживает также побитовые операторы, которые рассматривались в разделе 4.8. Применительно к объектам bitset эти операторы имеют тот же смысл, что и таковые встроенные операторы для типа unsigned.
Таблица 17.3. Операции с наборами битов
b.any() Установлен ли в наборе b хоть какой-нибудь бит? b.all() Все ли биты набора b установлены? b.none() Нет ли в наборе b установленных битов? b.count() Количество установленных битов в наборе b b.size() Функция constexpr (см. раздел 2.4.4), возвращающая количество битов набора b b.test(pos) Возвращает значение true, если бит в позиции pos установлен, и значение false в противном случае b.set(pos, v) b.set() Устанавливает для бита в позиции pos логическое значение v. По умолчанию v имеет значение true. Без аргументов устанавливает все биты набора b b.reset(pos) b.reset() Сбрасывает бит в позиции pos или все биты набора b b.flip(pos) b.flip() Изменяет состояние бита в позиции pos или все биты набора b b[pos] Предоставляет доступ к биту набора b в позиции pos; если набор b константен и бит установлен, то b[pos] возвращает логическое значение true, а в противном случае — значение false b.to_ulong() b.to_ullong() Возвращает значение типа unsigned long или типа unsigned long long с теми же битами, что и в наборе b. Если битовая схема в наборе b не соответствует указанному типу результата, передается исключение overflow_error b.to_string(zero, one) Возвращает строку, представляющую битовую схему набора b. Параметры zero и one имеют по умолчанию значения '0' и '1'. Они используют для представления битов 0 и 1 в наборе b os << b Выводит в поток os биты набора b как символы '0' и '1' is >> b Читает символы из потока is в набор b. Чтение прекращается, когда следующий символ отличается от 1 или 0 либо когда прочитано b.size() битовНекоторые из функций, count(), size(), all(), any() и none(), не получают аргументов и возвращают информацию о состоянии всего набора битов. Другие, set(), reset() и flip(), изменяют состояние набора битов. Функции-члены, изменяющие набор битов, допускают перегрузку. В любом случае версия функции без аргументов применяет соответствующую операцию ко всему набору, а версии функций, получающих позицию, применяют операцию к заданному биту: