chitay-knigi.com » Разная литература » C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 6 7 8 9 10 11 12 13 14 ... 121
Перейти на страницу:
первые два представляют собой начальный и конечный итераторы того или иного итерабельного промежутка, а третий параметр — это значение, с которым будут сравниваться все элементы промежутка. Метод std::count возвращает количество всех элементов внутри диапазона, равных третьему параметру.

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

Ее можно использовать следующим образом:

std::vector<int> v {1, 2, 3, 4, 5};

matches(v, 2, 5);                  // возвращает 2

matches(v, 100, 200);              // возвращает 0

matches("abcdefg", 'x', 'y', 'z'); // возвращает 0

matches("abcdefg", 'a', 'd', 'f'); // возвращает 3

Как видите, вспомогательная функция matches довольно гибкая — ее можно вызвать для векторов или даже строк. Она также будет работать для списка инициализаторов, контейнеров std::list, std::array, std::set и прочих!

Проверка успешности вставки нескольких элементов в множество

Напишем вспомогательную функцию, которая добавляет произвольное количество параметров в контейнер std::set и возвращает булево значение, показывающее, успешно ли прошла операция:

template <typename T, typename ... Ts>

bool insert_all(T &set, Ts ... ts)

{

  return (set.insert(ts).second && ...);

}

Как же это работает? Функция insert контейнера std::set имеет следующую сигнатуру:

std::pair<iterator, bool> insert(const value_type& value);

Документация гласит, что при попытке вставить элемент функция insert вернет пару из iterator и переменной bool. Если вставка пройдет успешно, значение переменной будет равно true. Итератор же в этом случае укажет на новый элемент множества, а в противном случае — на существующий элемент, который помешал вставке.

Наша вспомогательная функция после вставки обращается к полю .second. Оно содержит переменную bool, которая показывает, была ли вставка успешной. Если все полученные пары имеют значение true, то все вставки прошли успешно. Свертка объединяет все результаты вставки с помощью оператора && и возвращает результат.

Контейнер можно использовать следующим образом:

std::set<int> my_set {1, 2, 3};

insert_all(my_set, 4, 5, 6); // Возвращает true

insert_all(my_set, 7, 8, 2); // Возвращает false, поскольку 2 уже присутствует

Обратите внимание: если мы попробуем вставить, например, три элемента, но в процессе окажется, что второй элемент вставить нельзя, свертка && ... досрочно прекратит работать и оставшиеся элементы не будут добавлены:

std::set<int> my_set {1, 2, 3};

insert_all(my_set, 4, 2, 5); // Возвращает false

// теперь множество содержит значения {1, 2, 3, 4}, без 5!

Проверка попадания всех параметров в заданный диапазон

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

template <typename T, typename Ts>

bool within(T min, T max, Ts ts)

{

  return ((min <= ts && ts <= max) && ...);

}

Выражение (min <= ts && ts <= max) определяет, находится ли каждый элемент пакета параметров в диапазоне между min и max (включая min и max). Мы выбрали оператор &&, чтобы свести все результаты булева типа к одному, который имеет значение true только в том случае, если все отдельные результаты имеют такое же значение.

Это работает следующим образом:

within( 10, 20, 1, 15, 30);     // --> false

within( 10, 20, 11, 12, 13);    // --> true

within(5.0, 5.5, 5.1, 5.2, 5.3) // --> true

Что интересно: эта функция очень гибкая, поскольку единственным требованием, которое она предъявляет к типам, служит возможность сравнения экземпляров с помощью оператора <=. Это требование выполняется, например, типом std::string:

std::string aaa {"aaa"};

std::string bcd {"bcd"};

std::string def {"def"};

std::string zzz {"zzz"};

within(aaa, zzz, bcd, def); // --> true

within(aaa, def, bcd, zzz); // --> false

Отправка нескольких элементов в вектор

Кроме того, вы можете написать вспомогательную функцию, которая не обобщает никаких результатов, но обрабатывает несколько действий одного вида. Такими действиями могут быть вставки элементов в контейнер std::vector, поскольку они не возвращают никаких результатов (функция std::vector::insert() сообщает об ошибке, генерируя исключения):

template <typename T, typename ... Ts>

void insert_all(std::vector<T> &vec, Ts ... ts)

{

  (vec.push_back(ts), ...);

}

int main()

{

  std::vector<int> v {1, 2, 3};

  insert_all(v, 4, 5, 6);

}

Обратите внимание: мы используем оператор «запятая» (,), чтобы распаковать пакет параметров в отдельные вызовы vec.push_back(...), не выполняя свертку для самого результата. Эта функция также хорошо работает в отношении пустого пакета параметров, поскольку оператор «запятая» имеет неявный нейтральный элемент, void(), который означает «ничего не делать». 

Глава 2

Контейнеры STL

В этой главе:

□ использование идиомы erase-remove для контейнера std::vector;

□ удаление элементов из неотсортированного контейнера std::vector за время O(1);

□ получение доступа к экземплярам класса std::vector быстрым или безопасным способом;

□ поддержка экземпляров класса std::vector в отсортированном состоянии;

□ вставка элементов в контейнер std::map: эффективно и в соответствии с условиями;

□ исследование новой семантики подсказок для вставки элементов с помощью метода std::map::insert;

□ эффективное изменение ключей элементов std::map;

□ применение контейнера std::unordered_map для пользовательских типов;

□ отбор повторно встречающихся слов из пользовательского ввода и вывод их на экран в алфавитном порядке с помощью контейнера std::set;

□ реализация простого ОПН-калькулятора с использованием контейнера std::stack;

□ подсчет частоты встречаемости слов с применением контейнера std::map;

□ реализация вспомогательного инструмента для поиска очень длинных предложений в текстах с помощью std::multimap;

□ реализация личного списка текущих дел с помощью std::priority_queue.

Введение

В стандартной библиотеке С++ появилось большое количество стандартных контейнеров. Контейнер всегда содержит набор данных или объектов. Достоинство контейнеров в том, что их можно применять практически для всех объектов, поэтому нужно только выбрать правильные контейнеры для конкретного приложения. STL предоставляет стеки, автоматически увеличивающиеся векторы, ассоциативные массивы и т.д. Таким образом,

1 ... 6 7 8 9 10 11 12 13 14 ... 121
Перейти на страницу:

Комментарии
Минимальная длина комментария - 25 символов.
Комментариев еще нет. Будьте первым.