This Clause describes components for dealing with ranges of elements.

The following subclauses describe range and view requirements, and components for range primitives as summarized in Table [tab:ranges.lib.summary].

Table 9 — Ranges library summary

Subclause | Header(s) | |

[range.access] | Range access | <experimental/ranges/range> |

[range.primitives] | Range primitives | |

[ranges.requirements] | Requirements |

Several places in this Clause use the expression *DECAY_COPY*(x),
which is expression-equivalent to:

decay_t<decltype((x))>(x)

#include <experimental/ranges/iterator> namespace std { namespace experimental { namespace ranges { inline namespace v1 { // [range.access], range access: namespace { constexprunspecifiedbegin =unspecified; constexprunspecifiedend =unspecified; constexprunspecifiedcbegin =unspecified; constexprunspecifiedcend =unspecified; constexprunspecifiedrbegin =unspecified; constexprunspecifiedrend =unspecified; constexprunspecifiedcrbegin =unspecified; constexprunspecifiedcrend =unspecified; } // [range.primitives], range primitives: namespace { constexprunspecifiedsize =unspecified; constexprunspecifiedempty =unspecified; constexprunspecifieddata =unspecified; constexprunspecifiedcdata =unspecified; } template <class T> using iterator_t = decltype(ranges::begin(declval<T&>())); template <class T> using sentinel_t = decltype(ranges::end(declval<T&>())); template <class> constexpr bool disable_sized_range = false; template <class T> struct enable_view { }; struct view_base { }; // [ranges.requirements], range requirements: // [ranges.range], Range: template <class T> concept bool Range =see below; // [ranges.sized], SizedRange: template <class T> concept bool SizedRange =see below; // [ranges.view], View: template <class T> concept bool View =see below; // [ranges.bounded], BoundedRange: template <class T> concept bool BoundedRange =see below; // [ranges.input], InputRange: template <class T> concept bool InputRange =see below; // [ranges.output], OutputRange: template <class R, class T> concept bool OutputRange =see below; // [ranges.forward], ForwardRange: template <class T> concept bool ForwardRange =see below; // [ranges.bidirectional], BidirectionalRange: template <class T> concept bool BidirectionalRange =see below; // [ranges.random.access], RandomAccessRange: template <class T> concept bool RandomAccessRange =see below; }}}}

In addition to being available via inclusion of the <experimental/ranges/range> header, the customization point objects in [range.access] are available when <experimental/ranges/iterator> is included.

The name begin denotes a customization point object ([customization.point.object]). The expression ranges::begin(E) for some subexpression E is expression-equivalent to:

ranges::begin(static_cast<const T&>(E)) if E is an rvalue of type T. This usage is deprecated. [

*Note:*This deprecated usage exists so that ranges::begin(E) behaves similarly to std::begin(E) as defined in ISO/IEC 14882 when E is an rvalue.*— end note*]Otherwise, (E) + 0 if E has array type ( ISO/IEC 14882:2014 §[basic.compound]).

Otherwise,

*DECAY_COPY*((E).begin()) if it is a valid expression and its type I meets the syntactic requirements of Iterator<I>. If Iterator is not satisfied, the program is ill-formed with no diagnostic required.Otherwise,

*DECAY_COPY*(begin(E)) if it is a valid expression and its type I meets the syntactic requirements of Iterator<I> with overload resolution performed in a context that includes the declaration void begin(auto&) = delete; and does not include a declaration of ranges::begin. If Iterator is not satisfied, the program is ill-formed with no diagnostic required.Otherwise, ranges::begin(E) is ill-formed.

[ *Note:* Whenever ranges::begin(E) is a valid expression, its
type satisfies Iterator. * — end note* ]

The name end denotes a customization point object ([customization.point.object]). The expression ranges::end(E) for some subexpression E is expression-equivalent to:

ranges::end(static_cast<const T&>(E)) if E is an rvalue of type T. This usage is deprecated. [

*Note:*This deprecated usage exists so that ranges::end(E) behaves similarly to std::end(E) as defined in ISO/IEC 14882 when E is an rvalue.*— end note*]Otherwise, (E) + extent<T>::value if E has array type ( ISO/IEC 14882:2014 §[basic.compound]) T.

