diff --git a/src/content/docs/cpp/library/ranges.mdx b/src/content/docs/cpp/library/ranges.mdx new file mode 100644 index 0000000..546b14c --- /dev/null +++ b/src/content/docs/cpp/library/ranges.mdx @@ -0,0 +1,763 @@ +--- +title: "Ranges library (since C++20)" +cppref-url: "http://en.cppreference.com/w/cpp/ranges.html" +--- + +import { CppHeader, DR, DRList, Desc, DescList, DocLink, Revision, WG21PaperLink } from '@components/index'; + +The ranges library is an extension and generalization of the algorithms and iterator libraries that makes them more powerful by making them composable and less error-prone. + +The library creates and manipulates range *views*, lightweight objects that indirectly represent iterable sequences (*ranges*). Ranges are an abstraction on top of + +* `[begin, end)` – iterator pairs, e.g. ranges made by implicit conversion from containers. All algorithms that take iterator pairs now have overloads that accept ranges (e.g. `ranges::sort`) +* begin `+` `[0,` size`)` – counted sequences, e.g. range returned by `views::counted` +* `[begin,` *predicate*`)` – conditionally-terminated sequences, e.g. range returned by `views::take_while` +* `[begin, ..)` – unbounded sequences, e.g. range returned by `views::iota` + +The ranges library includes range algorithms, which are applied to ranges eagerly, and [range adaptors](#Range_adaptors), which are applied to views lazily. Adaptors can be composed into pipelines, so that their actions take place as the view is iterated. + +```cpp +namespace std { + namespace views = ranges::views; +} +``` + +The namespace alias `std::views` is provided as a shorthand for `std::ranges::views`. + +##### Defined in namespace `std::ranges` + +### Range access + +##### Defined in header +##### Defined in header + + + + `ranges::begin` :badge[C++20] + returns an iterator to the beginning of a range + (customization point object) + + + `ranges::end` :badge[C++20] + returns a sentinel indicating the end of a range + (customization point object) + + + `ranges::cbegin` :badge[C++20] + returns an iterator to the beginning of a read-only range + (customization point object) + + + `ranges::cend` :badge[C++20] + returns a sentinel indicating the end of a read-only range + (customization point object) + + + `ranges::rbegin` :badge[C++20] + returns a reverse iterator to a range + (customization point object) + + + `ranges::rend` :badge[C++20] + returns a reverse end iterator to a range + (customization point object) + + + `ranges::crbegin` :badge[C++20] + returns a reverse iterator to a read-only range + (customization point object) + + + `ranges::crend` :badge[C++20] + returns a reverse end iterator to a read-only range + (customization point object) + + + `ranges::reserve_hint` :badge[C++26] + returns an integer equal to the reserve hint given by a range + (customization point object) + + + `ranges::size` :badge[C++20] + returns an integer equal to the size of a range + (customization point object) + + + `ranges::ssize` :badge[C++20] + returns a signed integer equal to the size of a range + (customization point object) + + + `ranges::empty` :badge[C++20] + checks whether a range is empty + (customization point object) + + + `ranges::data` :badge[C++20] + obtains a pointer to the beginning of a contiguous range + (customization point object) + + + `ranges::cdata` :badge[C++20] + obtains a pointer to the beginning of a read-only contiguous range + (customization point object) + + + +### Range primitives + +##### Defined in header + + + + `ranges::iterator_t` `ranges::const_iterator_t` `ranges::sentinel_t` `ranges::const_sentinel_t` + obtains iterator and sentinel types of a range + (alias template) + + + `ranges::range_difference_t` `ranges::range_size_t` `ranges::range_value_t` + obtains size, difference, and value types of a range + (alias template) + + + `ranges::range_reference_t` `ranges::range_const_reference_t` `ranges::range_rvalue_reference_t` `ranges::range_common_reference_t` + obtains reference types of a range + (alias template) + + + +### Dangling iterator handling + +##### Defined in header + + + + `ranges::dangling` + a placeholder type indicating that an iterator or a `subrange` should not be returned since it would be dangling + (class) + + + `ranges::borrowed_iterator_t` `ranges::borrowed_subrange_t` + obtains iterator type or `subrange` type of a `borrowed_range` + (alias template) + + + +### Other utilities + +##### Defined in header + + + + `ranges::elements_of` + tags a range to be treated as a sequence rather than a single value + (class template) + + + +### Range concepts + +##### Defined in header + + + + `ranges::range` + specifies that a type is a range, that is, it provides a `begin` iterator and an `end` sentinel + (concept) + + + `ranges::borrowed_range` + specifies that a type is a `range` and iterators obtained from an expression of it can be safely returned without danger of dangling + (concept) + + + `ranges::approximately_sized_range` + specifies that a range can estimate its size in constant time + (concept) + + + `ranges::sized_range` + specifies that a range knows its size in constant time + (concept) + + + `ranges::view` + specifies that a range is a view, that is, it has constant time copy/move/assignment + (concept) + + + `ranges::input_range` + specifies a range whose iterator type satisfies `input_iterator` + (concept) + + + `ranges::output_range` + specifies a range whose iterator type satisfies `output_iterator` + (concept) + + + `ranges::forward_range` + specifies a range whose iterator type satisfies `forward_iterator` + (concept) + + + `ranges::bidirectional_range` + specifies a range whose iterator type satisfies `bidirectional_iterator` + (concept) + + + `ranges::random_access_range` + specifies a range whose iterator type satisfies `random_access_iterator` + (concept) + + + `ranges::contiguous_range` + specifies a range whose iterator type satisfies `contiguous_iterator` + (concept) + + + `ranges::common_range` + specifies that a range has identical iterator and sentinel types + (concept) + + + `ranges::viewable_range` + specifies the requirements for a `range` to be safely convertible to a `view` + (concept) + + + `ranges::constant_range` + specifies that a range has read-only elements + (concept) + + + +### Range conversions + +##### Defined in header + + + + `ranges::to` + constructs a new non-view object from an input range + (function template) + + + +### Views + +##### Defined in header + + + + `ranges::view_interface` + helper class template for defining a `view`, using the curiously recurring template pattern + (class template) + + + `ranges::subrange` + combines an iterator-sentinel pair into a `view` + (class template) + + + +### Range factories + +##### Defined in header +##### Defined in namespace `std::ranges` + + + + `ranges::empty_view` `views::empty` + an empty `view` with no elements + (class template) (variable template) + + + `ranges::single_view` `views::single` + a `view` that contains a single element of a specified value + (class template) (customization point object) + + + `ranges::iota_view` `views::iota` + a `view` consisting of a sequence generated by repeatedly incrementing an initial value + (class template) (customization point object) + + + `ranges::repeat_view` `views::repeat` + a `view` consisting of a generated sequence by repeatedly producing the same value + (class template) (customization point object) + + + `ranges::basic_istream_view` `views::istream` + a `view` consisting of the elements obtained by successive application of `operator>>` on the associated input stream + (class template) (customization point object) + + + +### Range adaptors + +##### Defined in header +##### Defined in namespace `std::ranges` + + + + `ranges::range_adaptor_closure` + helper base class template for defining a range adaptor closure object + (class template) + + + `views::all_t` `views::all` + a `view` that includes all elements of a `range` + (alias template) (range adaptor object) + + + `ranges::ref_view` + a `view` of the elements of some other `range` + (class template) + + + `ranges::owning_view` + a `view` with unique ownership of some `range` + (class template) + + + `ranges::as_rvalue_view` `views::as_rvalue` + a `view` of a sequence that casts each element to an rvalue + (class template) (range adaptor object) + + + `ranges::filter_view` `views::filter` + a `view` that consists of the elements of a `range` that satisfies a predicate + (class template) (range adaptor object) + + + `ranges::transform_view` `views::transform` + a `view` of a sequence that applies a transformation function to each element + (class template) (range adaptor object) + + + `ranges::take_view` `views::take` + a `view` consisting of the first N elements of another `view` + (class template) (range adaptor object) + + + `ranges::take_while_view` `views::take_while` + a `view` consisting of the initial elements of another `view`, until the first element on which a predicate returns `false` + (class template) (range adaptor object) + + + `ranges::drop_view` `views::drop` + a `view` consisting of elements of another `view`, skipping the first N elements + (class template) (range adaptor object) + + + `ranges::drop_while_view` `views::drop_while` + a `view` consisting of the elements of another `view`, skipping the initial subsequence of elements until the first element where the predicate returns `false` + (class template) (range adaptor object) + + + `ranges::join_view` `views::join` + a `view` consisting of the sequence obtained from flattening a `view` of `range`s + (class template) (range adaptor object) + + + `ranges::join_with_view` `views::join_with` + a `view` consisting of the sequence obtained from flattening a view of ranges, with the delimiter in between elements + (class template) (range adaptor object) + + + `ranges::lazy_split_view` `views::lazy_split` + a `view` over the subranges obtained from splitting another `view` using a delimiter + (class template) (range adaptor object) + + + `ranges::split_view` `views::split` + a `view` over the subranges obtained from splitting another `view` using a delimiter + (class template) (range adaptor object) + + + `ranges::concat_view` `views::concat` + a `view` consisting of concatenation of the adapted views + (class template) (customization point object) + + + `views::counted` + creates a subrange from an iterator and a count + (customization point object) + + + `ranges::common_view` `views::common` + converts a `view` into a `common_range` + (class template) (range adaptor object) + + + `ranges::reverse_view` `views::reverse` + a `view` that iterates over the elements of another bidirectional view in reverse order + (class template) (range adaptor object) + + + `ranges::as_const_view` `views::as_const` + converts a `view` into a `constant_range` + (class template) (range adaptor object) + + + `ranges::elements_view` `views::elements` + takes a `view` consisting of `tuple-like` values and a number N and produces a `view` of N`th` element of each tuple + (class template) (range adaptor object) + + + `ranges::keys_view` `views::keys` + takes a `view` consisting of pair-like values and produces a `view` of the first elements of each pair + (class template) (range adaptor object) + + + `ranges::values_view` `views::values` + takes a `view` consisting of pair-like values and produces a `view` of the second elements of each pair + (class template) (range adaptor object) + + + `ranges::enumerate_view` `views::enumerate` + a `view` that maps each element of adapted sequence to a tuple of both the element's position and its value + (class template) (range adaptor object) + + + `ranges::zip_view` `views::zip` + a `view` consisting of tuples of references to corresponding elements of the adapted views + (class template) (customization point object) + + + `ranges::zip_transform_view` `views::zip_transform` + a `view` consisting of results of application of a transformation function to corresponding elements of the adapted views + (class template) (customization point object) + + + `ranges::adjacent_view` `views::adjacent` + a `view` consisting of tuples of references to adjacent elements of the adapted view + (class template) (range adaptor object) + + + `ranges::adjacent_transform_view` `views::adjacent_transform` + a `view` consisting of results of application of a transformation function to adjacent elements of the adapted view + (class template) (range adaptor object) + + + `ranges::chunk_view` `views::chunk` + a range of `view`s that are `N`-sized non-overlapping successive chunks of the elements of another `view` + (class template) (range adaptor object) + + + `ranges::slide_view` `views::slide` + a `view` whose M`th` element is a `view` over the M`th` through (M + N - 1)`th` elements of another `view` + (class template) (range adaptor object) + + + `ranges::chunk_by_view` `views::chunk_by` + splits the `view` into subranges between each pair of adjacent elements for which the given predicate returns `false` + (class template) (range adaptor object) + + + `ranges::stride_view` `views::stride` + a `view` consisting of elements of another `view`, advancing over N elements at a time + (class template) (range adaptor object) + + + `ranges::cartesian_product_view` `views::cartesian_product` + a `view` consisting of tuples of results calculated by the n-ary cartesian product of the adapted views + (class template) (customization point object) + + + `ranges::cache_latest_view` `views::cache_latest` + a `view` that caches the last-accessed element of its underlying sequence + (class template) (range adaptor object) + + + `ranges::to_input_view` `views::to_input` + converts a `view` into a range that is `input_range`-only and non-`common_range` + (class template) (range adaptor object) + + + +### Range generators :badge[C++23] + +##### Defined in header +##### Defined in namespace `std` + + + + `generator` + A `view` that represents synchronous coroutine generator + (class template) + + + +### Helper items + +#### Range adaptor objects + +See `RangeAdaptorObject` (RAO). + +#### Range adaptor closure objects + +See `RangeAdaptorClosureObject` (RACO). + +#### Customization point objects + +See Customization point object (CPO). + +#### Assignable wrapper + +Some range adaptors wrap their elements or function objects with the `*copyable-box*``*movable-box*`. The wrapper augments the wrapped object with assignability when needed. + +#### Non-propagating cache + +Some range adaptors are specified in terms of an exposition-only class template `*non-propagating-cache*`, which behaves almost like `std::optional` (see description for differences). + +#### Conditionally-`const` type + +```cpp +template< bool Const, class T > +using /*maybe-const*/ = std::conditional_t; +``` +The alias template `/*maybe-const*/` is a shorthand used to conditionally apply a `const` qualifier to the type `T`. + +#### Integer-like type helper templates + +```cpp +template< /*is-integer-like*/ T > +using /*make-signed-like-t*/ = /* see description */; +``` +(1) +```cpp +template< /*is-integer-like*/ T > +using /*make-unsigned-like-t*/ = /* see description */; +``` +(2) +```cpp +template< /*is-integer-like*/ T > +/*make-unsigned-like-t*/ /*to-unsigned-like*/( T t ) +{ + return static_cast>(t); +} +``` +(3) + +1. For an integer-like type `T`: + * If `T` is an integer type, `/*make-signed-like-t*/` is `std::make_signed_t`. + * Otherwise, `/*make-signed-like-t*/` is a corresponding unspecified signed-integer-like type of the same width as `T`. + +2. For an integer-like type `T`: + * If `T` is an integer type, `/*make-unsigned-like-t*/` is `std::make_unsigned_t`. + * Otherwise, `/*make-signed-like-t*/` is a corresponding unspecified unsigned-integer-like type of the same width as `T`. + +3. Explicitly converts `t` to `/*make-unsigned-like-t*/`. + +#### Customization point object helpers + +```cpp +template< ranges::input_range R > +constexpr auto& /*possibly-const-range*/(R& r) noexcept +{ + if constexpr (ranges::input_range) + return const_cast(r); + else + return r; +} +``` +(1) +```cpp +template< class T > +constexpr auto /*as-const-pointer*/( const T* p ) noexcept +{ + return p; +} +``` +(2) + +Some range access customization point objects are specified in terms of these exposition-only function templates. + +1. `/*possibly-const-range*/` returns the const-qualified version of `r` if `const R` models `input_range`; otherwise, returns `r` without any casting. +2. `/*as-const-pointer*/` returns a pointer to object of constant type. + +#### Range adaptor helpers + +```cpp +template< class F, class Tuple > +constexpr auto /*tuple-transform*/( F&& f, Tuple&& tuple ) +{ + return std::apply([](Ts&&... args) + { + return std::tuple...> + (std::invoke(f, std::forward(args))...); + }, std::forward(tuple)); +} +``` +(1) +```cpp +template< class F, class Tuple > +constexpr void /*tuple-for-each*/( F&& f, Tuple&& tuple ) +{ + std::apply([](Ts&&... args) + { + (static_cast(std::invoke(f, std::forward(args))), ...); + }, std::forward(tuple)); +} +``` +(2) +```cpp +template< class T > +constexpr T& /*as-lvalue*/( T&& t ) +{ + return static_cast(t); +} +``` +(3) + +Some range adaptors are specified in terms of these exposition-only function templates. + +1. `/*tuple-transform*/` returns a new tuple constructed by applying `f` to each element of `tuple`. +2. `/*tuple-for-each*/` applies `f` to each element of `tuple` and returns nothing. +3. `/*as-lvalue*/` forwards rvalue `t` as lvalue. + +#### Helper concepts + +Following exposition-only concepts are used for several types, but they are not parts of the interface of standard library. + +```cpp +template< class R > +concept /*simple-view*/ = + ranges::view && ranges::range && + std::same_as, ranges::iterator_t> && + std::same_as, ranges::sentinel_t>; +``` +(1) +```cpp +template< class I > +concept /*has-arrow*/ = + ranges::input_iterator && + (std::is_pointer_v || requires(const I i) { i.operator->(); }); +``` +(2) +```cpp +template< class T, class U > +concept /*different-from*/ = + !std::same_as, std::remove_cvref_t>; +``` +(3) +```cpp +template< class R > +concept /*range-with-movable-references*/ = + ranges::input_range && + std::move_constructible> && + std::move_constructible>; +``` +(4) +```cpp +template< bool C, class... Views > +concept /*all-random-access*/ = + (ranges::random_access_range + > && ...); +``` +(5) +```cpp +template< bool C, class... Views > +concept /*all-bidirectional*/ = + (ranges::bidirectional_range + > && ...); +``` +(6) +```cpp +template< bool C, class... Views > +concept /*all-forward*/ = + (ranges::forward_range + > && ...); +``` +(7) + +### Notes + +| Feature-test macro | Value | Std | Feature | +| :----------------- | :---- | :-- | :------ | +| `__cpp_lib_generator` | `202207L` | | `std::generator` – synchronous coroutine generator for ranges | +| `__cpp_lib_ranges` | `201911L` | | Ranges library and constrained algorithms | +| | `202106L` | (DR20) | Non-default-initializable views | +| | `202110L` | (DR20) | Views with ownership | +| | `202202L` | | `ranges::range_adaptor_closure` | +| | `202207L` | | Relaxing [range adaptors](#Range_adaptors) to allow for move-only types | +| | `202211L` | | Removing "poison pills" overloads in `ranges::begin` etc | +| | `202302L` | | Relaxing ranges to allow certain projections | +| | `202406L` | (DR20) | Removing the common reference requirement from the indirectly invocable concepts | +| `__cpp_lib_ranges_as_const` | `202207L` | | `std::const_iterator`, `ranges::as_const_view` | +| `__cpp_lib_ranges_as_rvalue` | `202207L` | | `ranges::as_rvalue_view` | +| `__cpp_lib_ranges_cache_latest` | `202411L` | | `ranges::cache_latest_view` | +| `__cpp_lib_ranges_cartesian_product` | `202207L` | | `ranges::cartesian_product_view` | +| `__cpp_lib_ranges_chunk` | `202202L` | | `ranges::chunk_view` | +| `__cpp_lib_ranges_chunk_by` | `202202L` | | `ranges::chunk_by_view` | +| `__cpp_lib_ranges_concat` | `202403L` | | `ranges::concat_view` | +| `__cpp_lib_ranges_enumerate` | `202302L` | | `ranges::enumerate_view` | +| `__cpp_lib_ranges_join_with` | `202202L` | | `ranges::join_with_view` | +| `__cpp_lib_ranges_repeat` | `202207L` | | `ranges::repeat_view` | +| `__cpp_lib_ranges_reserve_hint` | `202502L` | | `ranges::reserve_hint` and `ranges::approximately_sized_range` | +| `__cpp_lib_ranges_slide` | `202202L` | | `ranges::slide_view` | +| `__cpp_lib_ranges_stride` | `202207L` | | `ranges::stride_view` | +| `__cpp_lib_ranges_to_container` | `202202L` | | `ranges::to` | +| `__cpp_lib_ranges_to_input` | `202502L` | | `ranges::to_input_view` | +| `__cpp_lib_ranges_zip` | `202110L` | | `ranges::zip_view`,
`ranges::zip_transform_view`,
`ranges::adjacent_view`,
`ranges::adjacent_transform_view` | + +### Example + +```cpp +#include +#include + +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; }; + + // the "pipe" syntax of composing the views: + for (int i : ints | std::views::filter(even) | std::views::transform(square)) + std::cout << i << ' '; + + std::cout << '\n'; + + // a traditional "functional" composing syntax: + for (int i : std::views::transform(std::views::filter(ints, even), square)) + std::cout << i << ' '; +} +``` + +Output: + +```text +0 4 16 +0 4 16 +``` + +### Defect reports + +The following behavior-changing defect reports were applied retroactively to previously published C++ standards. + + + + was unclear how range adaptor objects bound trailing arguments + they are bound by value + + + `*possibly-const-range*` and `*as-const-pointer*` were not declared `noexcept` + declared `noexcept` + + + `*possibly-const-range*` would not add const-qualification for ranges that has already modeled `constant_range` + adds const-qualification for such ranges + + + `*has-arrow*` did not require `i` to be const-qualified + requires + + + +### See also + +* Iterator library +* Constrained algorithms