Выбрать главу

□ новые правила инициализатора с фигурными скобками;

□ разрешение конструктору автоматически вывести полученный тип класса шаблона;

□ упрощение принятия решений во время компиляции с помощью 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);

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