Otherwise,

*DECAY_COPY*((E).end()) if it is a valid expression and its type S meets the syntactic requirements of Sentinel<S, decltype(ranges::begin(E))>. If Sentinel is not satisfied, the program is ill-formed with no diagnostic required.Otherwise,

*DECAY_COPY*(end(E)) if it is a valid expression and its type S meets the syntactic requirements of Sentinel<S, decltype(ranges::begin(E))> with overload resolution performed in a context that includes the declaration void end(auto&) = delete; and does not include a declaration of ranges::end. If Sentinel is not satisfied, the program is ill-formed with no diagnostic required.Otherwise, ranges::end(E) is ill-formed.

[ *Note:* Whenever ranges::end(E) is a valid expression, the
types of ranges::end(E) and ranges::begin(E) satisfy
Sentinel. * — end note* ]

The name cbegin denotes a customization point object ([customization.point.object]). The expression ranges::cbegin(E) for some subexpression E of type T is expression-equivalent to ranges::begin(static_cast<const T&>(E)).

Use of ranges::cbegin(E) with rvalue E is deprecated.
[ *Note:* This deprecated usage exists so that ranges::cbegin(E)
behaves similarly to std::cbegin(E) as defined in ISO/IEC 14882 when
E is an rvalue. * — end note* ]

[ *Note:* Whenever ranges::cbegin(E) is a valid expression, its
type satisfies Iterator. * — end note* ]

The name cend denotes a customization point object ([customization.point.object]). The expression ranges::cend(E) for some subexpression E of type T is expression-equivalent to ranges::end(static_cast<const T&>(E)).

Use of ranges::cend(E) with rvalue E is deprecated.
[ *Note:* This deprecated usage exists so that ranges::cend(E)
behaves similarly to std::cend(E) as defined in ISO/IEC 14882 when
E is an rvalue. * — end note* ]

[ *Note:* Whenever ranges::cend(E) is a valid expression, the
types of ranges::cend(E) and ranges::cbegin(E) satisfy
Sentinel. * — end note* ]

The name rbegin denotes a customization point object ([customization.point.object]). The expression ranges::rbegin(E) for some subexpression E is expression-equivalent to:

ranges::rbegin(static_cast<const T&>(E)) if E is an rvalue of type T. This usage is deprecated. [

*Note:*This deprecated usage exists so that ranges::rbegin(E) behaves similarly to std::rbegin(E) as defined in ISO/IEC 14882 when E is an rvalue.*— end note*]Otherwise,

*DECAY_COPY*((E).rbegin()) if it is a valid expression and its type I meets the syntactic requirements of Iterator<I>. If Iterator is not satisfied, the program is ill-formed with no diagnostic required.Otherwise, make_reverse_iterator(ranges::end(E)) if both ranges::begin(E) and ranges::end(E) are valid expressions of the same type I which meets the syntactic requirements of BidirectionalIterator<I> ([iterators.bidirectional]).

Otherwise, ranges::rbegin(E) is ill-formed.

[ *Note:* Whenever ranges::rbegin(E) is a valid expression, its
type satisfies Iterator. * — end note* ]

The name rend denotes a customization point object ([customization.point.object]). The expression ranges::rend(E) for some subexpression E is expression-equivalent to:

ranges::rend(static_cast<const T&>(E)) if E is an rvalue of type T. This usage is deprecated. [

*Note:*This deprecated usage exists so that ranges::rend(E) behaves similarly to std::rend(E) as defined in ISO/IEC 14882 when E is an rvalue.*— end note*]Otherwise,

*DECAY_COPY*((E).rend()) if it is a valid expression and its type S meets the syntactic requirements of Sentinel<S, decltype(ranges::rbegin(E))>. If Sentinel is not satisfied, the program is ill-formed with no diagnostic required.Otherwise, make_reverse_iterator(ranges::begin(E)) if both ranges::begin(E) and ranges::end(E) are valid expressions of the same type I which meets the syntactic requirements of BidirectionalIterator<I> ([iterators.bidirectional]).

