Диапазоны и представления в C++20
Диапазоны (<ranges>, C++20) описывают последовательность элементов, с которой можно работать единообразно: контейнер, массив, ленивая цепочка преобразований. Связь с циклами: 13. Ограничения шаблонов: 23, 11.
:::info Стандарт
Нужен C++20 (-std=c++20). В корпоративных проектах на C++17 этот раздел — ориентир на миграцию; см. Конфигурация и сборка.
:::
Range и view
Range — всё, для чего есть begin/end (контейнер, C-массив, строка).
View — невладеющее представление: не копирует данные, вычисляет элементы по запросу (лениво). Владелец данных живёт в исходном контейнере; view не продлевает его жизнь.
#include <vector>
#include <ranges>
std::vector<int> data{10, 20, 30, 40, 50};
auto evens = data
| std::views::filter([](int x) { return x % 20 == 0; })
| std::views::transform([](int x) { return x / 10; });
for (int v : evens) { /* 1, 2, 3, 4, 5 */ }
Пайп | читается слева направо: сначала фильтр, потом преобразование. Промежуточных vector нет.
Частые представления
| View | Назначение |
|---|---|
filter | Оставить элементы по предикату |
transform | Отобразить каждый элемент |
take / drop | Первые N / пропустить N |
take_while / drop_while | Пока предикат истинен |
reverse | Обратный порядок |
keys / values | Для ассоциативных контейнеров (C++23: keys/values в std) |
Пример «топ-3 после сортировки» без копирования всего контейнера в промежуточные векторы — сортировка всё же требует материализации; для уже отсортированных данных достаточно take.
Алгоритмы ranges
В <algorithm> есть перегрузки в пространстве std::ranges:
std::vector<int> v{3, 1, 4, 1, 5};
std::ranges::sort(v);
bool found = std::ranges::binary_search(v, 4);
Итераторы передаются как один range-аргумент — меньше ошибок «перепутал begin/end».
Remove-erase через ranges (C++23)
Классика удаления по условию:
std::vector<int> v{1, 2, 3, 2, 4};
auto tail = std::ranges::remove(v, 2);
v.erase(tail.begin(), tail.end());
В C++23 — std::erase / std::erase_if для контейнеров напрямую. Идиома в целом: 30.
Проекции (C++23)
Проекция — «по какому полю сравнивать/сортировать»:
struct User { std::string name; int age; };
std::vector<User> team{ /* ... */ };
std::ranges::sort(team, {}, &User::age); // по возрасту
Третий аргумент — указатель на член или лямбда-проекция.
Опасности
-
Висячие ссылки. View на временный объект:
auto bad = std::vector{1,2,3} | std::views::reverse; // UB после ;Привязывайте view к именованному контейнеру с временем жизни длиннее использования.
-
Инвалидация итераторов.
filter/dropне меняют вектор, ноeraseпри итерации по view — ошибка. Сначала материализуйте индексы или используйте erase-идиому на контейнере. -
Производительность. Ленивость выигрывает при короткой цепочке и одном проходе; многократный проход по тому же view с тяжёлым
transformможет быть хуже одного явного цикла.
Связь с концептами
Шаблоны вроде:
template<std::ranges::input_range R>
void dump(const R& r) {
for (const auto& x : r) { /* ... */ }
}
принимают и vector, и ленивый view. Ошибки компиляции короче, чем у «голых» итераторов.
Когда оставить классический цикл
- C++17 в продакшене без планов обновления;
- критичный hot path, где профайлер показал регресс от абстракции;
- сложная логика с несколькими выходами из цикла — явный
forчитается проще.
В остальном ranges делают код ближе к декларативному стилю и снижают число временных контейнеров.
Дальше
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). C++ как язык системного программирования - ключевые принципы, область применения и инженерные требования к коду. Экосистема приложений на C++ - области применения языка от системного ПО до высоконагруженных вычислений. C++ — это мощный язык программирования общего назначения, который обеспечивает прямой доступ к аппаратным ресурсам компьютера при сохранении высокой производительности. Гайд по установке и настройке с написанием первой программы и её запуском. Директива препроцессора include используется для подключения заголовочных файлов в исходный код. Она сообщает компилятору вставить содержимое указанного файла в текущее место перед началом компиляции. Конфигурация — это набор правил и переменных, которые управляют процессом превращения исходного текста в исполняемый продукт. Примеры простых и полезных консольных приложений с демонстрацией концепций языка. Минимальный кроссплатформенный проект C++17 с CMake — структура, сборка и разбор CMakeLists построчно. Модульные тесты с GTest и Catch2 в CMake-проекте — зачем отдельный target, примеры и запуск ctest. Набор мини-проектов для закрепления C++ — консоль, RAII, CMake, Qt, ranges и опционально Vulkan. Набор советов, правил, принципов и обычаев в разработке на этом языке. Типизация, набор правил определения типа данных значений языка.C++ - язык системного программирования
Экосистема приложений на C++
Что требуется знать перед началом изучения языка программирования C++
Первая программа на C++
Начало работы с C++
Конфигурация и сборка в C++
Простые приложения на C++
CMake — первая программа
Google Test и Catch2 в C++
Практические задания по C++
Рекомендации по разработке на C++
Типы данных в C++