Библиотека диапазонов (C++20)
Библиотека диапазонов является расширением и обобщением библиотек алгоритмов и итераторов, что делает их более мощными, составными и менее подверженным ошибкам.
Библиотека создаёт и управляет представлениями диапазонов, облегчёнными объектами, которые косвенно представляют итерируемые последовательности (диапазонов). Диапазоны это абстракция над
- пары итераторов [начало, конец), например диапазоны, созданные неявным преобразованием из контейнеров. Все алгоритмы, использующие пары итераторов, теперь имеют перегрузки, которые принимают диапазоны (например, ranges::sort)
- подсчитанные последовательности [начало, размер), т.е. диапазон, возвращённый views::counted
- условно-завершённые последовательности [начало, предикат), например диапазон, возвращаемый views::take_while
- неограниченные последовательности [начало..), например диапазон, возвращённый views::iota
Библиотека диапазонов включает алгоритмы диапазонов, которые применяются к диапазонам активно, и адаптеры диапазонов, которые применяются к представлениям лениво. Адаптеры могут быть объединены в конвейеры, чтобы их действия происходили по мере повторения представления.
| Определено в заголовочном файле <ranges>
|
||
| namespace std { namespace views = ranges::views; |
(начиная с C++20) | |
Псевдоним пространства имён std::views предоставляется как сокращение для std::ranges::views.
| Определены в пространстве имён
std::ranges | ||
Доступ к диапазонам | ||
| Определены в заголовочном файле
<ranges> | ||
| Определены в заголовочном файле
<iterator> | ||
| (C++20) |
возвращает итератор на начало диапазона (объект точки настройки) | |
| (C++20) |
возвращает ограничитель, указывающий на конец диапазона (объект точки настройки) | |
| (C++20) |
возвращает итератор на начало диапазона только для чтения (объект точки настройки) | |
| (C++20) |
возвращает ограничитель, указывающий на конец диапазона, доступного только для чтения (объект точки настройки) | |
| (C++20) |
возвращает обратный итератор на диапазон (объект точки настройки) | |
| (C++20) |
возвращает обратный конечный итератор диапазона (объект точки настройки) | |
| (C++20) |
возвращает обратный итератор на диапазон только для чтения (объект точки настройки) | |
| (C++20) |
возвращает обратный конечный итератор на диапазон только для чтения (объект точки настройки) | |
| (C++20) |
возвращает целое число, равное размеру диапазона (объект точки настройки) | |
| (C++20) |
возвращает целое число со знаком, равное размеру диапазона (объект точки настройки) | |
| (C++20) |
проверяет, пуст ли диапазон (объект точки настройки) | |
| (C++20) |
получает указатель на начало непрерывного диапазона (объект точки настройки) | |
| (C++20) |
получает указатель на начало непрерывного диапазона, доступного только для чтения (объект точки настройки) | |
Примитивы диапазонов | ||
| Определены в заголовочном файле
<ranges> | ||
| (C++20) (C++23) (C++20) (C++23) (C++20) (C++20) (C++20) (C++20) (C++23) (C++20) (C++20) |
получает ассоциированные типы диапазона (псевдоним шаблона) | |
Обработка висячих итераторов | ||
| Определены в заголовочном файле
<ranges> | ||
| (C++20) |
тип заполнителя, указывающий, что итератор или поддиапазон не должны быть возвращены, так как они будут висячими (класс) | |
получает тип итератора или тип поддиапазона из borrowed_range (псевдоним шаблона) | ||
Концепты диапазонов | ||
| Определены в заголовочном файле
<ranges> | ||
| (C++20) |
указывает, что тип является диапазоном, то есть предоставляет итератор begin и ограничитель end (концепт) | |
| (C++20) |
указывает, что тип является range, и итераторы, полученные из его выражения, могут быть безопасно возвращены без опасности зависания (концепт) | |
| (C++20) |
указывает, что диапазон узнаёт свой размер за константное время (концепт) | |
| (C++20) |
указывает, что диапазон является представлением, то есть имеет постоянное время копирования/перемещения/присваивания (концепт) | |
| (C++20) |
указывает диапазон, тип итератора которого соответствует input_iterator (концепт) | |
| (C++20) |
указывает диапазон, тип итератора которого соответствует output_iterator (концепт) | |
| (C++20) |
указывает диапазон, тип итератора которого соответствует forward_iterator (концепт) | |
| (C++20) |
указывает диапазон, тип итератора которого соответствует bidirectional_iterator (концепт) | |
| (C++20) |
указывает диапазон, тип итератора которого соответствует random_access_iterator (концепт) | |
| (C++20) |
указывает диапазон, тип итератора которого соответствует contiguous_iterator (концепт) | |
| (C++20) |
указывает, что диапазон имеет идентичные типы итератора и ограничителя (концепт) | |
| (C++20) |
определяет требования к range для безопасного преобразования в view (концепт) | |
Преобразования диапазонов | ||
| Определены в заголовочном файле
<ranges> | ||
| (C++23) |
создаёт непросматриваемый объект из входного диапазона (шаблон функции) | |
Представления | ||
| Определены в заголовочном файле
<ranges> | ||
| (C++20) |
шаблон вспомогательного класса для определения view, используя любопытно повторяющийся образец шаблон (шаблон класса) | |
| (C++20) |
объединяет пару итератор-ограничитель в view (шаблон класса) | |
[править] Фабрики диапазонов
| Определены в заголовочном файле
<ranges> | |
| Определены в пространстве имён
std::ranges | |
пустой view без элементов (шаблон класса) (шаблонная переменная) | |
view, который содержит единственный элемент указанного значения (шаблон класса) (объект точки настройки) | |
| (C++20) |
view, состоящий из последовательности, сгенерированной путём многократного увеличения начального значения (шаблон класса) (объект точки настройки) |
view, состоящий из элементов, полученных последовательным применением operator>> к соответствующему входному потоку (шаблон класса) (объект точки настройки) | |
view, состоящее из последовательности сгенерированной путём повторного создания одного и того же значения (шаблон класса) (объект точки настройки) | |
view, состоящее из кортежей результатов, вычисленных с помощью n-арного декартова произведения адаптированных представлений (шаблон класса) (объект точки настройки) | |
[править] Адаптеры диапазонов
| Определены в заголовочном файле
<ranges> | |
| Определены в пространстве имён
std::ranges | |
| (C++20) |
view, который включает все элементы range (псевдоним шаблона) (объект адаптера диапазона) |
| (C++20) |
view из элементов некоторого другого range (шаблон класса) |
| (C++20) |
view с уникальным владельцем некоторого range (шаблон класса) |
view, который состоит из элементов range, который соответствует предикату (шаблон класса) (объект адаптера диапазона) | |
view последовательности, которая применяет функцию преобразования к каждому элементу (шаблон класса) (объект адаптера диапазона) | |
| (C++20) |
view, состоящий из первых N элементов другого view (шаблон класса) (объект адаптера диапазона) |
view, состоящий из начальных элементов другого view, до первого элемента, для которого предикат не вернёт false (шаблон класса) (объект адаптера диапазона) | |
| (C++20) |
view, состоящий из элементов другого view, пропуская первые N элементов (шаблон класса) (объект адаптера диапазона) |
view, состоящий из элементов другого view, пропуская начальную подпоследовательность элементов до первого элемента, для которого предикат вернет false (шаблон класса) (объект адаптера диапазона) | |
| (C++20) |
view, состоящий из последовательности, полученной уплотнением view, состоящего из range (шаблон класса) (объект адаптера диапазона) |
view по поддиапазонам, полученным в результате разделения другого view с использованием разделителя (шаблон класса) (объект адаптера диапазона) | |
view по поддиапазонам, полученным в результате разделения другого view с использованием разделителя (шаблон класса) (объект адаптера диапазона) | |
| (C++20) |
создаёт поддиапазон из итератора и счётчика (объект точки настройки) |
преобразует view в common_range (шаблон класса) (объект адаптера диапазона) | |
view, который перебирает элементы другого двунаправленного представления в обратном порядке (шаблон класса) (объект адаптера диапазона) | |
принимает view, состоящий из значений, подобных кортежу, и числа N, и создаёт view из N-го элемента каждого кортежа (шаблон класса) (объект адаптера диапазона) | |
| (C++20) |
принимает view, состоящий из парных значений, и создаёт view первых элементов каждой пары (шаблон класса) (объект адаптера диапазона) |
принимает view, состоящий из парных значений, и создаёт view из вторых элементов каждой пары (шаблон класса) (объект адаптера диапазона) | |
| (C++23) |
view, состоящий из кортежей ссылок на соответствующие элементы адаптированных представлений (шаблон класса) (объект точки настройки) |
view, состоящий из кортежей результатов применения функции преобразования к соответствующим элементам адаптированных представлений (шаблон класса) (объект точки настройки) | |
view, состоящий из кортежей ссылок на соседние элементы адаптированного представления (шаблон класса) (объект адаптера диапазона) | |
view, состоящий из кортежей результатов применения функции преобразования к смежным элементам адаптированного представления (шаблон класса) (объект адаптера диапазона) | |
view, состоящее из последовательности, полученной путём выравнивания представления диапазонов, с разделителем между элементами (шаблон класса) (объект адаптера диапазона) | |
view, элемент Mый которого является view над Mый через (M + N - 1)ый элементы другого view (шаблон класса) (объект адаптера диапазона) | |
диапазон нескольких view, которые представляют собой неперекрывающиеся последовательные фрагменты элементов другого view размера N (шаблон класса) (объект адаптера диапазона) | |
разбивает view на поддиапазоны между каждой парой смежных элементов, для которых данный предикат возвращает false (шаблон класса) (объект адаптера диапазона) | |
преобразует view в constant_range (шаблон класса) (объект адаптера диапазона) | |
view последовательность, которая приводит каждый элемент к rvalue (шаблон класса) (объект адаптера диапазона) | |
view, состоящее из элементов другого view, перемещаюемся по N элементам за раз (шаблон класса) (объект адаптера диапазона) | |
[править] Генераторы диапазонов
| Определены в заголовочном файле
<generator> | |
| Определены в пространстве имён
std | |
| (C++23) |
view, представляющий синхронный генератор сопрограмм (шаблон класса) |
[править] Объекты замыкания адаптеров диапазонов
Объекты замыкания адаптеров диапазонов это объекты, тип которых совпадает с типом одного из следующих объектов (без учёта cv-квалификации):
- унарные объекты адаптеров диапазонов,
|
(начиная с C++23) |
- результаты привязки конечных аргументов объектами адаптеров диапазонов, и
- результаты объединения двух объектов замыкания адаптеров диапазонов с помощью operator|.
Объекты замыкания адаптеров диапазонов принимают один viewable_range в качестве единственного аргумента и возвращают view. Их можно вызвать с помощью оператора конвейера: если C объект замыкания адаптера диапазона, а R это viewable_range, эти два выражения эквивалентны:
C(R) R | C
Этот вызов перенаправляет связанные аргументы (если есть) в связанный объект адаптера диапазона. В этом вызове связанные аргументы в C (если есть) идентично обрабатываются как левостороннее или правостороннее значение и cv-квалифицированы как C.
Два объекта замыкания адаптеров диапазонов могут быть связаны с помощью operator| для создания другого объекта замыкания адаптеров диапазонов: если C и D являются объектами замыкания адаптеров диапазонов, то C | D также является объектом замыкания адаптеров диапазонов, если это допустимо.
Связанные аргументы C | D определяются следующим образом:
- в объекте результата есть субъект того же типа (cv-квалификация отброшена) для каждого подобъекта в обоих операндах, который является связанным аргументом,
- такой связанный аргумент инициализируется напрямую, без списка инициализации, с исходным подобъектом в содержащем его операнде, где источник идентично обрабатывается как левостороннее или правостороннее значение и cv-квалифицируется как операнд,
- результат действителен тогда и только тогда, когда правильна инициализация всех связанных аргументов.
Эффект и валидность результата operator() определяется следующим образом: при viewable_range R эти два выражения эквивалентны (оба правильно или неправильно сформированы):
R | C | D // (R | C) | D R | (C | D)
Примечание: operator() не поддерживается для версий типов замыкания объектов адаптеров диапазонов с квалификацией volatile или const volatile.
|
Пусть
Можно создать определяемый пользователем объект замыкания адаптера диапазона, следуя приведённым выше требованиям. Запустить этот код #include <ranges> #include <algorithm> struct TakeTripleAndReverse : std::ranges::range_adaptor_closure<TakeTripleAndReverse> { template <std::ranges::viewable_range R> requires std::ranges::bidirectional_range<R> constexpr auto operator()(R&& r) const { return std::forward<R>(r) | std::views::take(3) | std::views::reverse; } }; inline constexpr TakeTripleAndReverse take_triple_and_reverse {}; template <typename R, typename T> constexpr bool equal_to(R&& r, std::initializer_list<T> il) { return std::ranges::equal(r, il); } int main() { static constexpr int arr[] = {6, 2, 8, 4, 4, 2}; static constexpr auto plus_one = std::views::transform([](int n){ return n + 1; }); static_assert(equal_to(take_triple_and_reverse(arr), {8, 2, 6})); static_assert(equal_to(arr | take_triple_and_reverse, {8, 2, 6})); static_assert(equal_to(arr | take_triple_and_reverse | plus_one, {9, 3, 7})); static_assert(equal_to(arr | plus_one | take_triple_and_reverse, {9, 3, 7})); } |
(начиная с C++23) |
[править] Объекты адаптеров диапазонов
Объекты адаптера диапазона это объекты точек настройки, которые принимают viewable_range в качестве своих первых аргументов и возвращают view. Некоторые объекты адаптера диапазона являются унарными, т.е. они принимают один viewable_range в качестве единственного аргумента. Другие объекты адаптера диапазона принимают viewable_range и другие завершающие аргументы.
Если объект адаптера диапазона принимает более одного аргумента, он также поддерживает частичное применение: пусть
- a является таким объектом адаптера диапазона, и
- args... аргументы (обычно подходят для конечных аргументов),
выражение a(args...) имеет следующие свойства:
- оно действительно тогда и только тогда, когда для каждого аргумента e в args... такого, что
Eесть decltype((e)), std::is_constructible_v<std::decay_t<E>, E> равно true, - когда вызов действителен, его результирующий объект сохраняет подобъект типа std::decay_t<E> не инициализированного непосредственно списком с std::forward<E>(e), для каждого аргумента e в args... (другими словами, объекты адаптера диапазона связывают аргументы по значению), и
- результирующий объект представляет собой объект замыкания адаптера диапазона.
Как и другие объекты точки настройки, пусть
- a объект cv-неквалифицированной версии типа любых объектов адаптеров диапазонов,
- args... любая группа аргументов, соответствующая ограничениям operator() типа a,
вызовы
все эквивалентны.
Объектом результата каждого из этих выражений является либо объект view, либо объект замыкания адаптера диапазона.
Примечания: operator() не поддерживается для volatile-квалифицированной или const-volatile-квалифицированной версии типов объектов адаптеров диапазонов. Массивы и функции преобразуются в указатели при привязке.
[править] Перемещаемая обёртка
Некоторые адаптеры диапазона упаковывают свои элементы или объекты функций в перемещаемую обёртку.
[править] Нераспространяющийся кеш
Некоторые адаптеры диапазона указаны в терминах шаблона класса non-propagating-cache только для описания, который ведёт себя почти так же, как std::optional<T> (отличия смотрите в описании).
| Этот раздел не завершён Причина: Создайте страницу для non-propagating-cache [range.nonprop.cache] |
[править] Помощники адаптеров диапазонов
| template< class F, class Tuple > constexpr auto /*кортежное преобразование*/( F&& f, Tuple&& tuple ) { // только для пояснения |
(1) | |
| template< class F, class Tuple > constexpr void /*tuple-for-each*/( F&& f, Tuple&& tuple ) { // только для пояснения |
(2) | |
Некоторые адаптеры диапазона указаны в терминах этих шаблонов функций только для пояснения.
[править] Вспомогательные концепты
Следующие концепты только для описания и используются для нескольких типов, но они не являются частями интерфейса стандартной библиотеки.
| template<class R> concept __simple_view = // только разъяснение |
||
[править] Примечание
| Макрос тест функциональности | Значение | Стандарт | Комментарий |
|---|---|---|---|
__cpp_lib_generator |
202207L | (C++23) | std::generator – синхронный генератор сопрограмм для диапазонов |
__cpp_lib_ranges |
201911L | (C++20) | Библиотека диапазонов и алгоритмы с ограничениями |
| 202106L | (C++20)) | Не инициализируемые по умолчанию представления | |
| 202110L | (C++20)) | Представления с владением | |
| 202202L | (C++23) | std::ranges::range_adaptor_closure | |
| 202207L | (C++23) | Ослабленные адаптеры диапазонов, чтобы разрешить типы только для перемещения | |
| 202211L | (C++23) | Удаление перегрузок "ядовитых таблеток" в ranges::begin и т.д. | |
__cpp_lib_ranges_as_const |
202207L | (C++23) | std::const_iterator, std::ranges::as_const_view |
__cpp_lib_ranges_as_rvalue |
202207L | (C++23) | std::ranges::as_rvalue_view |
__cpp_lib_ranges_cartesian_product |
202207L | (C++23) | std::ranges::cartesian_product_view |
__cpp_lib_ranges_chunk |
202202L | (C++23) | std::ranges::chunk_view |
__cpp_lib_ranges_chunk_by |
202202L | (C++23) | std::ranges::chunk_by_view |
__cpp_lib_ranges_join_with |
202202L | (C++23) | std::ranges::join_with_view |
__cpp_lib_ranges_repeat |
202207L | (C++23) | std::ranges::repeat_view |
__cpp_lib_ranges_slide |
202202L | (C++23) | std::ranges::slide_view |
__cpp_lib_ranges_stride |
202207L | (C++23) | std::ranges::stride_view |
__cpp_lib_ranges_to_container |
202202L | (C++23) | std::ranges::to |
__cpp_lib_ranges_zip |
202110L | (C++23) | std::ranges::zip_view, std::ranges::zip_transform_view, std::ranges::adjacent_view, std::ranges::adjacent_transform_view |
[править] Пример
#include <iostream> #include <ranges> int main() { auto const ints = {0,1,2,3,4,5}; auto even = [](int i) { return 0 == i % 2; }; auto square = [](int i) { return i * i; }; // "конвейерный" синтаксис для создания представлений: for (int i : ints | std::views::filter(even) | std::views::transform(square)) { std::cout << i << ' '; } std::cout << '\n'; // традиционный "функциональный" синтаксис составления: for (int i : std::views::transform(std::views::filter(ints, even), square)) { std::cout << i << ' '; } }
Вывод:
0 4 16 0 4 16
[править] Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
| Номер | Применён | Поведение в стандарте | Корректное поведение |
|---|---|---|---|
| LWG 3509 | C++20 | было неясно, как объекты адаптеров диапазонов связывают конечные аргументы | они связаны по значению |