Otherwise, ranges::rend(E) is ill-formed.

[ *Note:* Whenever ranges::rend(E) is a valid expression, the
types of ranges::rend(E) and ranges::rbegin(E) satisfy
Sentinel. * — end note* ]

The name crbegin denotes a customization point object ([customization.point.object]). The expression ranges::crbegin(E) for some subexpression E of type T is expression-equivalent to ranges::rbegin(static_cast<const T&>(E)).

Use of ranges::crbegin(E) with rvalue E is deprecated.
[ *Note:* This deprecated usage exists so that ranges::crbegin(E)
behaves similarly to std::crbegin(E) as defined in ISO/IEC 14882 when
E is an rvalue. * — end note* ]

[ *Note:* Whenever ranges::crbegin(E) is a valid expression, its
type satisfies Iterator. * — end note* ]

The name crend denotes a customization point object ([customization.point.object]). The expression ranges::crend(E) for some subexpression E of type T is expression-equivalent to ranges::rend(static_cast<const T&>(E)).

Use of ranges::crend(E) with rvalue E is deprecated.
[ *Note:* This deprecated usage exists so that ranges::crend(E)
behaves similarly to std::crend(E) as defined in ISO/IEC 14882 when
E is an rvalue. * — end note* ]

[ *Note:* Whenever ranges::crend(E) is a valid expression, the
types of ranges::crend(E) and ranges::crbegin(E) satisfy
Sentinel. * — end note* ]

In addition to being available via inclusion of the <experimental/ranges/range> header, the customization point objects in [range.primitives] are available when <experimental/ranges/iterator> is included.

The name size denotes a customization point object ([customization.point.object]). The expression ranges::size(E) for some subexpression E with type T is expression-equivalent to:

*DECAY_COPY*(extent<T>::value) if T is an array type ( ISO/IEC 14882:2014 §[basic.compound]).Otherwise,

*DECAY_COPY*(static_cast<const T&>(E).size()) if it is a valid expression and its type I satisfies Integral<I> and disable_sized_range<T> ([ranges.sized]) is false.Otherwise,

*DECAY_COPY*(size(static_cast<const T&>(E))) if it is a valid expression and its type I satisfies Integral<I> with overload resolution performed in a context that includes the declaration void size(const auto&) = delete; and does not include a declaration of ranges::size, and disable_sized_range<T> is false.Otherwise,

*DECAY_COPY*(ranges::cend(E) - ranges::cbegin(E)), except that E is only evaluated once, if it is a valid expression and the types I and S of ranges::cbegin(E) and ranges::cend(E) meet the syntactic requirements of SizedSentinel<S, I> ([iterators.sizedsentinel]) and ForwardIterator<I>. If SizedSentinel and ForwardIterator are not satisfied, the program is ill-formed with no diagnostic required.Otherwise, ranges::size(E) is ill-formed.

[ *Note:* Whenever ranges::size(E) is a valid expression, its
type satisfies Integral. * — end note* ]

The name empty denotes a customization point object ([customization.point.object]). The expression ranges::empty(E) for some subexpression E is expression-equivalent to:

bool((E).empty()) if it is a valid expression.

Otherwise, ranges::size(E) == 0 if it is a valid expression.

Otherwise, bool(ranges::begin(E) == ranges::end(E)), except that E is only evaluated once, if it is a valid expression and the type of ranges::begin(E) satisfies ForwardIterator.

Otherwise, ranges::empty(E) is ill-formed.

[ *Note:* Whenever ranges::empty(E) is a valid expression, it
has type bool. * — end note* ]

The name data denotes a customization point object ([customization.point.object]). The expression ranges::data(E) for some subexpression E is expression-equivalent to:

ranges::data(static_cast<const T&>(E)) if E is an rvalue of type T. This usage is deprecated. [

*Note:*This deprecated usage exists so that ranges::data(E) behaves similarly to std::data(E) as defined in the C++ Working Paper when E is an rvalue.*— end note*]Otherwise,

