> 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, из нового в этом разделе только синтаксис.