25 Ranges library [ranges]

25.7 Range adaptors [range.adaptors]

25.7.34 Cache latest view [range.cache.latest]

25.7.34.1 Overview [range.cache.latest.overview]

cache_latest_view caches the last-accessed element of its underlying sequence so that the element does not have to be recomputed on repeated access.
[Note 1: 
This is useful if computation of the element to produce is expensive.
— end note]
The name views​::​cache_latest denotes a range adaptor object ([range.adaptor.object]).
Let E be an expression.
The expression views​::​cache_latest(E) is expression-equivalent to cache_latest_view(E).

25.7.34.2 Class template cache_latest_view [range.cache.latest.view]

namespace std::ranges { template<input_range V> requires view<V> class cache_latest_view : public view_interface<cache_latest_view<V>> { V base_ = V(); // exposition only using cache-t = conditional_t<is_reference_v<range_reference_t<V>>, // exposition only add_pointer_t<range_reference_t<V>>, range_reference_t<V>>; non-propagating-cache<cache-t> cache_; // exposition only class iterator; // exposition only class sentinel; // exposition only public: cache_latest_view() requires default_initializable<V> = default; constexpr explicit cache_latest_view(V base); constexpr V base() const & requires copy_constructible<V> { return base_; } constexpr V base() && { return std::move(base_); } constexpr auto begin(); constexpr auto end(); constexpr auto size() requires sized_range<V>; constexpr auto size() const requires sized_range<const V>; }; template<class R> cache_latest_view(R&&) -> cache_latest_view<views::all_t<R>>; }
constexpr explicit cache_latest_view(V base);
Effects: Initializes base_ with std​::​move(base).
constexpr auto begin();
Effects: Equivalent to: return iterator(*this);
constexpr auto end();
Effects: Equivalent to: return sentinel(*this);
constexpr auto size() requires sized_range<V>; constexpr auto size() const requires sized_range<const V>;
Effects: Equivalent to: return ranges​::​size(base_);

25.7.34.3 Class cache_latest_view​::​iterator [range.cache.latest.iterator]

namespace std::ranges { template<input_range V> requires view<V> class cache_latest_view<V>::iterator { cache_latest_view* parent_; // exposition only iterator_t<V> current_; // exposition only constexpr explicit iterator(cache_latest_view& parent); // exposition only public: using difference_type = range_difference_t<V>; using value_type = range_value_t<V>; using iterator_concept = input_iterator_tag; iterator(iterator&&) = default; iterator& operator=(iterator&&) = default; constexpr iterator_t<V> base() &&; constexpr const iterator_t<V>& base() const & noexcept; constexpr range_reference_t<V>& operator*() const; constexpr iterator& operator++(); constexpr void operator++(int); 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>>; }; }
constexpr explicit iterator(cache_latest_view& parent);
Effects: Initializes current_ with ranges​::​begin(parent.base_) and parent_ with addressof(parent).
constexpr iterator_t<V> base() &&;
Returns: std​::​move(current_).
constexpr const iterator_t<V>& base() const & noexcept;
Returns: current_.
constexpr iterator& operator++();
Effects: Equivalent to: parent_->cache_.reset(); ++current_; return *this;
constexpr void operator++(int);
Effects: Equivalent to: ++*this.
constexpr range_reference_t<V>& operator*() const;
Effects: Equivalent to: if constexpr (is_reference_v<range_reference_t<V>>) { if (!parent_->cache_) { parent_->cache_ = addressof(as-lvalue(*current_)); } return **parent_->cache_; } else { if (!parent_->cache_) { parent_->cache_.emplace-deref(current_); } return *parent_->cache_; }
[Note 1: 
Evaluations of operator* on the same iterator object can conflict ([intro.races]).
— end note]
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.34.4 Class cache_latest_view​::​sentinel [range.cache.latest.sentinel]

namespace std::ranges { template<input_range V> requires view<V> class cache_latest_view<V>::sentinel { sentinel_t<V> end_ = sentinel_t<V>(); // exposition only constexpr explicit sentinel(cache_latest_view& parent); // exposition only public: sentinel() = default; constexpr sentinel_t<V> base() const; friend constexpr bool operator==(const iterator& x, const sentinel& y); friend constexpr range_difference_t<V> operator-(const iterator& x, const sentinel& y) requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>; friend constexpr range_difference_t<V> operator-(const sentinel& x, const iterator& y) requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>; }; }
constexpr explicit sentinel(cache_latest_view& parent);
Effects: Initializes end_ with ranges​::​end(parent.base_).
constexpr sentinel_t<V> base() const;
Returns: end_.
friend constexpr bool operator==(const iterator& x, const sentinel& y);
Returns: x.current_ == y.end_.
friend constexpr range_difference_t<V> operator-(const iterator& x, const sentinel& y) requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
Returns: x.current_ - y.end_.
friend constexpr range_difference_t<V> operator-(const sentinel& x, const iterator& y) requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
Returns: x.end_ - y.current_.