- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц
Шрифт:
Интервал:
Закладка:
В этом разделе мы рассмотрим способ решения данной проблемы с помощью объекта std::function, который может выступать в роли полиморфической оболочки для любого лямбда-выражения, независимо от того, какие значения оно захватывает.
Как это делается
В этом примере мы создадим несколько лямбда-выражений, значительно отличающихся друг от друга, но имеющих одинаковую сигнатуру вызова. Затем сохраним их в одном векторе с помощью std::function.
1. Сначала включим необходимые заголовочные файлы:
#include <iostream>
#include <deque>
#include <list>
#include <vector>
#include <functional>
2. Реализуем небольшую функцию, которая возвращает лямбда-выражение. Она принимает контейнер и возвращает объект функции, захватывающий этот контейнер по ссылке. Сам по себе объект функции принимает целочисленный параметр. Когда данный объект получает целое число, он добавит его в свой контейнер.
static auto consumer (auto &container){
return [&] (auto value) {
container.push_back(value);
};
}
3. Еще одна небольшая вспомогательная функция выведет на экран содержимое экземпляра контейнера, который мы предоставим в качестве параметра:
static void print (const auto &c)
{
for (auto i : c) {
std::cout << i << ", ";
}
std::cout << 'n';
}
4. В функции main мы создадим объекты классов deque, list и vector, каждый из которых будет хранить целые числа:
int main()
{
std::deque<int> d;
std::list<int> l;
std::vector<int> v;
5. Сейчас воспользуемся функцией consumer для работы с нашими экземплярами контейнеров d, l и v: создадим для них объекты-потребители функций и поместим их в экземпляр vector. Эти объекты функций будут захватывать ссылку на один из объектов контейнера. Последние имеют разные типы, как и объекты функций. Тем не менее вектор хранит экземпляры типа std::function<void(int)>. Все объекты функций неявно оборачиваются в объекты типа std::function, которые затем сохраняются в векторе:
const std::vector<std::function<void(int)>> consumers
{consumer(d), consumer(l), consumer(v)};
6. Теперь поместим десять целочисленных значений во все структуры данных, проходя по значениям в цикле, а затем пройдем в цикле по объектам функций-потребителей, которые вызовем с записанными значениями:
for (size_t i {0}; i < 10; ++i) {
for (auto &&consume : consumers) {
consume(i);
}
}
7. Все три контейнера теперь должны содержать одинаковые десять чисел. Выведем на экран их содержимое:
print(d);
print(l);
print(v);
}
8. Компиляция и запуск программы дадут следующий результат, который выглядит именно так, как мы и ожидали:
$ ./std_function
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
Как это работает
Самой сложной частью этого примера является следующая строка:
const std::vector<std::function<void(int)>> consumers
{consumer(d), consumer(l), consumer(v)};
Объекты d, l и v обернуты в вызов consumer(...). Он возвращает объекты функций, каждый из которых захватывает ссылки на один из объектов — d, l или v. Хотя все объекты функций принимают в качестве параметров целочисленные значения, тот факт, что они захватывают абсолютно разные переменные, также делает их типы совершенно разными. Это похоже на попытку разместить в векторе переменные типов A, B и C, когда сами типы не имеют ничего общего.
Чтобы это исправить, нужно найти общий тип, способный хранить разные объекты функций, например std::function. Объект типа std::function<void(int)> может хранить любой объект функции или традиционную функцию, которая принимает целочисленный параметр и ничего не возвращает. С помощью полиморфизма он отвязывает тип от лежащего в его основе типа объекта функции.
Представьте, будто мы написали такой код:
std::function<void(int)> f (
[&vector](int x) { vector.push_back(x); });
Здесь объект функции, создаваемый на основе лямбда-выражения, обернут в объект типа std::function, и всякий раз вызов f(123) приводит к виртуальному вызову функции, который перенаправляется реальному объекту функции, находящемуся внутри.
При сохранении объектов функции экземпляры std::function применяют некоторую логику. При захвате все большего и большего количества переменных лямбда-выражение будет увеличиваться. Если его размер относительно мал, то std::function может хранить его внутри себя. Если же размер сохраненного объекта функций слишком велик, то std::function выделит фрагмент памяти в куче и сохранит объект там. Возможности нашего кода в подобном случае затронуты не будут, но знать об этом нужно, поскольку такая ситуация может повлиять на его производительность.
Многие программисты-новички думают или надеются, что std::function<...> на самом деле выражает тип лямбда-выражения. Отнюдь. Это полиморфическая вспомогательная библиотечная функция, которая полезна для оборачивания лямбда-выражений и сокрытия различий в их типах.
Создаем функции методом конкатенации
Многие проблемы можно решить, не полагаясь исключительно на собственный код. Например, взглянем на то, как решается задача поиска уникальных слов в тексте на языке программирования Haskell. В первой строке определяется функция unique_words, а во второй показывается ее использование на примере строки (рис. 4.2).
Ого! Программа получилась действительно короткой. Не вдаваясь особо в синтаксис языка Haskell, взглянем на то, что делает код. Определяется функция unique_words, в которой к входным данным применяется набор функций. Сначала все символы преобразуются в строчные с помощью map toLower. Таким образом, слова наподобие FOO и foo могут считаться одним словом. Далее функция words разбивает предложение на отдельные слова. Например, из строки "foo bar baz" мы получим массив ["foo", "bar", "baz"]. Следующий шаг — сортировка нового списка слов. В результате последовательность слов ["a", "b", "a"] будет выглядеть как ["a", "a", "b"]. Теперь в дело вступает функция group. Она группирует последовательные слова в списки, т.е. конструкция ["a", "a", "b"] получит вид [["a", "a"], ["b"]]. Задача практически выполнена, и теперь нужно сосчитать, сколько получилось групп одинаковых слов. В этом поможет функция length.
Это замечательный стиль программирования,