std::ranges::Range

From cppreference.com
< cpp‎ | ranges
Defined in header <ranges>
template< class T >
concept Range = __RangeImpl<T&>; // exposition-only definition
(1)
// exposition-only helper concept

template< class T >
concept __RangeImpl = requires(T&& t) {
  ranges::begin(std::forward<T>(t)); // equality-preserving for forward iterators
  ranges::end  (std::forward<T>(t));

};
(2)
// exposition-only helper concept

template< class T >

concept __ForwardingRange = Range<T> && __RangeImpl<T>;
(3)
1) 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.

Formally, given an expression E such that decltype((E)) is T, T models Range only if

  • [ranges::begin(E), ranges::end(E)) denotes a range, and
  • both ranges::begin(E) and ranges::end(E) are amortized constant time and non-modifying, and
  • if the type of ranges::begin(E) models ForwardIterator, ranges::begin(E) is equality-preserving (in other words, forward iterators support multi-pass algorithms)
Note: In the exposition-only definition above, the required expressions ranges::begin(std::forward<T>(t)) and ranges::end(std::forward<T>(t)) do not require implicit expression variations.
3) The exposition-only concept __ForwardingRange defines the requirements of a range such that a function can take it by value and return iterators obtained from it without danger of dangling.

Formally, given an expression E such that decltype((E)) is T and an lvalue t that denotes the same object as E, T models __ForwardingRange only if

  • ranges::begin(E) and ranges::begin(t) are expression-equivalent (have the same effect when evaluated, and both or neither are potentially-throwing, both or neither are constant subexpressions), and
  • 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.