template<class R, class T>
  concept output_range =
    range<R> && output_iterator<iterator_t<R>, T>;
template<class T>
  concept input_range =
    range<T> && input_iterator<iterator_t<T>>;
template<class T>
  concept forward_range =
    input_range<T> && forward_iterator<iterator_t<T>>;
template<class T>
  concept bidirectional_range =
    forward_range<T> && bidirectional_iterator<iterator_t<T>>;
template<class T>
  concept random_access_range =
    bidirectional_range<T> && random_access_iterator<iterator_t<T>>;
template<class T>
  concept contiguous_range =
    random_access_range<T> && contiguous_iterator<iterator_t<T>> &&
    requires(T& t) {
      { ranges::data(t) } -> same_as<add_pointer_t<range_reference_t<T>>>;
    };
template<class T>
  concept common_range =
    range<T> && same_as<iterator_t<T>, sentinel_t<T>>;
template<class R>
  constexpr bool is-initializer-list = see below;               // exposition only
template<class T>
  concept viewable_range =
    range<T> &&
    ((view<remove_cvref_t<T>> && constructible_from<remove_cvref_t<T>, T>) ||
     (!view<remove_cvref_t<T>> &&
      (is_lvalue_reference_v<T> || (movable<remove_reference_t<T>> && !is-initializer-list<T>))));
template<class T>
  concept constant_range =
    input_range<T> && constant-iterator<iterator_t<T>>;