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]

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 class iterator; // exposition only // [range.filter.sentinel], class filter_view​::​sentinel 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 begin(); constexpr auto end() { if constexpr (common_range<V>) return iterator{*this, ranges::end(base_)}; else return sentinel{*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 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.

25.7.8.3 Class 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> class filter_view<V, Pred>::iterator { private: iterator_t<V> current_ = iterator_t<V>(); // exposition only filter_view* parent_ = nullptr; // exposition only public: using iterator_concept = see below; using iterator_category = see below; // not always present using value_type = range_value_t<V>; using difference_type = range_difference_t<V>; iterator() requires default_initializable<iterator_t<V>> = default; constexpr iterator(filter_view& parent, iterator_t<V> current); constexpr const iterator_t<V>& base() const & noexcept; constexpr iterator_t<V> base() &&; constexpr range_reference_t<V> operator*() const; constexpr iterator_t<V> operator->() const requires has-arrow<iterator_t<V>> && copyable<iterator_t<V>>; constexpr iterator& operator++(); constexpr void operator++(int); constexpr iterator operator++(int) requires forward_range<V>; constexpr iterator& operator--() requires bidirectional_range<V>; constexpr iterator operator--(int) requires bidirectional_range<V>; friend constexpr bool operator==(const iterator& x, const iterator& y) requires equality_comparable<iterator_t<V>>; friend constexpr range_rvalue_reference_t<V> 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<V>>; }; }
Modification of the element a filter_view​::​iterator denotes is permitted, but results in undefined behavior if the resulting value does not satisfy the filter predicate.
iterator​::​iterator_concept is defined as follows:
The member typedef-name iterator_category is defined if and only if V models forward_range.
In that case, iterator​::​iterator_category is defined as follows:
  • Let C denote the type iterator_traits<iterator_t<V>>​::​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(filter_view& parent, iterator_t<V> current);
Effects: Initializes current_ with std​::​move(current) and parent_ with addressof(parent).
constexpr const iterator_t<V>& base() const & noexcept;
Effects: Equivalent to: return current_;
constexpr iterator_t<V> base() &&;
Effects: Equivalent to: return std​::​move(current_);
constexpr range_reference_t<V> operator*() const;
Effects: Equivalent to: return *current_;
constexpr iterator_t<V> operator->() const requires has-arrow<iterator_t<V>> && copyable<iterator_t<V>>;
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<V>;
Effects: Equivalent to: auto tmp = *this; ++*this; return tmp;
constexpr iterator& operator--() requires bidirectional_range<V>;
Effects: Equivalent to: do --current_; while (!invoke(*parent_->pred_, *current_)); return *this;
constexpr iterator operator--(int) requires bidirectional_range<V>;
Effects: Equivalent to: auto tmp = *this; --*this; return tmp;
friend constexpr bool operator==(const iterator& x, const iterator& y) requires equality_comparable<iterator_t<V>>;
Effects: Equivalent to: return x.current_ == y.current_;
friend constexpr range_rvalue_reference_t<V> 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<V>>;
Effects: Equivalent to ranges​::​iter_swap(x.current_, y.current_).

25.7.8.4 Class 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> class filter_view<V, Pred>::sentinel { private: sentinel_t<V> end_ = sentinel_t<V>(); // exposition only public: sentinel() = default; constexpr explicit sentinel(filter_view& parent); constexpr sentinel_t<V> base() const; friend constexpr bool operator==(const iterator& x, const sentinel& y); }; }
constexpr explicit sentinel(filter_view& parent);
Effects: Initializes end_ with ranges​::​end(parent.base_).
constexpr sentinel_t<V> base() const;
Effects: Equivalent to: return end_;
friend constexpr bool operator==(const iterator& x, const sentinel& y);
Effects: Equivalent to: return x.current_ == y.end_;