Читать книги » Книги » Компьютеры и Интернет » Программирование » 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 ... 31 32 33 34 35 ... 121 ВПЕРЕД
Перейти на страницу:
реализаций STL это может понадобиться для успешной компиляции кода:

namespace std {

  template <>

  struct iterator_traits<zip_iterator> {

    using iterator_category = std::forward_iterator_tag;

    using value_type = std::pair<double, double>;

    using difference_type = long int;

  };

}

10. Следующий шаг — определение класса диапазона данных, функции begin и end которого возвращают итераторы-упаковщики:

class zipper {

  using vec_type = std::vector<double>;

  vec_type &vec1;

  vec_type &vec2;

11. Он должен сослаться на два существующих контейнера, чтобы создать итераторы-упаковщики:

public:

  zipper(vec_type &va, vec_type &vb)

    : vec1{va}, vec2{vb}

  {}

12. Функции begin и end просто передают пары начальных и конечных указателей, чтобы создать с их помощью экземпляры итераторов-упаковщиков:

  zip_iterator begin() const {

    return {std::begin(vec1), std::begin(vec2)};

  }

  zip_iterator end() const {

    return {std::end(vec1), std::end(vec2)};

  }

};

13. Как и в примерах кода на языках Haskell и Python, определяем два вектора, содержащих значения типа double. Кроме того, указываем, что используем пространство имен std внутри функции main по умолчанию:

int main()

{

  using namespace std;

  vector<double> a {1.0, 2.0, 3.0};

  vector<double> b {4.0, 5.0, 6.0};

14. Объект класса zipper объединяет их в один диапазон данных, напоминающий вектор, где можно увидеть пары значений векторов a и b:

  zipper zipped {a, b};

15. Используем метод std::accumulate, чтобы сложить все элементы диапазона данных. Сделать это напрямую нельзя, поскольку в результате мы сложим экземпляры типа std::pair<double, double>, для которых концепция суммирования не определена. Поэтому зададим вспомогательное лямбда-выражение, которое принимает пару, перемножает ее члены и складывает результат со значением переменной-аккумулятора. Функция std::accumulate хорошо работает с лямбда-выражениями со следующей сигнатурой:

  const auto add_product ([](double sum, const auto &p) {

    return sum + p.first * p.second;

  });

16. Теперь передадим его функции std::accumulate, а также пару итераторов для упаковываемых диапазонов и стартовое значение 0.0 для переменной-аккумулятора, которая, в конечном счете, будет содержать сумму произведений:

  const auto dot_product (accumulate(

    begin(zipped), end(zipped), 0.0, add_product));

17. Выведем на экран полученный результат:

  cout << dot_product << 'n';

}

18. Компиляция и запуск программы дадут правильный результат:

32

Дополнительная информация

Да, нам пришлось написать много строк, чтобы добавить в код немного синтаксического сахара, и он все еще не так элегантен, как версия кода на Haskell. Большим недостатком является тот факт, что наш итератор-упаковщик жестко закодирован — он работает только для векторов, содержащих переменные типа double.

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

Нельзя недооценивать объем работы, которую нужно выполнить, чтобы сделать эти классы обобщенными. К счастью, такие библиотеки уже существуют. Одной из популярных библиотек, не входящих в STL, является Boost (zip_iterator). Ее легко использовать для самых разных классов.

Кстати, если хотите узнать о наиболее элегантном способе определения скалярного произведения в C++ и вам не особо нужна концепция итераторов-упаковщиков, то обратите внимание на std::valarray. Взгляните сами:

#include <iostream>

#include <valarray>

int main()

{

  std::valarray<double> a {1.0, 2.0, 3.0};

  std::valarray<double> b {4.0, 5.0, 6.0};

  std::cout << (a * b).sum() << 'n';

}

Библиотека ranges. Это очень интересная библиотека для языка C++, которая поддерживает упаковщики и все прочие виды волшебных адаптеров итераторов, фильтров и т.д. Ее создатели вдохновлялись библиотекой Boost ranges, и какое-то время казалось, что она может попасть в C++17, но, к сожалению, придется ждать следующего стандарта. Библиотека значительно улучшит возможности написания выразительного и быстрого кода на C++ путем создания сложных механизмов из универсальных и простых блоков кода. В документации к ней можно найти очень простые примеры.

1. Определение суммы квадратов всех чисел от 1 до 10:

const int sum = accumulate(view::ints(1)

                      | view::transform([](int i){return i*i;})

                      | view::take(10), 0);

2. Фильтрация всех четных чисел из вектора чисел и преобразование остальных чисел в строки:

std::vector<int> v {1,2,3,4,5,6,7,8,9,10};

auto rng = v | view::remove_if([](int i){return i % 2 == 1;})

             | view::transform([](int i){return std::to_string(i);});

// rng == {"2"s,"4"s,"6"s,"8"s,"10"s};

Если вы заинтересовались и не можете дождаться выхода следующего стандарта С++, то обратитесь к документации для ranges, которая находится по адресу https://ericniebler.github.io/range-v3/.

Глава 4

Лямбда-выражения

В этой главе:

□ динамическое определение функций с помощью лямбда-выражений;

□ добавление полиморфизма путем оборачивания лямбда-выражений в конструкцию std::function;

□ создание функций с помощью конкатенации;

□ создание сложных предикатов с помощью логической конъюнкции;

□ вызов нескольких функций с одними и теми же входными данными;

□ реализация transform_if с применением std::accumulate и лямбда-выражений;

□ генерация декартова произведения на основе любых входных данных во время компиляции.

Введение

 Одной из важных новых функций C++11 были лямбда-выражения. В C++14 и C++17 они получили новые возможности, и это сделало их еще мощнее. Но что же такое лямбда-выражение?

Лямбда-выражения или лямбда-функции создают замыкания. Замыкание — очень обобщенный термин для безымянных объектов, которые можно вызывать как функции. Чтобы предоставить подобную возможность в С++, такой объект должен реализовывать оператор вызова функции (), с параметрами или без. Создание аналогичного объекта без лямбда-выражений до появления С++11 выглядело бы так:

#include <iostream>

#include <string>

int main() {

  struct name_greeter {

    std::string name; void operator()() {

      std::cout << "Hello, " << name << 'n';

    }

  };

  name_greeter greet_john_doe {"John Doe"};

  greet_john_doe();

}

Экземпляры структуры name_greeter, очевидно, содержат строку. Обратите внимание: тип этой структуры и объект не являются безымянными, в отличие от лямбда-выражений. С точки зрения замыканий можно утверждать, что они захватывают строку. Когда экземпляр-пример вызывается

1 ... 31 32 33 34 35 ... 121 ВПЕРЕД
Перейти на страницу:
Комментарии (0)