Историческая справка

C++20 стал одним из самых значимых обновлений языка за последние десятилетия. После выхода C++11, который заложил фундамент для современного C++, и C++17, добавившего множество полезных улучшений, стандарт 2020 года подвёл черту под эпохой макросов и шаблонной метапрограммирования в их устаревшем виде. Идеи, обсуждавшиеся более 10 лет — такие как концепты, корутины и модули — наконец-то стали частью языка. Этот обзор C++20 позволит лучше понять, насколько кардинально изменился подход к разработке на C++.
Базовые принципы
C++20 фокусируется на улучшении выразительности, читаемости и компиляционной безопасности кода. Это достигается за счёт закрепления нескольких ключевых идей:
1. Явное ограничение шаблонов — концепты в C++20 позволяют задать точные требования к параметрам шаблонов.
2. Асинхронное программирование — корутины C++20 упростили написание логики, связанной с отложенным выполнением и потоками.
3. Инкапсуляция и ускорение сборки — модули в C++20 призваны заменить заголовочные файлы, уменьшив зависимости и время компиляции.
Каждая из этих возможностей направлена на решение реальных проблем, возникающих при разработке крупных и устойчивых систем.
Примеры реализации
Чтобы понять, как работают основные C++20 нововведения, рассмотрим практические примеры.
1. Концепты
До C++20 проверка корректности шаблонов происходила во время инстанцирования — то есть зачастую слишком поздно. Теперь можно явно указать, какие свойства должен иметь тип:
```cpp
template
concept Incrementable = requires(T x) {
++x;
};
template
void increment_all(std::vector
for (auto& v : vec) ++v;
}
```
Этот код не скомпилируется, если передать тип, не поддерживающий операцию инкремента.
2. Корутины
Ранее асинхронное выполнение приходилось реализовывать с помощью сложных шаблонов или сторонних библиотек. Корутины C++20 позволяют писать асинхронный код синхронным способом:
```cpp
task
co_return 42;
}
```
Функция выглядит как обычная, но `co_return` превращает её в корутину. Это упрощает отладку и делает код более предсказуемым.
3. Модули
Модули в C++20 позволяют избавиться от традиционных заголовочных файлов и `#include`-директив. Вместо этого используется `import`:
```cpp
// my_math.ixx
export module my_math;
export int add(int a, int b) { return a + b; }
```
```cpp
// main.cpp
import my_math;
int main() {
return add(2, 3);
}
```
Такой подход уменьшает дублирование и ускоряет компиляцию больших проектов.
Частые заблуждения
Несмотря на очевидные преимущества, вокруг новых возможностей C++20 сформировались устойчивые мифы:
1. "Концепты — это просто синтаксический сахар"
На самом деле концепты в C++20 выполняют раннюю проверку типов и могут существенно улучшить сообщения об ошибках компиляции. Они также позволяют использовать перегрузку по ограничениям, что невозможно было сделать с SFINAE.
2. "Корутины — это магия, которую трудно контролировать"
Корутины — это не потоки. Они не создают отдельные системные нити, а лишь позволяют приостанавливать и возобновлять выполнение. Их поведение полностью поддаётся контролю через пользовательские типы промисов и awaitable-объекты.
3. "Модули несовместимы с существующим кодом"
Хотя модули в C++20 требуют пересмотра структуры проекта, их можно вводить поэтапно. Они прекрасно сосуществуют с традиционными заголовочными файлами и работают как мост между старым и новым стилем организации кода.
Сравнение подходов к решению проблем

До C++20 многие задачи решались более громоздкими и менее надёжными способами. Рассмотрим несколько примеров:
1. Ограничение шаблонов
До появления концептов использовался SFINAE (Substitution Failure Is Not An Error) — техника, которая часто приводила к непонятным сообщениям об ошибках. С появлением концептов в C++20 стало возможно писать декларативные ограничения, понятные как компилятору, так и разработчику.
2. Асинхронность
Ранее асинхронный код требовал использования `std::future`, `std::thread` или сторонних библиотек. Все эти подходы сопряжены с рисками гонок данных и сложностью отладки. Корутины C++20 обеспечивают лаконичность и управляемость, не жертвуя производительностью.
3. Инкапсуляция и сборка
Система заголовочных файлов, унаследованная от C, была неэффективна при масштабировании. Модули в C++20 позволяют разработчикам точно контролировать видимость и зависимости, снижая время полной сборки в разы.
Заключение
C++20 — это не просто очередной этап эволюции языка. Это фундаментальный сдвиг в сторону выразительности, безопасности и модульности. Благодаря таким ключевым улучшениям, как концепты, корутины и модули, язык стал более пригодным для разработки масштабируемых и надёжных систем.
Если вы ещё не начали использовать C++20 нововведения, самое время пересмотреть архитектуру своих проектов. Концепты в C++20 повысят надёжность обобщённого кода, корутины C++20 упростят асинхронные вычисления, а модули в C++20 помогут структурировать большие кодовые базы. Этот обзор C++20 лишь верхушка айсберга — впереди ещё много интересного.



