C++ стремится начать это десятилетие так же, как и в прошлом, с изменений, захватывающих дух. Последняя версия C++ - C++20 - вводит множество новых функций, которые успешно прошли заключительные этапы утверждения комитетом. Официальная публикация ожидается в течение ближайших нескольких месяцев.
С приближением этого обновления у каждой компании есть прекрасная возможность обновить свою кодовую базу и воспользоваться преимуществами этих значительных улучшений языка. Однако начало этого процесса вызывает ряд важных вопросов. Помогут ли изменения в стандарте вашему бизнесу? Как лучше всего выполнить обновление? Есть ли подводные камни, на которые следует обратить внимание в процессе перехода? Эта статья ответит на все эти вопросы. Но сначала давайте посмотрим, что нового в C ++ 20.
Переход на C ++ 20
Почти десять лет назад C ++ 11 стал первым крупным шагом вперед после долгого периода незначительных изменений. Он предлагает ряд существенных новых функций, таких как семантика перемещения и лямбда-выражения. И C ++ 14, и C ++ 17 внесли важные инкрементные изменения в язык, хотя не все обновились, потому что изменения не были столь важными. C ++ 20 уточняет некоторые функции, представленные в предыдущих версиях стандарта, с учетом преимуществ ретроспективного анализа, а также было добавлено множество новых функций. Описанных ниже обновлений может быть достаточно, чтобы убедить вас в том, что настало время для перехода.
Модули
C ++ 20 теперь предоставляет стандартизированный механизм для повторного использования кода, который отражает то, что доступно на других языках, таких как Java и C #. Этот механизм называется модулем, и он явно экспортирует классы и функции, к которым будет разрешен доступ коду вне модуля. Весь остальной код остается закрытым для самого модуля. Затем другие модули или файлы кода могут импортировать модуль и импортировать предоставляемые им функции.
Модули значительно уменьшают зависимость от препроцессора и заголовочных файлов. Это делает ваш код более безопасным, так как он не подвержен таким проблемам, как порядок файлов #include. Это также сильно ускоряет сборку, потому что модули компилируются один раз, а не каждый раз, когда они включены. Так же происходит и с обычными заголовочными файлами. При импорте заголовочного файла вместо использования #include он будет вести себя так же, как и предварительно скомпилированный заголовок.
Ниже приведен простой пример импорта и экспорта модулей:
Концепции
Комитет C ++ уже довольно давно работает над упрощением ограничений для классов и методов шаблонов, и наконец решение для C ++ 20 было ратифицировано. Концепции используются, чтобы гарантировать, что выражения, включающие данный тип, гарантированно скомпилируются, а не демонстрируют поведение SFINAE.
Нарушение концепций приводит к появлению сообщений об ошибках, которые гораздо легче понять и устранить, чем обычные ошибки, связанные с шаблоном. Обнаружение этих проблем на ранней стадии помогает гарантировать, что ваше приложение будет работать именно так, как вы предполагали. Концепции также могут использоваться для ограничения типов, принимаемых функцией auto, что позволяет вам осуществлять больший контроль над типами, которые вы хотите, чтобы данная функция принимала.
Ниже приведен пример того, как ограничить тип, принятый функцией, используя понятия в g++ 9.3.0:
template<typename T>
concept Container = requires(T value) {
{ value.size() } -> std::size_t;
};
size_t size(Container& value) {
return value.size(); }
Сопрограммы
Асинхронное программирование и ленивое вычисление стало намного проще реализовать благодаря сопрограммам, представленным в C ++ 20. Сопрограммы могут использоваться для существенной приостановки выполнения функции и возврата управления обратно вызывающей стороне без потери вызываемой функцией своего текущего состояния. Это позволяет возобновить работу функции в будущем, начав с того же места, где она была остановлена. Для сопрограмм обратные вызовы не требуются. Вместо этого вы можете просто передать управление другим функциям по мере необходимости.
Сопрограммы C ++ 20 отличаются от реализаций только для библиотек, таких как Boost.Coroutines и Boost.Fibers тем, что они не стековые. Вместо того, чтобы требовать независимый стек для каждого вызова сопрограммы, сопрограммы без стека повторно используют стек вызывающей стороны и выделяют данные, необходимые для повторной активации сопрограммы в куче. В итоге это оказывается намного более эффективным с точки зрения использования памяти и переключения контекста.
Диапазоны
Диапазоны имеют огромное значение в том, как мы работаем с наборами данных, поскольку они дают пользователям возможность фильтровать и преобразовывать данные через конвейер. Диапазоны также делают пары итераторов в значительной степени ненужными, уменьшая необходимость написания кода, подверженного ошибкам. Знакомый оператор " | " используется для передачи данных из одной части конвейера в другую, что позволяет легко создавать различные конвейеры из общего набора примитивных функций.
Ниже приведен пример использования диапазонов для ленивой оценки конвейера данных над коллекцией в++ 10:
#include <iostream>
#include <ranges>
#include <vector>
int
main () {
using std::views::filter,
std::views::transform,
std::views::reverse;
// Некоторые данные для работы
std::vector<int> numbers = { 6, 5, 4, 3, 2, 1 };
//Лямбда-функция, обеспечивающая фильтрование
auto is_even = [](int n) { return n % 2 == 0; };
// Обработка нашего набора данных
auto results = numbers | filter(is_even)
| transform([](int n){ return n++; })
| reverse;
// Используйте отложенные вычисления для вывода результатов на экран
for (auto v: results) {
std::cout << v << ” “; // Вывод: 2 4 6
}
}
Мелкие Особенности
Есть множество полезных функций в C++20. Например, оператор космического корабля (т. е.<=>), который также может быть установлен по умолчанию, предлагает вам единственную функцию для реализации трехсторонних сравнений. Затем компилятор может использовать эту функцию для автоматического создания всех других вариантов оператора сравнения для вас.
C ++ 20 также добавляет ряд усовершенствований к тому, что может быть достигнуто во время компиляции. В то время как функции constexpr незаметно меняются во время выполнения при передаче непостоянных аргументов, новое ключевое слово consteval рассматривает это как ошибку. И строка, и вектор также были адаптированы для использования в функциях constexpr. Функции Contexpr теперь могут быть виртуальными, и они могут использовать блоки try / catch.
Как подготовиться к переходу?
Переход на C ++ 20 может оказаться серьезным делом в зависимости от того, какую версию C ++ вы используете в настоящее время, и от размера вашей кодовой базы. Ваша зависимость от сторонних зависимостей также может повлиять на переход, потому что их может потребоваться обновить или изменить для правильной компиляции в C ++ 20. Количество работы, необходимой для решения этих проблем, в конечном итоге определит, стоит ли польза от краткосрочного перехода затраченных усилий.
Важно выполнить первоначальную оценку новых функций C ++ 20, чтобы определить, насколько они соответствуют вашим потребностям в использовании. Например, если вы в настоящее время используете библиотечное решение для сопрограмм и вас соблазняет собственное решение, предоставляемое C ++ 20, напишите некоторый тестовый код, чтобы узнать, действительно ли новая реализация дает вам преимущество, вместо того, чтобы оставлять эту оценку до тех пор, пока вы не приложите все усилия, необходимые для изменения кода. Вы можете обнаружить, что эта функция не работает так, как вам нужно.
Перед созданием новой сборки вашей кодовой базы важно убедиться, что все ваши сторонние зависимости будут продолжать работать в обновленном компиляторе. Изменения в стандартной библиотеке и ABI могут вызвать проблемы, если вы попытаетесь использовать несколько версий одного и того же компилятора, и это до упоминания об использовании разных компиляторов. Решение этой проблемы в первую очередь приблизит вас к успешному переходу и позволит заранее выявить несоответствия.
Ниже приведены пять советов, которые помогут вам подготовиться к успешному переходу на C++ 20:
- Попробуйте новые функции. Разветвите свою кодовую базу и поэкспериментируйте с тем, как новые функции в C++20 могут повысить ценность. Это даст вам возможность понять, как работают эти функции и каковы их ограничения.
- Обеспечьте стороннюю библиотечную поддержку. В дополнение к компиляции собственного кода вам нужно будет гарантировать дальнейшее использование сторонних библиотек, от которых вы зависите. Если вы ранее создавали эти библиотеки из исходного кода, убедитесь, что они по-прежнему правильно собираются в C++20.
- Создайте свою кодовую базу. GCC, Clang и Microsoft Visual C++ обеспечивают различную степень поддержки C++20. Использование правильных флагов компилятора для вашей среды, таких как -std=c++2a, может помочь обеспечить успешную сборку.
- Устранение неполадок компиляции. Проблемы компиляции могут возникнуть в результате введения новых ключевых слов в язык, изменений в стандартных библиотеках и устаревших/удаленных функций. Имейте в виду, что компиляторы обычно различаются тем, насколько тщательно они предупреждают пользователей об устаревшем использовании функций.
- Проверьте правильность и производительность. Очень важно на самом деле использовать свой код, чтобы быть уверенным, что все работает правильно. Наличие автоматизированного тестирования и конвейеров CI/CD определенно поможет, как и запуск теста на стабильность.
Заключение
Достижения C++20 в области языкового стандарта C++ облегчают и ускоряют развертывание приложений. В некоторых случаях может быть трудно перейти на C++20 при работе с устаревшими кодовыми базами. Это риск возникновения проблем после миграции, которые могут возникнуть из-за отсутствия автоматизированного тестирования. Однако в большинстве случаев переход на C++20 расширит ваши горизонты.
Хотя эта статья была посвящена основным изменениям в C++20, само количество и масштаб небольших изменений и улучшений языка означают, что в этом обновлении есть что-то полезное для всех. Некоторые из этих изменений, такие как введение шаблонных лямбд, сделают ваш код менее многословным, не жертвуя читабельностью.
Лучший способ начать работу с C++20 - это опробовать некоторые из новых функций и оценить их полезность для вашей конкретной среды. Практический опыт работы с обновленным языком позволит вам легче оправдать усилия по переходу для вашей команды, когда придет время сделать это. Поскольку C++ движется вперед семимильными шагами, оставаться в курсе событий – по крайней мере, с основными версиями, такими как эта, – крайне важно.
Автор: Дори Экстерман
Опытный разработчик программного обеспечения и стратег по продуктам, Дори Экстерман имеет 20-летний опыт работы в индустрии разработки программного обеспечения. Как технический директор Incredibuild, он руководит продуктовой стратегией компании и отвечает за видение продукта, внедрение и техническое партнерство. До прихода в Incredibuild Дори занимал различные технические и продуктовые должности в компаниях-разработчиках программного обеспечения, уделяя особое внимание архитектуре, производительности, передовым технологиям, DevOps, управлению релизами и C++. Он является экспертом и часто выступает с докладами о технологическом прогрессе в области инструментов разработки.