26 Ranges library [ranges]

26.7 Range adaptors [range.adaptors]

26.7.10 Take view [range.take]

26.7.10.1 Overview [range.take.overview]

take_view produces a view of the first N elements from another view, or all the elements if the adapted view contains fewer than N.
The name views​::​take denotes a range adaptor object ([range.adaptor.object]).
Let E and F be expressions, let T be remove_cvref_t<decltype((E))>, and let D be range_difference_t<decltype((E))>.
If decltype((F)) does not model convertible_to<D>, views​::​take(E, F) is ill-formed.
Otherwise, the expression views​::​take(E, F) is expression-equivalent to:
  • If T is a specialization of empty_view ([range.empty.view]), then ((void)F, decay-copy(E)), except that the evaluations of E and F are indeterminately sequenced.
  • Otherwise, if T models random_access_range and sized_range and is a specialization of span ([views.span]), basic_string_view ([string.view]), or subrange ([range.subrange]), then U(ranges​::​begin(E), ranges​::​begin(E) + std​::​min<D>(ranges​::​distance(E), F)), except that E is evaluated only once, where U is a type determined as follows:
    • if T is a specialization of span, then U is span<typename T​::​element_type>;
    • otherwise, if T is a specialization of basic_string_view, then U is T;
    • otherwise, T is a specialization of subrange, and U is subrange<iterator_t<T>>;
  • otherwise, if T is a specialization of iota_view ([range.iota.view]) that models random_access_range and sized_range, then iota_view(*ranges​::​begin(E), *(ranges​::​begin(E) + std​::​
    min<D>(ranges​::​distance(E), F)))
    , except that E is evaluated only once.
  • Otherwise, if T is a specialization of repeat_view ([range.repeat.view]):
    • if T models sized_range, then views::repeat(*E.value_, std::min<D>(ranges::distance(E), F)) except that E is evaluated only once;
    • otherwise, views​::​repeat(*E.value_, static_cast<D>(F)).
  • Otherwise, take_view(E, F).
[Example 1: vector<int> is{0,1,2,3,4,5,6,7,8,9}; for (int i : is | views::take(5)) cout << i << ' '; // prints 0 1 2 3 4 — end example]

26.7.10.2 Class template take_view [range.take.view]

namespace std::ranges { template<view V> class take_view : public view_interface<take_view<V>> { private: V base_ = V(); // exposition only range_difference_t<V> count_ = 0; // exposition only // [range.take.sentinel], class template take_view​::​sentinel template<bool> class sentinel; // exposition only public: take_view() requires default_initializable<V> = default; constexpr explicit take_view(V base, range_difference_t<V> count); constexpr V base() const & requires copy_constructible<V> { return base_; } constexpr V base() && { return std::move(base_); } constexpr auto begin() requires (!simple-view<V>) { if constexpr (sized_range<V>) { if constexpr (random_access_range<V>) { return ranges::begin(base_); } else { auto sz = range_difference_t<V>(size()); return counted_iterator(ranges::begin(base_), sz); } } else if constexpr (sized_sentinel_for<sentinel_t<V>, iterator_t<V>>) { auto it = ranges::begin(base_); auto sz = std::min(count_, ranges::end(base_) - it); return counted_iterator(std::move(it), sz); } else { return counted_iterator(ranges::begin(base_), count_); } } constexpr auto begin() const requires range<const V> { if constexpr (sized_range<const V>) { if constexpr (random_access_range<const V>) { return ranges::begin(base_); } else { auto sz = range_difference_t<const V>(size()); return counted_iterator(ranges::begin(base_), sz); } } else if constexpr (sized_sentinel_for<sentinel_t<const V>, iterator_t<const V>>) { auto it = ranges::begin(base_); auto sz = std::min(count_, ranges::end(base_) - it); return counted_iterator(std::move(it), sz); } else { return counted_iterator(ranges::begin(base_), count_); } } constexpr auto end() requires (!simple-view<V>) { if constexpr (sized_range<V>) { if constexpr (random_access_range<V>) return ranges::begin(base_) + range_difference_t<V>(size()); else return default_sentinel; } else if constexpr (sized_sentinel_for<sentinel_t<V>, iterator_t<V>>) { return default_sentinel; } else { return sentinel<false>{ranges::end(base_)}; } } constexpr auto end() const requires range<const V> { if constexpr (sized_range<const V>) { if constexpr (random_access_range<const V>) return ranges::begin(base_) + range_difference_t<const V>(size()); else return default_sentinel; } else if constexpr (sized_sentinel_for<sentinel_t<const V>, iterator_t<const V>>) { return default_sentinel; } else { return sentinel<true>{ranges::end(base_)}; } } constexpr auto size() requires sized_range<V> { auto n = ranges::size(base_); return ranges::min(n, static_cast<decltype(n)>(count_)); } constexpr auto size() const requires sized_range<const V> { auto n = ranges::size(base_); return ranges::min(n, static_cast<decltype(n)>(count_)); } }; template<class R> take_view(R&&, range_difference_t<R>) -> take_view<views::all_t<R>>; }
constexpr explicit take_view(V base, range_difference_t<V> count);
Preconditions: count >= 0 is true.
Effects: Initializes base_ with std​::​move(base) and count_ with count.

26.7.10.3 Class template take_view​::​sentinel [range.take.sentinel]

namespace std::ranges { template<view V> template<bool Const> class take_view<V>::sentinel { private: using Base = maybe-const<Const, V>; // exposition only template<bool OtherConst> using CI = counted_iterator<iterator_t<maybe-const<OtherConst, V>>>; // exposition only sentinel_t<Base> end_ = sentinel_t<Base>(); // exposition only public: sentinel() = default; constexpr explicit sentinel(sentinel_t<Base> end); constexpr sentinel(sentinel<!Const> s) requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>; constexpr sentinel_t<Base> base() const; friend constexpr bool operator==(const CI<Const>& y, const sentinel& x); template<bool OtherConst = !Const> requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> friend constexpr bool operator==(const CI<OtherConst>& y, const sentinel& x); }; }
constexpr explicit sentinel(sentinel_t<Base> end);
Effects: Initializes end_ with end.
constexpr sentinel(sentinel<!Const> s) requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;
Effects: Initializes end_ with std​::​move(s.end_).
constexpr sentinel_t<Base> base() const;
Effects: Equivalent to: return end_;
friend constexpr bool operator==(const CI<Const>& y, const sentinel& x); template<bool OtherConst = !Const> requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> friend constexpr bool operator==(const CI<OtherConst>& y, const sentinel& x);
Effects: Equivalent to: return y.count() == 0 || y.base() == x.end_;