Files
2025-10-25 03:02:53 +03:00

599 lines
41 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[range.utility]
# 25 Ranges library [[ranges]](./#ranges)
## 25.5 Range utilities [range.utility]
### [25.5.1](#general) General [[range.utility.general]](range.utility.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L1742)
The components in [range.utility] are general utilities for representing and
manipulating ranges[.](#general-1.sentence-1)
### [25.5.2](#helpers) Helper concepts [[range.utility.helpers]](range.utility.helpers)
[1](#helpers-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L1748)
Many of the types in [range.utility] are specified in terms of
the following exposition-only concepts:template<class R>concept [*simple-view*](#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]") = // *exposition only*[view](range.view#concept:view "25.4.5Views[range.view]")<R> && [range](range.range#concept:range "25.4.2Ranges[range.range]")<const R> &&[same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<iterator_t<R>, iterator_t<const R>> &&[same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<sentinel_t<R>, sentinel_t<const R>>;
template<class I>concept [*has-arrow*](#concept:has-arrow "25.5.2Helper concepts[range.utility.helpers]") = // *exposition only*[input_iterator](iterator.concept.input#concept:input_iterator "24.3.4.9Concept input_­iterator[iterator.concept.input]")<I> && (is_pointer_v<I> || requires(const I i) { i.operator->(); });
template<class T, class U>concept [*different-from*](#concept:different-from "25.5.2Helper concepts[range.utility.helpers]") = // *exposition only*![same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<remove_cvref_t<T>, remove_cvref_t<U>>;
template<class R>concept [*range-with-movable-references*](#concept:range-with-movable-references "25.5.2Helper concepts[range.utility.helpers]") = // *exposition only*[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<R> && [move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13Concept move_­constructible[concept.moveconstructible]")<range_reference_t<R>> &&[move_constructible](concept.moveconstructible#concept:move_constructible "18.4.13Concept move_­constructible[concept.moveconstructible]")<range_rvalue_reference_t<R>>;
### [25.5.3](#view.interface) View interface [[view.interface]](view.interface)
#### [25.5.3.1](#view.interface.general) General [[view.interface.general]](view.interface.general)
[1](#view.interface.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L1776)
The class template view_interface is a helper for defining
view-like types that offer a container-like interface[.](#view.interface.general-1.sentence-1)
It is
parameterized with the type that is derived from it[.](#view.interface.general-1.sentence-2)
[🔗](#lib:view_interface)
namespace std::ranges {template<class D>requires is_class_v<D> && [same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<D, remove_cv_t<D>>class view_interface {private:constexpr D& *derived*() noexcept { // *exposition only*return static_cast<D&>(*this); }constexpr const D& *derived*() const noexcept { // *exposition only*return static_cast<const D&>(*this); }public:constexpr bool empty() requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<D> || [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<D> {if constexpr ([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<D>)return ranges::size(*derived*()) == 0; elsereturn ranges::begin(*derived*()) == ranges::end(*derived*()); }constexpr bool empty() const requires [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const D> || [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const D> {if constexpr ([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const D>)return ranges::size(*derived*()) == 0; elsereturn ranges::begin(*derived*()) == ranges::end(*derived*()); }constexpr auto cbegin() requires [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<D> {return ranges::cbegin(*derived*()); }constexpr auto cbegin() const requires [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<const D> {return ranges::cbegin(*derived*()); }constexpr auto cend() requires [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<D> {return ranges::cend(*derived*()); }constexpr auto cend() const requires [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<const D> {return ranges::cend(*derived*()); }constexpr explicit operator bool()requires requires { ranges::empty(*derived*()); } {return !ranges::empty(*derived*()); }constexpr explicit operator bool() constrequires requires { ranges::empty(*derived*()); } {return !ranges::empty(*derived*()); }constexpr auto data() requires [contiguous_iterator](iterator.concept.contiguous#concept:contiguous_iterator "24.3.4.14Concept contiguous_­iterator[iterator.concept.contiguous]")<iterator_t<D>> {return to_address(ranges::begin(*derived*())); }constexpr auto data() constrequires [range](range.range#concept:range "25.4.2Ranges[range.range]")<const D> && [contiguous_iterator](iterator.concept.contiguous#concept:contiguous_iterator "24.3.4.14Concept contiguous_­iterator[iterator.concept.contiguous]")<iterator_t<const D>> {return to_address(ranges::begin(*derived*())); }constexpr auto size() requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<D> &&[sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<D>, iterator_t<D>> {return *to-unsigned-like*(ranges::end(*derived*()) - ranges::begin(*derived*())); }constexpr auto size() const requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const D> &&[sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<const D>, iterator_t<const D>> {return *to-unsigned-like*(ranges::end(*derived*()) - ranges::begin(*derived*())); }constexpr decltype(auto) front() requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<D>; constexpr decltype(auto) front() const requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const D>; constexpr decltype(auto) back() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<D> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<D>; constexpr decltype(auto) back() constrequires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<const D> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<const D>; template<[random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]") R = D>constexpr decltype(auto) operator[](range_difference_t<R> n) {return ranges::begin(*derived*())[n]; }template<[random_access_range](range.refinements#concept:random_access_range "25.4.6Other range refinements[range.refinements]") R = const D>constexpr decltype(auto) operator[](range_difference_t<R> n) const {return ranges::begin(*derived*())[n]; }};}
[2](#view.interface.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L1867)
The template parameter D for view_interface may be an
incomplete type[.](#view.interface.general-2.sentence-1)
Before any member of the resulting specialization ofview_interface other than special member functions
is referenced, D shall be complete, and
model both [derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<view_interface<D>> and [view](range.view#concept:view "25.4.5Views[range.view]")[.](#view.interface.general-2.sentence-2)
#### [25.5.3.2](#view.interface.members) Members [[view.interface.members]](view.interface.members)
[🔗](#lib:front,view_interface)
`constexpr decltype(auto) front() requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<D>;
constexpr decltype(auto) front() const requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const D>;
`
[1](#view.interface.members-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L1883)
*Hardened preconditions*: !empty() is true[.](#view.interface.members-1.sentence-1)
[2](#view.interface.members-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L1887)
*Effects*: Equivalent to: return *ranges::begin(*derived*());
[🔗](#lib:back,view_interface)
`constexpr decltype(auto) back() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<D> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<D>;
constexpr decltype(auto) back() const
requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<const D> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<const D>;
`
[3](#view.interface.members-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L1900)
*Hardened preconditions*: !empty() is true[.](#view.interface.members-3.sentence-1)
[4](#view.interface.members-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L1904)
*Effects*: Equivalent to: return *ranges::prev(ranges::end(*derived*()));
### [25.5.4](#range.subrange) Sub-ranges [[range.subrange]](range.subrange)
#### [25.5.4.1](#range.subrange.general) General [[range.subrange.general]](range.subrange.general)
[1](#range.subrange.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L1913)
The subrange class template combines together an
iterator and a sentinel into a single object that models the[view](range.view#concept:view "25.4.5Views[range.view]") concept[.](#range.subrange.general-1.sentence-1)
Additionally, it models the[sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]") concept when the final template parameter issubrange_kind::sized[.](#range.subrange.general-1.sentence-2)
[🔗](#lib:subrange)
namespace std::ranges {template<class From, class To>concept [*uses-nonqualification-pointer-conversion*](#concept:uses-nonqualification-pointer-conversion "25.5.4.1General[range.subrange.general]") = // *exposition only* is_pointer_v<From> && is_pointer_v<To> &&![convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<remove_pointer_t<From>(*)[], remove_pointer_t<To>(*)[]>; template<class From, class To>concept [*convertible-to-non-slicing*](#concept:convertible-to-non-slicing "25.5.4.1General[range.subrange.general]") = // *exposition only*[convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<From, To> &&![*uses-nonqualification-pointer-conversion*](#concept:uses-nonqualification-pointer-conversion "25.5.4.1General[range.subrange.general]")<decay_t<From>, decay_t<To>>; template<class T, class U, class V>concept [*pair-like-convertible-from*](#concept:pair-like-convertible-from "25.5.4.1General[range.subrange.general]") = // *exposition only*![range](range.range#concept:range "25.4.2Ranges[range.range]")<T> && !is_reference_v<T> && [*pair-like*](tuple.syn#concept:pair-like "22.4.2Header <tuple> synopsis[tuple.syn]")<T> &&[constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<T, U, V> &&[*convertible-to-non-slicing*](#concept:convertible-to-non-slicing "25.5.4.1General[range.subrange.general]")<U, tuple_element_t<0, T>> &&[convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<V, tuple_element_t<1, T>>; template<[input_or_output_iterator](iterator.concept.iterator#concept:input_or_output_iterator "24.3.4.6Concept input_­or_­output_­iterator[iterator.concept.iterator]") I, [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept sentinel_­for[iterator.concept.sentinel]")<I> S = I, subrange_kind K =[sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<S, I> ? subrange_kind::sized : subrange_kind::unsized>requires (K == subrange_kind::sized || ![sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<S, I>)class subrange : public view_interface<subrange<I, S, K>> {private:static constexpr bool *StoreSize* = // *exposition only* K == subrange_kind::sized && ![sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<S, I>;
I *begin_* = I(); // *exposition only* S *end_* = S(); // *exposition only**make-unsigned-like-t*<iter_difference_t<I>> *size_* = 0; // *exposition only*; present only// if *StoreSize* is truepublic: subrange() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<I> = default; constexpr subrange([*convertible-to-non-slicing*](#concept:convertible-to-non-slicing "25.5.4.1General[range.subrange.general]")<I> auto i, S s) requires (!*StoreSize*); constexpr subrange([*convertible-to-non-slicing*](#concept:convertible-to-non-slicing "25.5.4.1General[range.subrange.general]")<I> auto i, S s, *make-unsigned-like-t*<iter_difference_t<I>> n)requires (K == subrange_kind::sized); template<[*different-from*](#concept:different-from "25.5.2Helper concepts[range.utility.helpers]")<subrange> R>requires [borrowed_range](range.range#concept:borrowed_range "25.4.2Ranges[range.range]")<R> &&[*convertible-to-non-slicing*](#concept:convertible-to-non-slicing "25.5.4.1General[range.subrange.general]")<iterator_t<R>, I> &&[convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<R>, S>constexpr subrange(R&& r) requires (!*StoreSize* || [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<R>); template<[borrowed_range](range.range#concept:borrowed_range "25.4.2Ranges[range.range]") R>requires [*convertible-to-non-slicing*](#concept:convertible-to-non-slicing "25.5.4.1General[range.subrange.general]")<iterator_t<R>, I> &&[convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<R>, S>constexpr subrange(R&& r, *make-unsigned-like-t*<iter_difference_t<I>> n)requires (K == subrange_kind::sized): subrange{ranges::begin(r), ranges::end(r), n} {}template<[*different-from*](#concept:different-from "25.5.2Helper concepts[range.utility.helpers]")<subrange> PairLike>requires [*pair-like-convertible-from*](#concept:pair-like-convertible-from "25.5.4.1General[range.subrange.general]")<PairLike, const I&, const S&>constexpr operator PairLike() const; constexpr I begin() const requires [copyable](concepts.object#concept:copyable "18.6Object concepts[concepts.object]")<I>; constexpr I begin() requires (![copyable](concepts.object#concept:copyable "18.6Object concepts[concepts.object]")<I>); constexpr S end() const; constexpr bool empty() const; constexpr *make-unsigned-like-t*<iter_difference_t<I>> size() constrequires (K == subrange_kind::sized); constexpr subrange next(iter_difference_t<I> n = 1) const &requires [forward_iterator](iterator.concept.forward#concept:forward_iterator "24.3.4.11Concept forward_­iterator[iterator.concept.forward]")<I>; constexpr subrange next(iter_difference_t<I> n = 1) &&; constexpr subrange prev(iter_difference_t<I> n = 1) constrequires [bidirectional_iterator](iterator.concept.bidir#concept:bidirectional_iterator "24.3.4.12Concept bidirectional_­iterator[iterator.concept.bidir]")<I>; constexpr subrange& advance(iter_difference_t<I> n); }; template<[input_or_output_iterator](iterator.concept.iterator#concept:input_or_output_iterator "24.3.4.6Concept input_­or_­output_­iterator[iterator.concept.iterator]") I, [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept sentinel_­for[iterator.concept.sentinel]")<I> S> subrange(I, S) -> subrange<I, S>; template<[input_or_output_iterator](iterator.concept.iterator#concept:input_or_output_iterator "24.3.4.6Concept input_­or_­output_­iterator[iterator.concept.iterator]") I, [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept sentinel_­for[iterator.concept.sentinel]")<I> S> subrange(I, S, *make-unsigned-like-t*<iter_difference_t<I>>) -> subrange<I, S, subrange_kind::sized>; template<[borrowed_range](range.range#concept:borrowed_range "25.4.2Ranges[range.range]") R> subrange(R&&) -> subrange<iterator_t<R>, sentinel_t<R>, ([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<R> || [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<R>, iterator_t<R>>)? subrange_kind::sized : subrange_kind::unsized>; template<[borrowed_range](range.range#concept:borrowed_range "25.4.2Ranges[range.range]") R> subrange(R&&, *make-unsigned-like-t*<range_difference_t<R>>) -> subrange<iterator_t<R>, sentinel_t<R>, subrange_kind::sized>;}
#### [25.5.4.2](#range.subrange.ctor) Constructors and conversions [[range.subrange.ctor]](range.subrange.ctor)
[🔗](#lib:subrange,constructor)
`constexpr subrange([convertible-to-non-slicing](#concept:convertible-to-non-slicing "25.5.4.1General[range.subrange.general]")<I> auto i, S s) requires (!StoreSize);
`
[1](#range.subrange.ctor-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2020)
*Preconditions*: [i, s) is a valid range[.](#range.subrange.ctor-1.sentence-1)
[2](#range.subrange.ctor-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2024)
*Effects*: Initializes *begin_* with std::move(i) and *end_* withs[.](#range.subrange.ctor-2.sentence-1)
[🔗](#lib:subrange,constructor_)
`constexpr subrange([convertible-to-non-slicing](#concept:convertible-to-non-slicing "25.5.4.1General[range.subrange.general]")<I> auto i, S s,
make-unsigned-like-t<iter_difference_t<I>> n)
requires (K == subrange_kind::sized);
`
[3](#range.subrange.ctor-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2038)
*Preconditions*: [i, s) is a valid range, andn == *to-unsigned-like*(ranges::distance(i, s)) is true[.](#range.subrange.ctor-3.sentence-1)
[4](#range.subrange.ctor-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2044)
*Effects*: Initializes *begin_* with std::move(i) and *end_* withs[.](#range.subrange.ctor-4.sentence-1)
If *StoreSize* is true, initializes *size_* withn[.](#range.subrange.ctor-4.sentence-2)
[5](#range.subrange.ctor-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2050)
[*Note [1](#range.subrange.ctor-note-1)*:
Accepting the length of the range and storing it to later return fromsize() enables subrange to model [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]") even
when it stores an iterator and sentinel that do not model[sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")[.](#range.subrange.ctor-5.sentence-1)
— *end note*]
[🔗](#lib:subrange,constructor__)
`template<[different-from](#concept:different-from "25.5.2Helper concepts[range.utility.helpers]")<subrange> R>
requires [borrowed_range](range.range#concept:borrowed_range "25.4.2Ranges[range.range]")<R> &&
[convertible-to-non-slicing](#concept:convertible-to-non-slicing "25.5.4.1General[range.subrange.general]")<iterator_t<R>, I> &&
[convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<R>, S>
constexpr subrange(R&& r) requires (!StoreSize || [sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<R>);
`
[6](#range.subrange.ctor-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2069)
*Effects*: Equivalent to:
- [(6.1)](#range.subrange.ctor-6.1)
If *StoreSize* is true,subrange(r, static_cast<decltype(*size_*)>(ranges::size(r)))[.](#range.subrange.ctor-6.1.sentence-1)
- [(6.2)](#range.subrange.ctor-6.2)
Otherwise, subrange(ranges::begin(r), ranges::end(r))[.](#range.subrange.ctor-6.2.sentence-1)
[🔗](#lib:operator_PairLike,subrange)
`template<[different-from](#concept:different-from "25.5.2Helper concepts[range.utility.helpers]")<subrange> PairLike>
requires [pair-like-convertible-from](#concept:pair-like-convertible-from "25.5.4.1General[range.subrange.general]")<PairLike, const I&, const S&>
constexpr operator PairLike() const;
`
[7](#range.subrange.ctor-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2087)
*Effects*: Equivalent to: return PairLike(*begin_*, *end_*);
#### [25.5.4.3](#range.subrange.access) Accessors [[range.subrange.access]](range.subrange.access)
[🔗](#lib:begin,subrange)
`constexpr I begin() const requires [copyable](concepts.object#concept:copyable "18.6Object concepts[concepts.object]")<I>;
`
[1](#range.subrange.access-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2100)
*Effects*: Equivalent to: return *begin_*;
[🔗](#lib:begin,subrange_)
`constexpr I begin() requires (![copyable](concepts.object#concept:copyable "18.6Object concepts[concepts.object]")<I>);
`
[2](#range.subrange.access-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2111)
*Effects*: Equivalent to: return std::move(*begin_*);
[🔗](#lib:end,subrange)
`constexpr S end() const;
`
[3](#range.subrange.access-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2122)
*Effects*: Equivalent to: return *end_*;
[🔗](#lib:empty,subrange)
`constexpr bool empty() const;
`
[4](#range.subrange.access-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2133)
*Effects*: Equivalent to: return *begin_* == *end_*;
[🔗](#lib:size,subrange)
`constexpr make-unsigned-like-t<iter_difference_t<I>> size() const
requires (K == subrange_kind::sized);
`
[5](#range.subrange.access-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2145)
*Effects*:
- [(5.1)](#range.subrange.access-5.1)
If *StoreSize* is true, equivalent to: return *size_*;
- [(5.2)](#range.subrange.access-5.2)
Otherwise, equivalent to: return *to-unsigned-like*(*end_* - *begin_*);
[🔗](#lib:next,subrange)
`constexpr subrange next(iter_difference_t<I> n = 1) const &
requires [forward_iterator](iterator.concept.forward#concept:forward_iterator "24.3.4.11Concept forward_­iterator[iterator.concept.forward]")<I>;
`
[6](#range.subrange.access-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2160)
*Effects*: Equivalent to:auto tmp = *this;
tmp.advance(n);return tmp;
[🔗](#lib:next,subrange_)
`constexpr subrange next(iter_difference_t<I> n = 1) &&;
`
[7](#range.subrange.access-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2176)
*Effects*: Equivalent to:advance(n);return std::move(*this);
[🔗](#lib:prev,subrange)
`constexpr subrange prev(iter_difference_t<I> n = 1) const
requires [bidirectional_iterator](iterator.concept.bidir#concept:bidirectional_iterator "24.3.4.12Concept bidirectional_­iterator[iterator.concept.bidir]")<I>;
`
[8](#range.subrange.access-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2192)
*Effects*: Equivalent to:auto tmp = *this;
tmp.advance(-n);return tmp;
[🔗](#lib:advance,subrange)
`constexpr subrange& advance(iter_difference_t<I> n);
`
[9](#range.subrange.access-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2208)
*Effects*: Equivalent to:if constexpr ([bidirectional_iterator](iterator.concept.bidir#concept:bidirectional_iterator "24.3.4.12Concept bidirectional_­iterator[iterator.concept.bidir]")<I>) {if (n < 0) { ranges::advance(*begin_*, n); if constexpr (*StoreSize*)*size_* += *to-unsigned-like*(-n); return *this; }}auto d = n - ranges::advance(*begin_*, n, *end_*);if constexpr (*StoreSize*)*size_* -= *to-unsigned-like*(d);return *this;
[🔗](#lib:get,subrange)
`template<size_t N, class I, class S, subrange_kind K>
requires ((N == 0 && [copyable](concepts.object#concept:copyable "18.6Object concepts[concepts.object]")<I>) || N == 1)
constexpr auto get(const subrange<I, S, K>& r);
template<size_t N, class I, class S, subrange_kind K>
requires (N < 2)
constexpr auto get(subrange<I, S, K>&& r);
`
[10](#range.subrange.access-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2239)
*Effects*: Equivalent to:if constexpr (N == 0)return r.begin();elsereturn r.end();
### [25.5.5](#range.dangling) Dangling iterator handling [[range.dangling]](range.dangling)
[1](#range.dangling-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2252)
The type dangling is used together with the template aliasesborrowed_iterator_t and borrowed_subrange_t[.](#range.dangling-1.sentence-1)
When an algorithm
that typically returns an iterator into, or a subrange of, a range argument
is called with an rvalue range argument
that does not model [borrowed_range](range.range#concept:borrowed_range "25.4.2Ranges[range.range]") ([[range.range]](range.range "25.4.2Ranges")),
the return value possibly refers to a range whose lifetime has ended[.](#range.dangling-1.sentence-2)
In such cases,
the type dangling is returned instead of an iterator or subrange[.](#range.dangling-1.sentence-3)
[🔗](#lib:dangling)
namespace std::ranges {struct dangling {constexpr dangling() noexcept = default; constexpr dangling(auto&&...) noexcept {}};}
[2](#range.dangling-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2272)
[*Example [1](#range.dangling-example-1)*: vector<int> f();auto result1 = ranges::find(f(), 42); // #1static_assert([same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<decltype(result1), ranges::dangling>);auto vec = f();auto result2 = ranges::find(vec, 42); // #2static_assert([same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<decltype(result2), vector<int>::iterator>);auto result3 = ranges::find(ranges::subrange{vec}, 42); // #3static_assert([same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<decltype(result3), vector<int>::iterator>);
The call to ranges::find at #1 returns ranges::dangling since f() is an rvalue vector;
it is possible for the vector to be destroyed
before a returned iterator is dereferenced[.](#range.dangling-2.sentence-1)
However, the calls at #2 and #3 both return iterators
since the lvalue vec and specializations of subrange model [borrowed_range](range.range#concept:borrowed_range "25.4.2Ranges[range.range]")[.](#range.dangling-2.sentence-2)
— *end example*]
[3](#range.dangling-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2293)
For a type R that models [range](range.range#concept:range "25.4.2Ranges[range.range]"):
- [(3.1)](#range.dangling-3.1)
if R models [borrowed_range](range.range#concept:borrowed_range "25.4.2Ranges[range.range]"), thenborrowed_iterator_t<R> denotes iterator_t<R>, andborrowed_subrange_t<R> denotes subrange<iterator_t<R>>;
- [(3.2)](#range.dangling-3.2)
otherwise,
both borrowed_iterator_t<R> and borrowed_subrange_t<R> denote dangling[.](#range.dangling-3.sentence-1)
### [25.5.6](#range.elementsof) Class template elements_of [[range.elementsof]](range.elementsof)
Specializations of elements_of encapsulate a range and
act as a tag in overload sets to disambiguate
when a range should be treated as a sequence
rather than a single value[.](#range.elementsof-sentence-1)
[*Example [1](#range.elementsof-example-1)*: template<bool YieldElements> generator<any> f(ranges::[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") auto&& r) {if constexpr (YieldElements)co_yield ranges::elements_of(r); // yield each element of relseco_yield r; // yield r as a single value} — *end example*]
namespace std::ranges {template<[range](range.range#concept:range "25.4.2Ranges[range.range]") R, class Allocator = allocator<byte>>struct elements_of {[[no_unique_address]] R range; [[no_unique_address]] Allocator allocator = Allocator(); }; template<class R, class Allocator = allocator<byte>> elements_of(R&&, Allocator = Allocator()) -> elements_of<R&&, Allocator>;}
### [25.5.7](#conv) Range conversions [[range.utility.conv]](range.utility.conv)
#### [25.5.7.1](#conv.general) General [[range.utility.conv.general]](range.utility.conv.general)
[1](#conv.general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2342)
The range conversion functions construct
an object (usually a container) from a range,
by using a constructor taking a range,
a from_range_t tagged constructor, or
a constructor taking a pair of iterators, or
by inserting each element of the range into the default-constructed object[.](#conv.general-1.sentence-1)
[2](#conv.general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2350)
ranges::to is applied recursively,
allowing the conversion of a range of ranges[.](#conv.general-2.sentence-1)
[*Example [1](#conv.general-example-1)*: string_view str = "the quick brown fox";auto words = views::split(str, ' ') | to<vector<string>>();// words is vector<string>{"the", "quick", "brown", "fox"} — *end example*]
[3](#conv.general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2362)
Let *reservable-container* be defined as follows:template<class Container>constexpr bool *reservable-container* = // *exposition only*[sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<Container> &&requires(Container& c, range_size_t<Container> n) { c.reserve(n); { c.capacity() } -> [same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<decltype(n)>; { c.max_size() } -> [same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<decltype(n)>; };
[4](#conv.general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2375)
Let *container-appendable* be defined as follows:template<class Container, class Ref>constexpr bool *container-appendable* = // *exposition only*requires(Container& c, Ref&& ref) {requires (requires { c.emplace_back(std::forward<Ref>(ref)); } ||requires { c.push_back(std::forward<Ref>(ref)); } ||requires { c.emplace(c.end(), std::forward<Ref>(ref)); } ||requires { c.insert(c.end(), std::forward<Ref>(ref)); }); };
[5](#conv.general-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2388)
Let *container-append* be defined as follows:template<class Container>constexpr auto *container-append*(Container& c) { // *exposition only*return [&c]<class Ref>(Ref&& ref) {if constexpr (requires { c.emplace_back(declval<Ref>()); }) c.emplace_back(std::forward<Ref>(ref)); else if constexpr (requires { c.push_back(declval<Ref>()); }) c.push_back(std::forward<Ref>(ref)); else if constexpr (requires { c.emplace(c.end(), declval<Ref>()); }) c.emplace(c.end(), std::forward<Ref>(ref)); else c.insert(c.end(), std::forward<Ref>(ref)); };}
#### [25.5.7.2](#conv.to) ranges::to [[range.utility.conv.to]](range.utility.conv.to)
[🔗](#lib:to,ranges)
`template<class C, [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R, class... Args> requires (![view](range.view#concept:view "25.4.5Views[range.view]")<C>)
constexpr C to(R&& r, Args&&... args);
`
[1](#conv.to-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2415)
*Mandates*: C is a cv-unqualified class type[.](#conv.to-1.sentence-1)
[2](#conv.to-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2419)
*Returns*: An object of type C constructed from the elements of r in the following manner:
- [(2.1)](#conv.to-2.1)
If C does not satisfy [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") or[convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<range_reference_t<R>, range_value_t<C>> is true:
* [(2.1.1)](#conv.to-2.1.1)
If [constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<C, R, Args...> is true:C(std::forward<R>(r), std::forward<Args>(args)...)
* [(2.1.2)](#conv.to-2.1.2)
Otherwise, if[constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<C, from_range_t, R, Args...> is true:C(from_range, std::forward<R>(r), std::forward<Args>(args)...)
* [(2.1.3)](#conv.to-2.1.3)
Otherwise, if
+
[(2.1.3.1)](#conv.to-2.1.3.1)
[common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<R> is true,
+
[(2.1.3.2)](#conv.to-2.1.3.2)
the [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3Qualified names[expr.prim.id.qual]")iterator_traits<iterator_t<R>>::iterator_category is valid and denotes a type that models[derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<input_iterator_tag>, and
+
[(2.1.3.3)](#conv.to-2.1.3.3)
[constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<C, iterator_t<R>, sentinel_t<R>, Args...> is true:
C(ranges::begin(r), ranges::end(r), std::forward<Args>(args)...)
* [(2.1.4)](#conv.to-2.1.4)
Otherwise, if
+
[(2.1.4.1)](#conv.to-2.1.4.1)
[constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<C, Args...> is true, and
+
[(2.1.4.2)](#conv.to-2.1.4.2)
*container-appendable*<C, range_reference_t<R>> is true:
C c(std::forward<Args>(args)...);if constexpr ([approximately_sized_range](range.approximately.sized#concept:approximately_sized_range "25.4.3Approximately sized ranges[range.approximately.sized]")<R> && *reservable-container*<C>) c.reserve(static_cast<range_size_t<C>>(ranges::reserve_hint(r)));
ranges::for_each(r, *container-append*(c));
* [(2.1.5)](#conv.to-2.1.5)
Otherwise, the program is ill-formed[.](#conv.to-2.1.sentence-1)
- [(2.2)](#conv.to-2.2)
Otherwise,
if [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<R>> is true:to<C>(ref_view(r) | views::transform([](auto&& elem) {return to<range_value_t<C>>(std::forward<decltype(elem)>(elem));}), std::forward<Args>(args)...);
- [(2.3)](#conv.to-2.3)
Otherwise, the program is ill-formed[.](#conv.to-2.3.sentence-1)
[🔗](#lib:to,ranges_)
`template<template<class...> class C, [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R, class... Args>
constexpr auto to(R&& r, Args&&... args);
`
[3](#conv.to-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2497)
Let *input-iterator* be an exposition-only type:struct *input-iterator* { // *exposition only*using iterator_category = input_iterator_tag; using value_type = range_value_t<R>; using difference_type = ptrdiff_t; using pointer = add_pointer_t<range_reference_t<R>>; using reference = range_reference_t<R>;
reference operator*() const;
pointer operator->() const; *input-iterator*& operator++(); *input-iterator* operator++(int); bool operator==(const *input-iterator*&) const;};
[*Note [1](#conv.to-note-1)*:
*input-iterator* meets
the syntactic requirements of *Cpp17InputIterator*[.](#conv.to-3.sentence-1)
— *end note*]
[4](#conv.to-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2518)
Let *DEDUCE_EXPR* be defined as follows:
- [(4.1)](#conv.to-4.1)
C(declval<R>(), declval<Args>()...) if that is a valid expression,
- [(4.2)](#conv.to-4.2)
otherwise, C(from_range, declval<R>(), declval<Args>()...) if that is a valid expression,
- [(4.3)](#conv.to-4.3)
otherwise,C(declval<*input-iterator*>(), declval<*input-iterator*>(), declval<Args>()...) if that is a valid expression,
- [(4.4)](#conv.to-4.4)
otherwise, the program is ill-formed[.](#conv.to-4.sentence-1)
[5](#conv.to-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2536)
*Returns*: to<decltype(*DEDUCE_EXPR*)>(std::forward<R>(r), std::forward<Args>(args)...)[.](#conv.to-5.sentence-1)
#### [25.5.7.3](#conv.adaptors) ranges::to adaptors [[range.utility.conv.adaptors]](range.utility.conv.adaptors)
[🔗](#lib:to,ranges__)
`template<class C, class... Args> requires (![view](range.view#concept:view "25.4.5Views[range.view]")<C>)
constexpr auto to(Args&&... args);
template<template<class...> class C, class... Args>
constexpr auto to(Args&&... args);
`
[1](#conv.adaptors-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2552)
*Mandates*: For the first overload,C is a cv-unqualified class type[.](#conv.adaptors-1.sentence-1)
[2](#conv.adaptors-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L2557)
*Returns*: A range adaptor closure object ([[range.adaptor.object]](range.adaptor.object "25.7.2Range adaptor objects")) f that is a perfect forwarding call wrapper ([[func.require]](func.require#term.perfect.forwarding.call.wrapper "22.10.4Requirements"))
with the following properties:
- [(2.1)](#conv.adaptors-2.1)
It has no target object[.](#conv.adaptors-2.1.sentence-1)
- [(2.2)](#conv.adaptors-2.2)
Its bound argument entities bound_args consist of
objects of types decay_t<Args>... direct-non-list-initialized with std::forward<Args>(args)...,
respectively[.](#conv.adaptors-2.2.sentence-1)
- [(2.3)](#conv.adaptors-2.3)
Its call pattern is to<C>(r, bound_args...),
where r is the argument used in a function call expression of f[.](#conv.adaptors-2.3.sentence-1)