*DECAY_COPY*((E).data()) if it is a valid expression of pointer to object type.Otherwise, ranges::begin(E) if it is a valid expression of pointer to object type.

Otherwise, ranges::data(E) is ill-formed.

[ *Note:* Whenever ranges::data(E) is a valid expression, it
has pointer to object type. * — end note* ]

The name cdata denotes a customization point object ([customization.point.object]). The expression ranges::cdata(E) for some subexpression E of type T is expression-equivalent to ranges::data(static_cast<const T&>(E)).

Use of ranges::cdata(E) with rvalue E is deprecated.
[ *Note:* This deprecated usage exists so that ranges::cdata(E)
has behavior consistent with ranges::data(E) when E is
an rvalue. * — end note* ]

[ *Note:* Whenever ranges::cdata(E) is a valid expression, it
has pointer to object type. * — end note* ]

Ranges are an abstraction of containers that allow a C++ program to operate on elements of data structures uniformly. It their simplest form, a range object is one on which one can call begin and end to get an iterator ([iterators.iterator]) and a sentinel ([iterators.sentinel]). To be able to construct template algorithms and range adaptors that work correctly and efficiently on different types of sequences, the library formalizes not just the interfaces but also the semantics and complexity assumptions of ranges.

This document defines three fundamental categories of ranges
based on the syntax and semantics supported by each: *range*,
*sized range* and *view*, as shown in
Table [tab:ranges.relations].

The Range concept requires only that begin and end return an iterator and a sentinel. The SizedRange concept refines Range with the requirement that the number of elements in the range can be determined in constant time using the size function. The View concept specifies requirements on a Range type with constant-time copy and assign operations.

In addition to the three fundamental range categories, this document defines
a number of convenience refinements of Range that group together requirements
that appear often in the concepts and algorithms.
*Bounded ranges* are ranges for which begin and end return objects of the
same type. *Random access ranges* are ranges for which
begin returns a type that satisfies
RandomAccessIterator ([iterators.random.access]). The range
categories *bidirectional ranges*,
*forward ranges*,
*input ranges*, and
*output ranges* are defined similarly.

The Range concept defines the requirements of a type that allows
iteration over its elements by providing a begin iterator and an
end sentinel.
[ *Note:* Most algorithms requiring this concept simply forward to an
Iterator-based algorithm by calling begin and end. * — end note* ]

```
template <class T>
concept bool Range =
requires(T&& t) {
ranges::begin(t); // not necessarily equality-preserving (see below)
ranges::end(t);
};
```

Given an lvalue t of type remove_reference_t<T>, Range<T> is satisfied only if

[begin(t),end(t)) denotes a range.

Both begin(t) and end(t) are amortized constant time and non-modifying. [

*Note:*begin(t) and end(t) do not require implicit expression variations ([concepts.lib.general.equality]).*— end note*]If iterator_t<T> satisfies ForwardIterator, begin(t) is equality preserving.

[ *Note:*
Equality preservation of both begin and end enables passing a Range
whose iterator type satisfies ForwardIterator
to multiple algorithms and
making multiple passes over the range by repeated calls to begin and end.
Since begin is not required to be equality preserving when the return type does
not satisfy ForwardIterator, repeated calls might not return equal values or
might not be well-defined; begin should be called at most once for such a range.
* — end note* ]

The SizedRange concept specifies the requirements of a Range type that knows its size in constant time with the size function.

```
template <class T>
concept bool SizedRange =
Range<T> &&
!disable_sized_range<remove_cv_t<remove_reference_t<T>>> &&
requires(T& t) {
{ ranges::size(t) } -> ConvertibleTo<difference_type_t<iterator_t<T>>>;
};
```

Given an lvalue t of type remove_reference_t<T>, SizedRange<T> is satisfied only if:

ranges::size(t) is Ο(1), does not modify t, and is equal to ranges::distance(t).

