Выбрать главу

> class unordered_map;

В качестве первых двух типов шаблона мы выбрали coord и int, здесь все просто и очевидно. Три остальных типа шаблона являются необязательными, так что автоматически заполняются существующими стандартными шаблонными классами, которые сами принимают типы шаблонов. В случае если последние аргументы заполняются значениями по умолчанию, в качестве типов шаблонов передаются те типы, которые мы указали в первых двух аргументах.

Для нас сейчас особый интерес представляет шаблонный параметр class Hash: когда мы не указываем явно что-то другое, он будет специализирован как std::hash<key_type>. STL уже содержит специализации std::hash<std::string>, std::hash<int>, std::hash<unique_ptr> и многие другие. Эти классы знают, как работать с подобными конкретными типами, что позволяет вычислять оптимальные хеш-значения.

Однако STL пока не знает, как рассчитывать хеш-значение на основе нашей структуры coord. Мы лишь определили еще одну специализацию, которая знает, как это делается. Компилятор теперь может пройти по списку всех известных специализаций для контейнера std::hash и найти нашу реализацию, что позволит соотнести ее с типом, который мы выбрали для ключа.

Если бы мы не добавили новую специализацию std::hash<coord>, а назвали бы имеющуюся вместо этого my_hash_type, то нам пришлось бы использовать следующую строку для создания объекта:

std::unordered_map<coord, value_type, my_hash_type> my_unordered_map;

Очевидно, что таким образом придется набирать больше кода. Кроме того, при этом подходе код тяжелее читать, в отличие от ситуации, когда компилятор самостоятельно находит правильную реализацию хеш-функции. 

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

 Контейнер std::set довольно странный. Принцип его работы похож на принцип работы контейнера std::map. Однако std::set содержит только ключи в качестве значений, а не пары «ключ — значение». Поэтому он не очень подходит для соотношения значения одного типа со значениями другого. Поскольку способы применения этого контейнера не вполне очевидны, многие разработчики даже не знают о его существовании. Они часто начинают реализовывать похожие механизмы самостоятельно, хотя в некоторых ситуациях контейнер std::set оказался бы отличным подспорьем.

В этом разделе будет показано, как применить контейнер std::set, на примере, в котором мы получаем потенциально большое количество разных элементов. Мы отфильтруем их и выведем на экран уникальные элементы.

Как это делается

В этом примере мы считаем поток слов из стандартного средства ввода. Все уникальные слова будут помещены в экземпляр класса std::set. Таким образом мы сможем перечислить все уникальные слова из потока[1].

1. Мы используем несколько разных типов STL, для чего включим некоторые заголовочные файлы:

#include <iostream>

#include <set>

#include <string>

#include <iterator>

2. Чтобы сэкономить немного времени на наборе текста, объявим об использовании пространства имен std:

using namespace std;

3. Теперь мы готовы писать саму программу, начинающуюся с функции main. В ней создается экземпляр класса std::set, в котором будут храниться строки:

int main()

{

  set<string> s;

4. Далее получим данные от пользователя. Просто считаем их из стандартного потока ввода с помощью удобного итератора istream_iterator:

  istream_iterator<string> it {cin};

  istream_iterator<string> end;

5. Имея начальный и конечный итераторы, которые представляют данные, введенные пользователем, можем просто заполнить множество на основе этих данных с помощью std::inserter:

  copy(it, end, inserter(s, s.end()));

6. На этом, в общем-то, все. Чтобы увидеть, какие уникальные слова мы получили из стандартного ввода, просто выведем на экран содержимое нашего множества:

  for (const auto word : s) {

    cout << word << ", ";

  }

  cout << '\n';

}

7. Скомпилируем и запустим программу с нашими входными данными. Взглянем на полученный результат, из которого были удалены все дубликаты, а уникальные слова теперь отсортированы по алфавиту:

вернуться

1

Все это будет проделано средствами стандарта C++98, из нового в этом разделе только синтаксис.