- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц
Шрифт:
Интервал:
Закладка:
for (const animal &a : l) {
switch (a.index()) {
case 0:
get<dog>(a).woof();
break;
case 1:
get<cat>(a).meow();
break;
}
}
cout << "-----n";
9. Вместо того чтобы использовать численный индекс типа, можно также явно запросить каждый тип. Вызов get_if<dog> возвращает указатель на объект типа do на внутренний экземпляр типа dog. Если такого экземпляра внутри нет, то указатель равен null. Таким образом, мы можем попробовать получать разные типы до тех пор, пока не преуспеем.
for (const animal &a : l) {
if (const auto d (get_if<dog>(&a)); d) {
d->woof();
} else if (const auto c (get_if<cat>(&a)); c) {
c->meow();
}
}
cout << "-----n";
10. Последний — и самый элегантный вариант — это variant::visit. Данная функция принимает объект функции и экземпляр типа variant. Объект функции должен реализовывать разные перегруженные версии для всех вероятных типов, которые может хранить variant. Ранее мы реализовали структуру, имеющую необходимые перегруженные версии оператора (), поэтому можем использовать ее здесь:
for (const animal &a : l) {
visit(animal_voice{}, a);
}
cout << "-----n";
11. Наконец подсчитаем количество экземпляров типов cat и dog в списке. Предикат is_type<T> может быть специализирован для типов cat и dog, а затем использован в комбинации с std::count_if, чтобы получить количество экземпляров этого типа:
cout << "There are "
<< count_if(begin(l), end(l), is_type<cat>)
<< " cats and "
<< count_if(begin(l), end(l), is_type<dog>)
<< " dogs in the list.n";
}
12. После компиляции и запуска программы на экране будет список, выведенный три раза. Затем мы увидим, что предикаты is_type, объединенные с count_if, тоже работают хорошо:
$ ./variant Tuba says Meow!
Balou says Woof!
Bobby says Meow!
-----
Tuba says Meow!
Balou says Woof!
Bobby says Meow!
-----
Tuba says Meow!
Balou says Woof!
Bobby says Meow!
-----
There are 2 cats and 1 dogs in the list.
Как это работает
Тип std::variant похож на тип std::any, поскольку они оба могут содержать объекты разных типов, и нужно определять во время работы программы, что именно в них хранится, прежде чем получить доступ к их содержимому.
С другой стороны, тип std::variant отличается от std::any тем, что мы должны объявлять, экземпляры каких типов он может хранить в виде списка шаблонных типов. Экземпляр типа std::variant<A, B, C> должен хранить один экземпляр типа A, B или C. Нельзя сделать так, чтобы в экземпляре типа variant не хранился ни один экземпляр. Это значит, что тип std::variant не поддерживает возможность опциональности.
Экземпляр типа variant<A, B, C> имитирует объединение, которое может выглядеть так:
union U {
A a;
B b;
C c;
};
Проблема с объединениями заключается в том, что нужно создавать собственные механизмы для определения того, экземпляром какого типа оно было инициализировано: A, B или C. Тип std::variant может сделать это за нас, не прилагая особых усилий.
В коде, показанном в этом разделе, мы использовали три разных способа работы с содержимым переменной variant.
Первый способ — применение функции index() типа variant. Для типа variant<A, B, C> она может вернуть индекс 0, если экземпляр был инициализирован переменной типа A, 1 для типа B или 2 для типа C, и т.д. для более сложных вариантов.
Следующий способ — использование функции get_if<T>. Она принимает адрес объекта типа variant и возвращает указатель типа T на его содержимое. Если тип T указан неправильно, то указатель станет нулевым. Кроме того, можно вызвать метод get<T>(x) для переменной типа variant, чтобы получить ссылку на ее содержимое, но если это не сработает, то данная функция сгенерирует исключение (перед выполнением таких преобразований можно проверить правильность типа с помощью булева предиката holds_alternative<T>(x)).
Последний способ получить доступ к значению, хранящемуся в типе variant, — применить функцию std::visit. Она принимает объект функции и экземпляр типа variant. Функция проверяет, какой тип имеет содержимое экземпляра типа variant, а затем вызывает соответствующий перегруженный оператор () объекта функции.
Именно для этих целей мы и реализовали тип animal_voice, поскольку он может быть использован в комбинации с visit и variant<dog, cat>:
struct animal_voice
{
void operator()(const dog &d) const { d.woof(); }
void operator()(const cat &c) const { c.meow(); }
};
Последний описанный способ получения доступа к экземплярам, хранящимся в экземплярах типа variant, считается самым элегантным, поскольку в разделах кода, в которых мы получаем доступ к экземпляру, не нужно жестко кодировать возможные типы. Это позволяет проще расширять код.
Утверждение о том, что тип variant не может не иметь значения, было не совсем верным. Добавив тип std::monostate в список вероятных типов, можно указать, что экземпляр не будет хранить значения.
Автоматическое управление ресурсами с помощью std::unique_ptr
Начиная с C++11 в STL появились умные указатели, помогающие отслеживать динамическую память и ее использование. Даже до C++11 существовал класс auto_ptr, который мог управлять динамической памятью, но его было легко применить неправильно.
Однако с появлением умных указателей теперь редко приходится самостоятельно использовать ключевые слова new и delete, и это очень хорошо. Умные указатели — отличный пример автоматического управления памятью. Поддерживая объекты, память для которых выделяется динамически с помощью unique_ptr, мы защищены от утечек памяти, поскольку при разрушении объекта данный класс автоматически вызывает поддерживаемый им объект.
Уникальный указатель выражает принадлежность объекта,