24 Ranges library [ranges]

24.3 Range access [range.access]

24.3.1 General [range.access.general]

In addition to being available via inclusion of the <ranges> header, the customization point objects in [range.access] are available when <iterator> is included.
Within [range.access], the reified object of a subexpression E denotes
  • the same object as E if E is a glvalue, or
  • the result of applying the temporary materialization conversion ([conv.rval]) to E otherwise.

24.3.2 ranges​::​begin [range.access.begin]

The name ranges​::​begin denotes a customization point object ([customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If E is an rvalue and enable_­borrowed_­range<remove_­cv_­t<T>> is false, ranges​::​begin(E) is ill-formed.
  • Otherwise, if T is an array type ([basic.compound]) and remove_­all_­extents_­t<T> is an incomplete type, ranges​::​begin(E) is ill-formed with no diagnostic required.
  • Otherwise, if T is an array type, ranges​::​begin(E) is expression-equivalent to t + 0.
  • Otherwise, if decay-copy(t.begin()) is a valid expression whose type models input_­or_­output_­iterator, ranges​::​begin(E) is expression-equivalent to decay-copy(t.begin()).
  • Otherwise, if T is a class or enumeration type and decay-copy(begin(t)) is a valid expression whose type models input_­or_­output_­iterator with overload resolution performed in a context in which unqualified lookup for begin finds only the declarations void begin(auto&) = delete; void begin(const auto&) = delete; then ranges​::​begin(E) is expression-equivalent to decay-copy(begin(t)) with overload resolution performed in the above context.
  • Otherwise, ranges​::​begin(E) is ill-formed.
[Note 1:
Diagnosable ill-formed cases above result in substitution failure when ranges​::​begin(E) appears in the immediate context of a template instantiation.
— end note]
[Note 2:
Whenever ranges​::​begin(E) is a valid expression, its type models input_­or_­output_­iterator.
— end note]

24.3.3 ranges​::​end [range.access.end]

The name ranges​::​end denotes a customization point object ([customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If E is an rvalue and enable_­borrowed_­range<remove_­cv_­t<T>> is false, ranges​::​end(E) is ill-formed.
  • Otherwise, if T is an array type ([basic.compound]) and remove_­all_­extents_­t<T> is an incomplete type, ranges​::​end(E) is ill-formed with no diagnostic required.
  • Otherwise, if T is an array of unknown bound, ranges​::​end(E) is ill-formed.
  • Otherwise, if T is an array, ranges​::​end(E) is expression-equivalent to t + extent_­v<T>.
  • Otherwise, if decay-copy(t.end()) is a valid expression whose type models sentinel_­for<iterator_­t<T>> then ranges​::​end(E) is expression-equivalent to decay-copy(t.end()).
  • Otherwise, if T is a class or enumeration type and decay-copy(end(t)) is a valid expression whose type models sentinel_­for<iterator_­t<T>> with overload resolution performed in a context in which unqualified lookup for end finds only the declarations void end(auto&) = delete; void end(const auto&) = delete; then ranges​::​end(E) is expression-equivalent to decay-copy(end(t)) with overload resolution performed in the above context.
  • Otherwise, ranges​::​end(E) is ill-formed.
[Note 1:
Diagnosable ill-formed cases above result in substitution failure when ranges​::​end(E) appears in the immediate context of a template instantiation.
— end note]
[Note 2:
Whenever ranges​::​end(E) is a valid expression, the types S and I of ranges​::​end(E) and ranges​::​begin(E) model sentinel_­for<S, I>.
— end note]

24.3.4 ranges​::​cbegin [range.access.cbegin]

The name ranges​::​cbegin denotes a customization point object ([customization.point.object]).
The expression ranges​::​​cbegin(E) for a subexpression E of type T is expression-equivalent to:
  • ranges​::​begin(static_­cast<const T&>(E)) if E is an lvalue.
  • Otherwise, ranges​::​begin(static_­cast<const T&&>(E)).
[Note 1:
Whenever ranges​::​cbegin(E) is a valid expression, its type models input_­or_­output_­iterator.
— end note]

24.3.5 ranges​::​cend [range.access.cend]

The name ranges​::​cend denotes a customization point object ([customization.point.object]).
The expression ranges​::​cend(E) for a subexpression E of type T is expression-equivalent to:
  • ranges​::​end(static_­cast<const T&>(E)) if E is an lvalue.
  • Otherwise, ranges​::​end(static_­cast<const T&&>(E)).
[Note 1:
Whenever ranges​::​cend(E) is a valid expression, the types S and I of the expressions ranges​::​cend(E) and ranges​::​cbegin(E) model sentinel_­for<S, I>.
— end note]

24.3.6 ranges​::​rbegin [range.access.rbegin]

The name ranges​::​rbegin denotes a customization point object ([customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If E is an rvalue and enable_­borrowed_­range<remove_­cv_­t<T>> is false, ranges​::​rbegin(E) is ill-formed.
  • Otherwise, if T is an array type ([basic.compound]) and remove_­all_­extents_­t<T> is an incomplete type, ranges​::​rbegin(E) is ill-formed with no diagnostic required.
  • Otherwise, if decay-copy(t.rbegin()) is a valid expression whose type models input_­or_­output_­iterator, ranges​::​rbegin(E) is expression-equivalent to decay-copy(t.rbegin()).
  • Otherwise, if T is a class or enumeration type and decay-copy(rbegin(t)) is a valid expression whose type models input_­or_­output_­iterator with overload resolution performed in a context in which unqualified lookup for rbegin finds only the declarations void rbegin(auto&) = delete; void rbegin(const auto&) = delete; then ranges​::​rbegin(E) is expression-equivalent to decay-copy(rbegin(t)) with overload resolution performed in the above context.
  • Otherwise, if both ranges​::​begin(t) and ranges​::​end(t) are valid expressions of the same type which models bidirectional_­iterator ([iterator.concept.bidir]), ranges​::​rbegin(E) is expression-equivalent to make_­reverse_­iterator(ranges​::​end(t)).
  • Otherwise, ranges​::​rbegin(E) is ill-formed.
[Note 1:
Diagnosable ill-formed cases above result in substitution failure when ranges​::​rbegin(E) appears in the immediate context of a template instantiation.
— end note]
[Note 2:
Whenever ranges​::​rbegin(E) is a valid expression, its type models input_­or_­output_­iterator.
— end note]

24.3.7 ranges​::​rend [range.access.rend]

The name ranges​::​rend denotes a customization point object ([customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If E is an rvalue and enable_­borrowed_­range<remove_­cv_­t<T>> is false, ranges​::​rend(E) is ill-formed.
  • Otherwise, if T is an array type ([basic.compound]) and remove_­all_­extents_­t<T> is an incomplete type, ranges​::​rend(E) is ill-formed with no diagnostic required.
  • Otherwise, if decay-copy(t.rend()) is a valid expression whose type models sentinel_­for<decltype(ranges​::​rbegin(E))> then ranges​::​rend(E) is expression-equivalent to decay-copy(t.rend()).
  • Otherwise, if T is a class or enumeration type and decay-copy(rend(t)) is a valid expression whose type models sentinel_­for<decltype(ranges​::​rbegin(E))> with overload resolution performed in a context in which unqualified lookup for rend finds only the declarations void rend(auto&) = delete; void rend(const auto&) = delete; then ranges​::​rend(E) is expression-equivalent to decay-copy(rend(t)) with overload resolution performed in the above context.
  • Otherwise, if both ranges​::​begin(t) and ranges​::​end(t) are valid expressions of the same type which models bidirectional_­iterator ([iterator.concept.bidir]), then ranges​::​rend(E) is expression-equivalent to make_­reverse_­iterator(ranges​::​begin(t)).
  • Otherwise, ranges​::​rend(E) is ill-formed.
[Note 1:
Diagnosable ill-formed cases above result in substitution failure when ranges​::​rend(E) appears in the immediate context of a template instantiation.
— end note]
[Note 2:
Whenever ranges​::​rend(E) is a valid expression, the types S and I of the expressions ranges​::​rend(E) and ranges​::​rbegin(E) model sentinel_­for<S, I>.
— end note]

24.3.8 ranges​::​crbegin [range.access.crbegin]

The name ranges​::​crbegin denotes a customization point object ([customization.point.object]).
The expression ranges​::​​crbegin(E) for a subexpression E of type T is expression-equivalent to:
  • ranges​::​​rbegin(static_­cast<const T&>(E)) if E is an lvalue.
  • Otherwise, ranges​::​rbegin(static_­cast<const T&&>(E)).
[Note 1:
Whenever ranges​::​crbegin(E) is a valid expression, its type models input_­or_­output_­iterator.
— end note]

24.3.9 ranges​::​crend [range.access.crend]

The name ranges​::​crend denotes a customization point object ([customization.point.object]).
The expression ranges​::​​crend(E) for a subexpression E of type T is expression-equivalent to:
  • ranges​::​rend(static_­cast<const T&>(E)) if E is an lvalue.
  • Otherwise, ranges​::​rend(static_­cast<const T&&>(E)).
[Note 1:
Whenever ranges​::​crend(E) is a valid expression, the types S and I of the expressions ranges​::​crend(E) and ranges​::​crbegin(E) model sentinel_­for<S, I>.
— end note]

24.3.10 ranges​::​size [range.prim.size]

The name ranges​::​size denotes a customization point object ([customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If T is an array of unknown bound ([dcl.array]), ranges​::​size(E) is ill-formed.
  • Otherwise, if T is an array type, ranges​::​size(E) is expression-equivalent to decay-copy(extent_­v<T>).
  • Otherwise, if disable_­sized_­range<remove_­cv_­t<T>> ([range.sized]) is false and decay-copy(t.size()) is a valid expression of integer-like type ([iterator.concept.winc]), ranges​::​size(E) is expression-equivalent to decay-copy(t.size()).
  • Otherwise, if T is a class or enumeration type, disable_­sized_­range<remove_­cv_­t<T>> is false and decay-copy(size(t)) is a valid expression of integer-like type with overload resolution performed in a context in which unqualified lookup for size finds only the declarations void size(auto&) = delete; void size(const auto&) = delete; then ranges​::​size(E) is expression-equivalent to decay-copy(size(t)) with overload resolution performed in the above context.
  • Otherwise, if to-unsigned-like(ranges​::​end(t) - ranges​::​begin(t)) ([ranges.syn]) is a valid expression and the types I and S of ranges​::​begin(t) and ranges​::​end(t) (respectively) model both sized_­sentinel_­for<S, I> ([iterator.concept.sizedsentinel]) and forward_­iterator<I>, then ranges​::​size(E) is expression-equivalent to to-unsigned-like(ranges​::​end(t) - ranges​::​begin(t)).
  • Otherwise, ranges​::​size(E) is ill-formed.
[Note 1:
Diagnosable ill-formed cases above result in substitution failure when ranges​::​size(E) appears in the immediate context of a template instantiation.
— end note]
[Note 2:
Whenever ranges​::​size(E) is a valid expression, its type is integer-like.
— end note]

24.3.11 ranges​::​ssize [range.prim.ssize]

The name ranges​::​ssize denotes a customization point object ([customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
If ranges​::​size(t) is ill-formed, ranges​::​ssize(E) is ill-formed.
Otherwise let D be make-signed-like-t<decltype(ranges​::​​size(t))>, or ptrdiff_­t if it is wider than that type; ranges​::​ssize(E) is expression-equivalent to static_­cast<D>(ranges​::​size(t)).

24.3.12 ranges​::​empty [range.prim.empty]

The name ranges​::​empty denotes a customization point object ([customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If T is an array of unknown bound ([basic.compound]), ranges​::​empty(E) is ill-formed.
  • Otherwise, if bool(t.empty()) is a valid expression, ranges​::​empty(E) is expression-equivalent to bool(t.empty()).
  • Otherwise, if (ranges​::​size(t) == 0) is a valid expression, ranges​::​empty(E) is expression-equivalent to (ranges​::​size(t) == 0).
  • Otherwise, if bool(ranges​::​begin(t) == ranges​::​end(t)) is a valid expression and the type of ranges​::​begin(t) models forward_­iterator, ranges​::​empty(E) is expression-equivalent to bool(​ranges​::​begin(t) == ranges​::​end(t)).
  • Otherwise, ranges​::​empty(E) is ill-formed.
[Note 1:
Diagnosable ill-formed cases above result in substitution failure when ranges​::​empty(E) appears in the immediate context of a template instantiation.
— end note]
[Note 2:
Whenever ranges​::​empty(E) is a valid expression, it has type bool.
— end note]

24.3.13 ranges​::​data [range.prim.data]

The name ranges​::​data denotes a customization point object ([customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If E is an rvalue and enable_­borrowed_­range<remove_­cv_­t<T>> is false, ranges​::​data(E) is ill-formed.
  • Otherwise, if T is an array type ([basic.compound]) and remove_­all_­extents_­t<T> is an incomplete type, ranges​::​data(E) is ill-formed with no diagnostic required.
  • Otherwise, if decay-copy(t.data()) is a valid expression of pointer to object type, ranges​::​data(E) is expression-equivalent to decay-copy(t.data()).
  • Otherwise, if ranges​::​begin(t) is a valid expression whose type models contiguous_­iterator, ranges​::​data(E) is expression-equivalent to to_­address(ranges​::​begin(E)).
  • Otherwise, ranges​::​data(E) is ill-formed.
[Note 1:
Diagnosable ill-formed cases above result in substitution failure when ranges​::​data(E) appears in the immediate context of a template instantiation.
— end note]
[Note 2:
Whenever ranges​::​data(E) is a valid expression, it has pointer to object type.
— end note]

24.3.14 ranges​::​cdata [range.prim.cdata]

The name ranges​::​cdata denotes a customization point object ([customization.point.object]).
The expression ranges​::​​cdata(E) for a subexpression E of type T is expression-equivalent to:
  • ranges​::​data(static_­cast<const T&>(E)) if E is an lvalue.
  • Otherwise, ranges​::​data(static_­cast<const T&&>(E)).
[Note 1:
Whenever ranges​::​cdata(E) is a valid expression, it has pointer to object type.
— end note]