25 Ranges library [ranges]

25.7 Range adaptors [range.adaptors]

25.7.8 Filter view [range.filter]


25.7.8.1 Overview [range.filter.overview]

25.7.8.2 Class template filter_view [range.filter.view]

25.7.8.3 Class template filter_view​::​iterator [range.filter.iterator]

25.7.8.4 Class template filter_view​::​sentinel [range.filter.sentinel]


25.7.8.1 Overview [range.filter.overview]

filter_view presents a view of the elements of an underlying sequence that satisfy a predicate.
The name views​::​filter denotes a range adaptor object ([range.adaptor.object]).
Given subexpressions E and P, the expression views​::​filter(E, P) is expression-equivalent to filter_view(E, P).
[Example 1: vector<int> is{ 0, 1, 2, 3, 4, 5, 6 }; auto evens = views::filter(is, [](int i) { return 0 == i % 2; }); for (int i : evens) cout << i << ' '; // prints 0 2 4 6 — end example]

25.7.8.2 Class template filter_view [range.filter.view]

namespace std::ranges { template<input_range V, indirect_unary_predicate<iterator_t<V>> Pred> requires view<V> && is_object_v<Pred> class filter_view : public view_interface<filter_view<V, Pred>> { private: V base_ = V(); // exposition only movable-box<Pred> pred_; // exposition only // [range.filter.iterator], class filter_view​::​iterator template<bool> class iterator; // exposition only // [range.filter.sentinel], class filter_view​::​sentinel template<bool> class sentinel; // exposition only public: filter_view() requires default_initializable<V> && default_initializable<Pred> = default; constexpr explicit filter_view(V base, Pred pred); constexpr V base() const & requires copy_constructible<V> { return base_; } constexpr V base() && { return std::move(base_); } constexpr const Pred& pred() const; constexpr iterator<false> begin(); constexpr iterator<true> begin() const requires (input_range<const V> && !forward_range<const V> && indirect_unary_predicate<const Pred, iterator_t<const V>>); constexpr auto end() { if constexpr (common_range<V>) return iterator<false>{*this, ranges::end(base_)}; else return sentinel<false>{*this}; } constexpr sentinel<true> end() const requires (input_range<const V> && !forward_range<const V> && indirect_unary_predicate<const Pred, iterator_t<const V>>) { return sentinel<true>{*this}; } }; template<class R, class Pred> filter_view(R&&, Pred) -> filter_view<views::all_t<R>, Pred>; }
constexpr explicit filter_view(V base, Pred pred);
Effects: Initializes base_ with std​::​move(base) and initializes pred_ with std​::​move(pred).
constexpr const Pred& pred() const;
Effects: Equivalent to: return *pred_;
constexpr iterator<false> begin();
Preconditions: pred_.has_value() is true.
Returns: {*this, ranges​::​find_if(base_, ref(*pred_))}.
Remarks: In order to provide the amortized constant time complexity required by the range concept when filter_view models forward_range, this function caches the result within the filter_view for use on subsequent calls.
constexpr iterator<true> begin() const requires (input_range<const V> && !forward_range<const V> && indirect_unary_predicate<const Pred, iterator_t<const V>>);
Preconditions: pred_.has_value() is true.
Returns: {*this, ranges​::​find_if(base_, ref(*pred_))}.
[Note 1: 
This function does not cache the result within the filter_view.
— end note]

25.7.8.3 Class template filter_view​::​iterator [range.filter.iterator]

namespace std::ranges { template<input_range V, indirect_unary_predicate<iterator_t<V>> Pred> requires view<V> && is_object_v<Pred> template<bool Const> class filter_view<V, Pred>::iterator { private: using Parent = maybe-const<Const, filter_view>; // exposition only using Base = maybe-const<Const, V>; // exposition only iterator_t<Base> current_ = iterator_t<Base>(); // exposition only Parent* parent_ = nullptr; // exposition only constexpr iterator(Parent& parent, iterator_t<Base> current); // exposition only public: using iterator_concept = see below; using iterator_category = see below; // not always present using value_type = range_value_t<Base>; using difference_type = range_difference_t<Base>; iterator() requires default_initializable<iterator_t<Base>> = default; constexpr iterator(iterator<!Const> i) requires Const && convertible_to<iterator_t<V>, iterator_t<Base>>; constexpr const iterator_t<Base>& base() const & noexcept; constexpr iterator_t<Base> base() &&; constexpr range_reference_t<Base> operator*() const; constexpr iterator_t<Base> operator->() const requires has-arrow<iterator_t<Base>> && copyable<iterator_t<Base>>; constexpr iterator& operator++(); constexpr void operator++(int); constexpr iterator operator++(int) requires forward_range<Base>; constexpr iterator& operator--() requires bidirectional_range<Base>; constexpr iterator operator--(int) requires bidirectional_range<Base>; friend constexpr bool operator==(const iterator& x, const iterator& y) requires equality_comparable<iterator_t<Base>>; friend constexpr range_rvalue_reference_t<Base> iter_move(const iterator& i) noexcept(noexcept(ranges::iter_move(i.current_))); friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(noexcept(ranges::iter_swap(x.current_, y.current_))) requires indirectly_swappable<iterator_t<Base>>; }; }
[Note 1: 
Modification of the element a filter_view​::​iterator denotes can result in undefined behavior if the underlying range is a forward_range and the resulting value does not satisfy the filter predicate when the predicate is next evaluated for that element ([concepts.equality]).
— end note]
iterator​::​iterator_concept is defined as follows:
  • If Const is true, then iterator_concept denotes input_iterator_tag.
  • Otherwise, if V models bidirectional_range, then iterator_concept denotes bidirectional_iterator_tag.
  • Otherwise, if V models forward_range, then iterator_concept denotes forward_iterator_tag.
  • Otherwise, iterator_concept denotes input_iterator_tag.
The member typedef-name iterator_category is declared if and only if Base models forward_range.
In that case, iterator​::​iterator_category is defined as follows:
  • Let C denote the type iterator_traits<iterator_t<Base>>​::​iterator_category.
  • If C models derived_from<bidirectional_iterator_tag>, then iterator_category denotes bidirectional_iterator_tag.
  • Otherwise, if C models derived_from<forward_iterator_tag>, then iterator_category denotes forward_iterator_tag.
  • Otherwise, iterator_category denotes C.
constexpr iterator(Parent& parent, iterator_t<Base> current);
Effects: Initializes current_ with std​::​move(current) and parent_ with addressof(parent).
constexpr iterator(iterator<!Const> i) requires Const && convertible_to<iterator_t<V>, iterator_t<Base>>;
Effects: Initializes parent_ with i.parent_ and current_ with std​::​move(i.current_).
constexpr const iterator_t<Base>& base() const & noexcept;
Effects: Equivalent to: return current_;
constexpr iterator_t<Base> base() &&;
Effects: Equivalent to: return std​::​move(current_);
constexpr range_reference_t<Base> operator*() const;
Effects: Equivalent to: return *current_;
constexpr iterator_t<Base> operator->() const requires has-arrow<iterator_t<Base>> && copyable<iterator_t<Base>>;
Effects: Equivalent to: return current_;
constexpr iterator& operator++();
Effects: Equivalent to: current_ = ranges::find_if(std::move(++current_), ranges::end(parent_->base_), ref(*parent_->pred_)); return *this;
constexpr void operator++(int);
Effects: Equivalent to ++*this.
constexpr iterator operator++(int) requires forward_range<Base>;
Effects: Equivalent to: auto tmp = *this; ++*this; return tmp;
constexpr iterator& operator--() requires bidirectional_range<Base>;
Effects: Equivalent to: do --current_; while (!invoke(*parent_->pred_, *current_)); return *this;
constexpr iterator operator--(int) requires bidirectional_range<Base>;
Effects: Equivalent to: auto tmp = *this; --*this; return tmp;
friend constexpr bool operator==(const iterator& x, const iterator& y) requires equality_comparable<iterator_t<Base>>;
Effects: Equivalent to: return x.current_ == y.current_;
friend constexpr range_rvalue_reference_t<Base> iter_move(const iterator& i) noexcept(noexcept(ranges::iter_move(i.current_)));
Effects: Equivalent to: return ranges​::​iter_move(i.current_);
friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(noexcept(ranges::iter_swap(x.current_, y.current_))) requires indirectly_swappable<iterator_t<Base>>;
Effects: Equivalent to ranges​::​iter_swap(x.current_, y.current_).

25.7.8.4 Class template filter_view​::​sentinel [range.filter.sentinel]

namespace std::ranges { template<input_range V, indirect_unary_predicate<iterator_t<V>> Pred> requires view<V> && is_object_v<Pred> template<bool Const> class filter_view<V, Pred>::sentinel { private: using Base = maybe-const<Const, V>; // exposition only sentinel_t<Base> end_ = sentinel_t<Base>(); // exposition only constexpr explicit sentinel(Parent& parent); // exposition only public: sentinel() = default; constexpr sentinel(sentinel<!Const> other) requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>> constexpr sentinel_t<Base> base() const; template<bool OtherConst> requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y); }; }
constexpr sentinel(sentinel<!Const> other) requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;
Effects: Initializes end_ with std​::​move(other.end_).
constexpr explicit sentinel(Parent& parent);
Effects: Initializes end_ with ranges​::​end(parent.base_).
constexpr sentinel_t<Base> base() const;
Effects: Equivalent to: return end_;
template<bool OtherConst> requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const <OtherConst, V>>> friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
Effects: Equivalent to: return x.current_ == y.end_;