The Range concept defines the requirements of a type that allows
iteration over its elements by providing an iterator and sentinel
that denote the elements of the range.

```
template<class T>
concept range-impl = // exposition only
requires(T&& t) {
ranges::begin(std::forward<T>(t)); // sometimes equality-preserving (see below)
ranges::end(std::forward<T>(t));
};
template<class T>
concept Range = range-impl<T&>;
template<class T>
concept forwarding-range = // exposition only
Range<T> && range-impl<T>;
```

The required expressions
ranges::begin(std::forward<T>(t))
and
ranges::end(std::forward<T>(t))
of the range-impl concept
do not require implicit expression variations ([concepts.equality]).

Given an expression E such that decltype((E)) is T,
T models range-impl only if

- both ranges::begin(E) and ranges::end(E) are amortized constant time and non-modifying, and

[βNote

: *end note*

β]Equality preservation of both ranges::begin and
ranges::end enables passing a Range whose iterator
type models ForwardIterator to multiple
algorithms and making multiple passes over the range by repeated calls to
ranges::begin and ranges::end.

Since ranges::begin is not required to be equality-preserving
when the return type does not model ForwardIterator, repeated calls
might not return equal values or might not be well-defined;
ranges::begin should be called at most once for such a range.

ββGiven an expression E such that decltype((E)) is T
and an lvalue t that denotes the same object as E,
T models forwarding-range only if

- ranges::begin(E) and ranges::begin(t) are expression-equivalent,
- ranges::end(E) and ranges::end(t) are expression-equivalent, and
- the validity of iterators obtained from the object denoted by E is not tied to the lifetime of that object.