[range.filter]

# 25 Ranges library [[ranges]](./#ranges)

## 25.7 Range adaptors [[range.adaptors]](range.adaptors#range.filter)

### 25.7.8 Filter view [range.filter]

#### [25.7.8.1](#overview) Overview [[range.filter.overview]](range.filter.overview)

[1](#overview-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4751)

filter_view presents a view of the elements
of an underlying sequence that satisfy a predicate[.](#overview-1.sentence-1)

[2](#overview-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4755)

The name views​::​filter denotes a
range adaptor object ([[range.adaptor.object]](range.adaptor.object "25.7.2 Range adaptor objects"))[.](#overview-2.sentence-1)

Given subexpressions E and P,
the expression views​::​filter(E, P) is expression-equivalent tofilter_view(E, P)[.](#overview-2.sentence-2)

[3](#overview-3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4763)

[*Example [1](#overview-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](#view) Class template filter_view [[range.filter.view]](range.filter.view)

[ð](#lib:filter_view)

namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6 Other range refinements [range.refinements]") V, [indirect_unary_predicate](indirectcallable.indirectinvocable#concept:indirect_unary_predicate "24.3.6.3 Indirect callables [indirectcallable.indirectinvocable]")<iterator_t<V>> Pred>requires [view](range.view#concept:view "25.4.5 Views [range.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]](#iterator "25.7.8.3 Class filter_­view​::​iterator"), class filter_view​::​*iterator*class *iterator*; // *exposition only*// [[range.filter.sentinel]](#sentinel "25.7.8.4 Class filter_­view​::​sentinel"), class filter_view​::​*sentinel*class *sentinel*; // *exposition only*public: filter_view() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12 Concept default_­initializable [concept.default.init]")<V> && [default_initializable](concept.default.init#concept:default_initializable "18.4.12 Concept default_­initializable [concept.default.init]")<Pred> = default; constexpr explicit filter_view(V base, Pred pred); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14 Concept copy_­constructible [concept.copyconstructible]")<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](range.refinements#concept:common_range "25.4.6 Other range refinements [range.refinements]")<V>)return *iterator*{*this, ranges::end(*base_*)}; elsereturn *sentinel*{*this}; }}; template<class R, class Pred> filter_view(R&&, Pred) -> filter_view<views::all_t<R>, Pred>;}

[ð](#lib:filter_view,constructor)

`constexpr explicit filter_view(V base, Pred pred);
`

[1](#view-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4822)

*Effects*: Initializes *base_* with std​::​move(base) and initializes*pred_* with std​::​move(pred)[.](#view-1.sentence-1)

[ð](#lib:pred,filter_view)

`constexpr const Pred& pred() const;
`

[2](#view-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4834)

*Effects*: Equivalent to: return **pred_*;

[ð](#lib:begin,filter_view)

`constexpr iterator begin();
`

[3](#view-3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4845)

*Preconditions*: *pred_*.has_value() is true[.](#view-3.sentence-1)

[4](#view-4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4849)

*Returns*: {*this, ranges​::​find_if(*base_*, ref(**pred_*))}[.](#view-4.sentence-1)

[5](#view-5)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4853)

*Remarks*: In order to provide the amortized constant time complexity required by
the [range](range.range#concept:range "25.4.2 Ranges [range.range]") concept
when filter_view models [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]"),
this function caches the result within thefilter_view for use on subsequent calls[.](#view-5.sentence-1)

#### [25.7.8.3](#iterator) Class filter_view​::​*iterator* [[range.filter.iterator]](range.filter.iterator)

[ð](#lib:filter_view::iterator)

namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6 Other range refinements [range.refinements]") V, [indirect_unary_predicate](indirectcallable.indirectinvocable#concept:indirect_unary_predicate "24.3.6.3 Indirect callables [indirectcallable.indirectinvocable]")<iterator_t<V>> Pred>requires [view](range.view#concept:view "25.4.5 Views [range.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 presentusing value_type = range_value_t<V>; using difference_type = range_difference_t<V>; *iterator*() requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12 Concept default_­initializable [concept.default.init]")<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->() constrequires [*has-arrow*](range.utility.helpers#concept:has-arrow "25.5.2 Helper concepts [range.utility.helpers]")<iterator_t<V>> && [copyable](concepts.object#concept:copyable "18.6 Object concepts [concepts.object]")<iterator_t<V>>; constexpr *iterator*& operator++(); constexpr void operator++(int); constexpr *iterator* operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<V>; constexpr *iterator*& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<V>; constexpr *iterator* operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<V>; friend constexpr bool operator==(const *iterator*& x, const *iterator*& y)requires [equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept equality_­comparable [concept.equalitycomparable]")<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](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4 Concept indirectly_­swappable [alg.req.ind.swap]")<iterator_t<V>>; };}

[1](#iterator-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4910)

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-1.sentence-1)

[2](#iterator-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4915)

*iterator*​::​iterator_concept is defined as follows:

- [(2.1)](#iterator-2.1)

  If V models [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]"), theniterator_concept denotes bidirectional_iterator_tag[.](#iterator-2.1.sentence-1)

- [(2.2)](#iterator-2.2)

  Otherwise, if V models [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]"), theniterator_concept denotes forward_iterator_tag[.](#iterator-2.2.sentence-1)

- [(2.3)](#iterator-2.3)

  Otherwise, iterator_concept denotes input_iterator_tag[.](#iterator-2.3.sentence-1)

[3](#iterator-3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4927)

The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") iterator_category is defined
if and only if V models [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")[.](#iterator-3.sentence-1)

In that case,*iterator*​::​iterator_category is defined as follows:

- [(3.1)](#iterator-3.1)

  Let C denote the typeiterator_traits<iterator_t<V>>​::​iterator_category[.](#iterator-3.1.sentence-1)

- [(3.2)](#iterator-3.2)

  If C models[derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_­from [concept.derived]")<bidirectional_iterator_tag>,
then iterator_category denotes bidirectional_iterator_tag[.](#iterator-3.2.sentence-1)

- [(3.3)](#iterator-3.3)

  Otherwise, if C models[derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_­from [concept.derived]")<forward_iterator_tag>,
then iterator_category denotes forward_iterator_tag[.](#iterator-3.3.sentence-1)

- [(3.4)](#iterator-3.4)

  Otherwise, iterator_category denotes C[.](#iterator-3.4.sentence-1)

[ð](#lib:filter_view::iterator,constructor)

`constexpr iterator(filter_view& parent, iterator_t<V> current);
`

[4](#iterator-4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4953)

*Effects*: Initializes *current_* with std​::​move(current) and*parent_* with addressof(parent)[.](#iterator-4.sentence-1)

[ð](#lib:base,filter_view::iterator)

`constexpr const iterator_t<V>& base() const & noexcept;
`

[5](#iterator-5)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4965)

*Effects*: Equivalent to: return *current_*;

[ð](#lib:base,filter_view::iterator_)

`constexpr iterator_t<V> base() &&;
`

[6](#iterator-6)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4976)

*Effects*: Equivalent to: return std​::​move(*current_*);

[ð](#lib:operator*,filter_view::iterator)

`constexpr range_reference_t<V> operator*() const;
`

[7](#iterator-7)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4987)

*Effects*: Equivalent to: return **current_*;

[ð](#lib:operator-%3e,filter_view::iterator)

`constexpr iterator_t<V> operator->() const
  requires [has-arrow](range.utility.helpers#concept:has-arrow "25.5.2 Helper concepts [range.utility.helpers]")<iterator_t<V>> && [copyable](concepts.object#concept:copyable "18.6 Object concepts [concepts.object]")<iterator_t<V>>;
`

[8](#iterator-8)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L4999)

*Effects*: Equivalent to: return *current_*;

[ð](#lib:operator++,filter_view::iterator)

`constexpr iterator& operator++();
`

[9](#iterator-9)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5010)

*Effects*: Equivalent to:*current_* = ranges::find_if(std::move(++*current_*), ranges::end(*parent_*->*base_*),
 ref(**parent_*->*pred_*));return *this;

[ð](#lib:operator++,filter_view::iterator_)

`constexpr void operator++(int);
`

[10](#iterator-10)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5026)

*Effects*: Equivalent to ++*this[.](#iterator-10.sentence-1)

[ð](#lib:operator++,filter_view::iterator__)

`constexpr iterator operator++(int) requires [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<V>;
`

[11](#iterator-11)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5037)

*Effects*: Equivalent to:auto tmp = *this;++*this;return tmp;

[ð](#lib:operator--,filter_view::iterator)

`constexpr iterator& operator--() requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<V>;
`

[12](#iterator-12)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5053)

*Effects*: Equivalent to:do--*current_*;while (!invoke(**parent_*->*pred_*, **current_*));return *this;

[ð](#lib:operator--,filter_view::iterator_)

`constexpr iterator operator--(int) requires [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<V>;
`

[13](#iterator-13)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5070)

*Effects*: Equivalent to:auto tmp = *this;--*this;return tmp;

[ð](#lib:operator==,filter_view::iterator)

`friend constexpr bool operator==(const iterator& x, const iterator& y)
  requires [equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept equality_­comparable [concept.equalitycomparable]")<iterator_t<V>>;
`

[14](#iterator-14)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5087)

*Effects*: Equivalent to: return x.*current_* == y.*current_*;

[ð](#lib:iter_move,filter_view::iterator)

`friend constexpr range_rvalue_reference_t<V> iter_move(const iterator& i)
  noexcept(noexcept(ranges::iter_move(i.current_)));
`

[15](#iterator-15)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5099)

*Effects*: Equivalent to: return ranges​::​iter_move(i.*current_*);

[ð](#lib:iter_swap,filter_view::iterator)

`friend constexpr void iter_swap(const iterator& x, const iterator& y)
  noexcept(noexcept(ranges::iter_swap(x.current_, y.current_)))
  requires [indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4 Concept indirectly_­swappable [alg.req.ind.swap]")<iterator_t<V>>;
`

[16](#iterator-16)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5112)

*Effects*: Equivalent to ranges​::​iter_swap(x.*current_*, y.*current_*)[.](#iterator-16.sentence-1)

#### [25.7.8.4](#sentinel) Class filter_view​::​*sentinel* [[range.filter.sentinel]](range.filter.sentinel)

[ð](#lib:filter_view::sentinel)

namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6 Other range refinements [range.refinements]") V, [indirect_unary_predicate](indirectcallable.indirectinvocable#concept:indirect_unary_predicate "24.3.6.3 Indirect callables [indirectcallable.indirectinvocable]")<iterator_t<V>> Pred>requires [view](range.view#concept:view "25.4.5 Views [range.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); };}

[ð](#lib:filter_view::sentinel,constructor)

`constexpr explicit sentinel(filter_view& parent);
`

[1](#sentinel-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5146)

*Effects*: Initializes *end_* with ranges​::​end(parent.*base_*)[.](#sentinel-1.sentence-1)

[ð](#lib:base,filter_view::sentinel)

`constexpr sentinel_t<V> base() const;
`

[2](#sentinel-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5157)

*Effects*: Equivalent to: return *end_*;

[ð](#lib:operator==,filter_view::sentinel)

`friend constexpr bool operator==(const iterator& x, const sentinel& y);
`

[3](#sentinel-3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L5168)

*Effects*: Equivalent to: return x.*current_* == y.*end_*;