If iterator_t<T> satisfies ForwardIterator, size(t) is well-defined regardless of the evaluation of begin(t). [

*Note:*size(t) is otherwise not required be well-defined after evaluating begin(t). For a SizedRange whose iterator type does not model ForwardIterator, for example, size(t) might only be well-defined if evaluated before the first call to begin(t).*— end note*]

[ *Note:* The disable_sized_range predicate provides a mechanism to enable use
of range types with the library that meet the syntactic requirements but do
not in fact satisfy SizedRange. A program that instantiates a library template
that requires a Range with such a range type R is ill-formed with no
diagnostic required unless
disable_sized_range<remove_cv_t<remove_reference_t<R>>> evaluates
to true ([structure.requirements]). * — end note* ]

The View concept specifies the requirements of a Range type that has constant time copy, move and assignment operators; that is, the cost of these operations is not proportional to the number of elements in the View.

[ *Example:*
Examples of Views are:

A Range type that wraps a pair of iterators.

A Range type that holds its elements by shared_ptr and shares ownership with all its copies.

A Range type that generates its elements on demand.

A container ( ISO/IEC 14882:2014 §[containers]) is not a View since copying the
container copies the elements, which cannot be done in constant time.
* — end example* ]

```
template <class T>
constexpr bool
```

*view-predicate* // *exposition only*
= *see below*;
template <class T>
concept bool View =
Range<T> &&
Semiregular<T> &&
*view-predicate*<T>;

Since the difference between Range and View is largely semantic, the two are differentiated with the help of the enable_view trait. Users may specialize enable_view to derive from true_type or false_type.

For a type T, the value of *view-predicate*<T> shall be:

If enable_view<T> has a member type type, enable_view<T>::type::value;

Otherwise, if T is derived from view_base, true;

Otherwise, if T is an instantiation of class template initializer_list ( ISO/IEC 14882:2014 §[support.initlist]), set ( ISO/IEC 14882:2014 §[set]), multiset ( ISO/IEC 14882:2014 §[multiset]), unordered_set ( ISO/IEC 14882:2014 §[unord.set]), or unordered_multiset ( ISO/IEC 14882:2014 §[unord.multiset]), false;

Otherwise, if both T and const T satisfy Range and reference_t<iterator_t<T>> is not the same type as reference_t<iterator_t<const T>>, false; [

*Note:*Deep const-ness implies element ownership, whereas shallow const-ness implies reference semantics.*— end note*]Otherwise, true.

The BoundedRange concept specifies requirements
of a Range type for which begin and end return objects of
the same type. [ *Note:* The standard containers ( ISO/IEC 14882:2014 §[containers])
satisfy BoundedRange.* — end note* ]

template <class T> concept bool BoundedRange = Range<T> && Same<iterator_t<T>, sentinel_t<T>>;

The InputRange concept specifies requirements of a Range type for which begin returns a type that satisfies InputIterator ([iterators.input]).

template <class T> concept bool InputRange = Range<T> && InputIterator<iterator_t<T>>;

The OutputRange concept specifies requirements of a Range type for which begin returns a type that satisfies OutputIterator ([iterators.output]).

template <class R, class T> concept bool OutputRange = Range<R> && OutputIterator<iterator_t<R>, T>;

The ForwardRange concept specifies requirements of an InputRange type for which begin returns a type that satisfies ForwardIterator ([iterators.forward]).

template <class T> concept bool ForwardRange = InputRange<T> && ForwardIterator<iterator_t<T>>;

The BidirectionalRange concept specifies requirements of a ForwardRange type for which begin returns a type that satisfies BidirectionalIterator ([iterators.bidirectional]).

template <class T> concept bool BidirectionalRange = ForwardRange<T> && BidirectionalIterator<iterator_t<T>>;

The RandomAccessRange concept specifies requirements of a BidirectionalRange type for which begin returns a type that satisfies RandomAccessIterator ([iterators.random.access]).

template <class T> concept bool RandomAccessRange = BidirectionalRange<T> && RandomAccessIterator<iterator_t<T>>;