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

Тут можно читать бесплатно C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц. Жанр: Компьютеры и Интернет / Программирование. Так же Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте «WorldBooks (МирКниг)» или прочесть краткое содержание, предисловие (аннотацию), описание и ознакомиться с отзывами (комментариями) о произведении.
C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц

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

Прочтите описание перед тем, как прочитать онлайн книгу «C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц» бесплатно полную версию:

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

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

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

выражений свертки (пример, связанный с выражениями свертки, мы рассмотрим далее в этой главе). Полученная сумма сохраняется в переменную-член value. Теперь вопрос заключается в том, что за тип — T? Если мы не хотим указывать его явно, то ему следует зависеть от типов значений, переданных в конструктор. В случае передачи объектов-строк тип должен быть std::string. При передаче целых чисел тип должен быть int. Если мы передадим целые числа, числа с плавающей точкой и числа с удвоенной точностью, то компилятору следует определить, какой тип подходит всем значениям без потери точности. Для этого мы предоставляем явные правила выведения типов:

template <typename ... Ts>

sum(Ts&& ... ts) -> sum<std::common_type_t<Ts...>>;

Согласно этим правилам компилятор может использовать типаж std::common_ type_t, который способен определить, какой тип данных подходит всем значениям. Посмотрим, как его применить:

sum s {1u, 2.0, 3, 4.0f};

sum string_sum {std::string{"abc"}, "def"};

std::cout << s.value << '\n'

          << string_sum.value << '\n';

В первой строке мы создаем объект типа sum на основе аргументов конструктора, имеющих типы unsigned, double, int и float. Типаж std::common_type_t возвращает тип double, поэтому мы получаем объект типа sum<double>. Во второй строке мы предоставляем экземпляр типа std::string и строку в стиле C. В соответствии с нашими правилами компилятор создает экземпляр типа sum<std::string>.

При запуске этот код выведет значение 10 как результат сложения чисел и abcdef в качестве результата объединения строк.

Упрощаем принятие решений во время компиляции с помощью constexpr-if

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

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

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

1. Напишем обобщенную часть кода. В нашем примере рассматривается простой класс, который добавляет значение типа U к элементу типа T с помощью функции add:

template <typename T>

class addable

{

  T val;

public:

  addable(T v) : val{v} {}

  template <typename U>

  T add(U x) const {

    return val + x;

  }

};

2. Представим, что тип T — это std::vector<что-то>, а тип U — просто int. Каков смысл выражения «добавить целое число к вектору»? Допустим, нужно добавить данное число к каждому элементу вектора. Это делается в цикле:

template <typename U>

T add(U x)

{

  auto copy (val); // Получаем копию элемента вектора

  for (auto &n : copy) {

    n += x;

  }

  return copy;

}

3. Следующий и последний шаг заключается в том, чтобы объединить оба варианта. Если T — это вектор, состоящий из элементов типа U, то выполняем цикл. В противном случае выполняем обычное сложение.

template <typename U>

T add(U x) const {

  if constexpr (std::is_same_v<T, std::vector<U>>) {

    auto copy (val);

    for (auto &n : copy) {

      n += x;

    }

    return copy;

  } else {

    return val + x;

  }

}

4. Теперь класс можно использовать. Посмотрим, насколько хорошо он может работать с разными типами, такими как int, float, std::vector<int> и std::vector<string>:

addable<int>{1}.add(2);               // результат - 3

addable<float>{1.0}.add(2);           // результат - 3.0

addable<std::string>{"aa"}.add("bb"); // результат - "aabb"

std::vector<int> v {1, 2, 3};

addable<std::vector<int>>{v}.add(10);

  // is std::vector<int>{11, 12, 13}

std::vector<std::string> sv {"a", "b", "c"};

addable<std::vector<std::string>>{sv}.add(std::string{"z"});

  // is {"az", "bz", "cz"}

Как это работает

Новая конструкция constexpr-if работает точно так же, как и обычные конструкции if-else. Разница между ними заключается в том, что значение условного выражения определяется во время компиляции. Весь код завершения, который компилятор сгенерирует из нашей программы, не будет содержать дополнительных ветвлений, относящихся к условиям constexpr-if. Кто-то может сказать, что эти механизмы работают так же, как и макросы препроцессора #if и #else, предназначенные для подстановки текста, но в данном случае всему коду даже не нужно быть синтаксически правильным. Ветвления конструкции constexpr-if должны быть синтаксически правильными, но неиспользованные ветви не обязаны быть семантически корректными.

Чтобы определить, должен ли код добавлять значение х к вектору, задействуем типаж std::is_same. Выражение std::is_same<A, B>::value вычисляется в логическое значение true, если A и B имеют один и тот же тип. В нашем примере применяется условие std::is_same<T, std::vector<U>>::value, которое имеет значение true, если пользователь конкретизировал шаблон для класса T = std::vector<X> и пробует вызвать функцию add с параметром типа U = X.

В одном блоке constexpr-if-else может оказаться несколько условий (обратите внимание, что a и b должны зависеть от параметров шаблона, а не только от констант времени компиляции):

if constexpr (a) {

  // что-нибудь делаем

} else if constexpr (b) {

  // делаем что-нибудь еще

} else {

  // делаем нечто совсем другое

}

С помощью C++17 гораздо легче как выразить, так и прочитать код, получающийся при метапрограммировании.

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

Для того чтобы убедиться, каким прекрасным новшеством являются конструкции constexpr-if для C++, взглянем, как решалась та же самая задача до С++17:

template <typename T>

class addable

{

  T val;

public:

  addable(T v) : val{v} {} template <typename U>

  std::enable_if_t<!std::is_same<T, std::vector<U>>::value, T>

  add(U x) const { return val + x; }

  template <typename U>

  std::enable_if_t<std::is_same<T, std::vector<U>>::value,

                   std::vector<U>>

  add(U x) const {

    auto copy (val);

    for (auto &n : copy) {

     

Перейти на страницу:
Вы автор?
Жалоба
Все книги на сайте размещаются его пользователями. Приносим свои глубочайшие извинения, если Ваша книга была опубликована без Вашего на то согласия.
Напишите нам, и мы в срочном порядке примем меры.
Комментарии / Отзывы
    Ничего не найдено.