Читать книги » Книги » Компьютеры и Интернет » Программирование » C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц

C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц

Читать книгу C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц, Яцек Галовиц . Жанр: Программирование.
C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц
Название: C++17 STL Стандартная библиотека шаблонов
Дата добавления: 15 июль 2023
Количество просмотров: 1 473
(18+) Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних просмотр данного контента СТРОГО ЗАПРЕЩЕН! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту для удаления материала.
Читать онлайн

C++17 STL Стандартная библиотека шаблонов читать книгу онлайн

C++17 STL Стандартная библиотека шаблонов - читать онлайн , автор Яцек Галовиц

С++ — объектно-ориентированный язык программирования, без которого сегодня немыслима промышленная разработка ПО. В этой замечательной книге описана работа с контейнерами, алгоритмами, вспомогательными классами, лямбда-выражениями и другими интересными инструментами, которыми богат современный С++. Освоив материал, вы сможете коренным образом пересмотреть привычный подход к программированию.
Преимущество издания — в подробном описании стандартной библиотеки шаблонов С++, STL. Ее свежая версия была выпущена в 2017 году. В книге вы найдете более 90 максимально реалистичных примеров, которые демонстрируют всю мощь STL. Многие из них станут базовыми кирпичиками для решения более универсальных задач.
Вооружившись этой книгой, вы сможете эффективно использовать С++17 для создания высококачественного и высокопроизводительного ПО, применимого в различных отраслях.

1 ... 84 85 86 87 88 ... 121 ВПЕРЕД
Перейти на страницу:
мы воспользуемся методом std::apply, чтобы распаковать все элементы из кортежа t. Если данный шаг выглядит слишком сложным, обратитесь к предыдущему примеру — он демонстрирует работу метода std::apply.

Функция zip для кортежей

Функция zip принимает два кортежа, но выглядит весьма сложной, несмотря на то что имеет очень четкую реализацию:

template <typename T1, typename T2>

auto zip(const T1 &a, const T2 &b)

{

  auto z ([](auto ...xs) {

    return [xs...](auto ...ys) {

      return tuple_cat(make_tuple(xs, ys) ...);

    };

  });

  return apply(apply(z, a), b);

}

Для лучшего понимания этого кода представьте, что кортеж a содержит значения 1, 2, 3, а кортеж b — значения 'a', 'b', 'c'.

В данном случае вызов apply(z, a) приведет к вызову z(1, 2, 3). Он вернет объект функции, который захватит значения 1, 2, 3 в набор параметров xs. В момент вызова с помощью apply(z(1,2,3),b) этот объект получит значения 'a', 'b', 'c', помещенные в набор параметров ys. По сути, действие аналогично прямому вызову z(1,2,3)('a', 'b', 'c').

О’кей, что произойдет теперь, когда у нас есть значения xs = (1, 2, 3) и ys = ('a', 'b', 'c')? Выражение tuple_cat(make_tuple(xs, ys) ...) сделает следующее (рис. 8.1).

Сначала элементы из наборов xs и ys будут сгруппированы попарно. Это «попарное чередование» выполняется в вызове make_tuple(xs,ys). Сначала мы получим список кортежей переменной длины по два элемента в каждом. Чтобы получить один большой кортеж, мы применяем вызов tuple_cat — в результате получаем большой сконкатенированный кортеж, содержащий все члены исходных кортежей, которые чередуются. 

Замена void* с использованием std::any для повышения безопасности типов

Может случиться так: нам понадобится сохранить элементы любого типа в переменной. Для такой переменной следует проверить, содержит ли она что-либо, и если да, то нужно определить, что именно. Все это надо сделать безопасно для типов.

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

Еще одним дополнением к STL в C++17 является тип std::any. Он разработан для того, чтобы хранить переменные любого вида, и предоставляет средства, которые позволяют выполнить проверку, безопасную для типов, и получить доступ к данным.

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

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

В этом примере мы реализуем функцию, которая пробует вывести на экран какие-либо данные. В качестве ее типа аргумента служит тип std::any.

1. Сначала включим необходимые заголовочные файлы и объявим об использовании пространства имен std:

#include <iostream>

#include <iomanip>

#include <list>

#include <any>

#include <iterator>

using namespace std;

2. Чтобы сократить объем использования угловых скобок в следующей программе, определим псевдоним для типа list<int> и будем применять его впоследствии:

using int_list = list<int>;

3. Реализуем функцию, которая утверждает, что может вывести на экран любые данные. Обещание заключается вот в чем: она выводит любые данные, предоставленные как аргумент в виде переменной std::any:

void print_anything(const std::any &a)

{

4. Первое, что нужно сделать, — проверить, содержит ли аргумент какие-то данные, или же это пустой экземпляр типа any. Если он пуст, то нет смысла пытаться определить, как его выводить на экран.

  if (!a.has_value()) {

    cout << "Nothing.n";

5. Если он не пуст, то можно попробовать сравнивать его с разными типами до тех пор, пока не получим совпадение. Первым типом послужит тип string. Если это строка, то можно выполнить преобразование a к ссылке string с помощью std::any_cast и просто вывести его на экран. Из соображений эстетики мы поместим строку в кавычки:

  } else if (a.type() == typeid(string)) {

    cout << "It's a string: "

         << quoted(any_cast<const string&>(a)) << 'n';

6. Если это не string, то может быть int. При совпадении данного типа можно использовать преобразование any_cast<int>, чтобы получить реальное значение int:

  } else if (a.type() == typeid(int)) {

    cout << "It's an integer: "

         << any_cast<int>(a) << 'n';

7. std::any работает не только для простых типов наподобие string и int. В переменную any можно поместить и ассоциативный массив, список или экземпляр любого другого сложного типа данных. Посмотрим, являются ли входные данные списком целых чисел, и если да, то можем вывести его точно так же, как и любой другой список:

  } else if (a.type() == typeid(int_list)) {

    const auto &l (any_cast<const int_list&>(a));

    cout << "It's a list: ";

    copy(begin(l), end(l),

         ostream_iterator<int>{cout, ", "});

    cout << 'n';

8. Если не подошел ни один из перечисленных типов, то у нас закончатся догадки. В таком случае просто сдадимся и скажем пользователю, что не знаем, как выводить эти данные на экран:

  } else {

    cout << "Can't handle this item.n";

  }

}

9. В функции main можем вызвать эту функцию с произвольными типами, с пустой переменной типа any с помощью {} или передать ей строку "abc" или целое число. Поскольку экземпляр типа std::any может быть создан на основе этих типов неявно, не возникает задержек, связанных с синтаксисом. Мы даже можем создать целый список и передать его в эту функцию:

int main()

{

  print_anything({});

  print_anything("abc"s);

  print_anything(123);

  print_anything(int_list{1, 2, 3});

10. Если мы будем помещать объекты, копировать которые действительно дорого, в переменную типа any, то можем также выполнить конструкцию «на месте» (in-place). Попробуем сделать это для нашего списочного типа. Выражение in_place_type_t<int_list>{} представляет собой пустой объект, дающий

1 ... 84 85 86 87 88 ... 121 ВПЕРЕД
Перейти на страницу:
Комментарии (0)