Литвек - электронная библиотека >> Яцек Галовиц >> Базы данных >> C++17 STL Стандартная библиотека шаблонов >> страница 4
время компиляции с помощью constexpr-if;

□ подключение библиотек, перечисленных в заголовочных файлах, с использованием встраиваемых переменных;

□ реализация вспомогательных функций с помощью выражений свертки.

Введение

Функциональность языка C++ значительно расширилась с выходом C++11, C++14 и недавней версии C++17. На текущий момент он совсем не похож на себя образца десятилетней давности. Стандарт С++ упорядочивает не только язык, но и STL.

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

Мы рассмотрим, как получить доступ к отдельным элементам пар, кортежей и структур с помощью структурированных привязок и ограничить область видимости переменных благодаря новым возможностям по инициализации переменных внутри выражений if и switch. Синтаксические двусмысленности, появившиеся в C++11 из-за нового синтаксиса инициализатора с фигурными скобками, который выглядит так же, как синтаксис списков инициализаторов, были исправлены в новых правилах инициализатора с фигурными скобками. Точный тип экземпляра шаблонного класса может быть определен по аргументам, переданным его конструктору, а если разные специализации шаблонного класса выполняются в разном коде, то это легко выразить с помощью constexpr-if. Обработка переменного количества параметров в шаблонных функциях значительно упростилась благодаря новым выражениям свертки. Наконец, стало гораздо удобнее определять доступные глобально статические объекты в библиотеках, указанных в заголовочных файлах, благодаря новой возможности объявлять встраиваемые переменные, что ранее было выполнимо только для функций.

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

Применяем структурированные привязки (декомпозицию) для распаковки набора возвращаемых значений

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


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

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


1. Получаем доступ к отдельным значениям std::pair. Представьте, что у нас есть математическая функция divide_remainder, которая принимает в качестве параметров делимое и делитель и возвращает частное и остаток в std::pair.


std::pair<int, int> divide_remainder(int dividend, int divisor);


Рассмотрим следующий способ получения доступа к отдельным значениям полученной пары.


const auto result (divide_remainder(16, 3));

std::cout << "16 / 3 is "

          << result.first << " with a remainder of "

          << result.second << '\n';


Вместо выполнения действий, показанных во фрагменте выше, мы теперь можем присвоить отдельные значения конкретным переменным с говорящими именами, что более удобочитаемо:


auto [fraction, remainder] = divide_remainder(16, 3);

std::cout << "16 / 3 is "

          << fraction << " with a remainder of "

          << remainder << '\n';


2. Структурированные привязки работают и для std::tuple. Рассмотрим следующий пример функции, которая возвращает информацию о ценах на акции:


std::tuple<std::string,

           std::chrono::system_clock::time_point, unsigned>

stock_info(const std::string &name);


Присваивание результата ее работы отдельным переменным выглядит так же, как и в предыдущем примере:


const auto [name, valid_time, price] = stock_info("INTC");


3. Декомпозицию можно применять и для пользовательских структур. В качестве примера создадим следующую структуру.


struct employee {

    unsigned id;

    std::string name;

    std::string role;

    unsigned salary;

};


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


int main()

{

  std::vector<employee> employees {

  /* Инициализируется в другом месте */};

  for (const auto &[id, name, role, salary] : employees) {

    std::cout << "Name: " << name

              << "Role: " << role

              << "Salary: " << salary << '\n';

  }


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

Структурированные привязки всегда применяются по одному шаблону:


auto [var1, var2, ...] = <выражение пары, кортежа, структуры или массива>;


□ Количество переменных var1, var2... должно точно совпадать с количеством переменных в выражении, в отношении которого выполняется присваивание.

□ Элементом <выражение пары, кортежа, структуры или массива> должен быть один из следующих объектов:

  • std::pair;

  • std::tuple;

  • структура. Все члены должны быть нестатическими и определенными в одном базовом классе. Первый объявленный член присваивается первой переменной, второй член — второй переменной и т.д.;

  • массив фиксированного размера.

□ Тип может иметь модификаторы auto, const auto, const auto& и даже auto&&. 


 C++17 STL Стандартная библиотека шаблонов. Иллюстрация № 3 При необходимости пользуйтесь ссылками, а не создавайте копии. Это важно не только с точки зрения производительности.


Если в квадратных скобках вы укажете слишком мало или слишком много переменных, то компилятор выдаст ошибку.


std::tuple<int, float, long> tup {1, 2.0, 3};

auto [a, b] = tup; // Не работает


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


error: type 'std::tuple<int, float, long>' decomposes into 3 elements,

but only 2 names were provided

auto [a, b] = tup;


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

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


std::map<std::string, size_t> animal_population {

  {"humans", 7000000000},

  {"chickens", 17863376000},

  {"camels", 24246291},