auto historical_figures = map{ {"Lovelace"sv, 1815}, {"Turing"sv, 1912}, {"Babbage"sv, 1791}, {"Hamilton"sv, 1936} }; auto names = historical_figures | views::elements<0>; for (auto&& name : names) { cout << name << ' '; // prints Babbage Hamilton Lovelace Turing } auto birth_years = historical_figures | views::elements<1>; for (auto&& born : birth_years) { cout << born << ' '; // prints 1791 1936 1815 1912 }— end example
namespace std::ranges { template<class T, size_t N> concept has-tuple-element = // exposition only requires(T t) { typename tuple_size<T>::type; requires N < tuple_size_v<T>; typename tuple_element_t<N, T>; { get<N>(t) } -> convertible_to<const tuple_element_t<N, T>&>; }; template<input_range V, size_t N> requires view<V> && has-tuple-element<range_value_t<V>, N> && has-tuple-element<remove_reference_t<range_reference_t<V>>, N> class elements_view : public view_interface<elements_view<V, N>> { public: elements_view() = default; constexpr explicit elements_view(V base); constexpr V base() const& requires copy_constructible<V> { return base_; } constexpr V base() && { return std::move(base_); } constexpr auto begin() requires (!simple-view<V>) { return iterator<false>(ranges::begin(base_)); } constexpr auto begin() const requires simple-view<V> { return iterator<true>(ranges::begin(base_)); } constexpr auto end() { return sentinel<false>{ranges::end(base_)}; } constexpr auto end() requires common_range<V> { return iterator<false>{ranges::end(base_)}; } constexpr auto end() const requires range<const V> { return sentinel<true>{ranges::end(base_)}; } constexpr auto end() const requires common_range<const V> { return iterator<true>{ranges::end(base_)}; } constexpr auto size() requires sized_range<V> { return ranges::size(base_); } constexpr auto size() const requires sized_range<const V> { return ranges::size(base_); } private: // [range.elements.iterator], class template elements_view::iterator template<bool> struct iterator; // exposition only // [range.elements.sentinel], class template elements_view::sentinel template<bool> struct sentinel; // exposition only V base_ = V(); // exposition only }; }
constexpr explicit elements_view(V base);
namespace std::ranges { template<input_range V, size_t N> requires view<V> && has-tuple-element<range_value_t<V>, N> && has-tuple-element<remove_reference_t<range_reference_t<V>>, N> template<bool Const> class elements_view<V, N>::iterator { // exposition only using Base = conditional_t<Const, const V, V>; // exposition only iterator_t<Base> current_ = iterator_t<Base>(); public: using iterator_category = typename iterator_traits<iterator_t<Base>>::iterator_category; using value_type = remove_cvref_t<tuple_element_t<N, range_value_t<Base>>>; using difference_type = range_difference_t<Base>; iterator() = default; constexpr explicit iterator(iterator_t<Base> current); constexpr iterator(iterator<!Const> i) requires Const && convertible_to<iterator_t<V>, iterator_t<Base>>; constexpr iterator_t<Base> base() const& requires copyable<iterator_t<Base>>; constexpr iterator_t<Base> base() &&; constexpr decltype(auto) operator*() const { return get<N>(*current_); } constexpr iterator& operator++(); constexpr void operator++(int) requires (!forward_range<Base>); constexpr iterator operator++(int) requires forward_range<Base>; constexpr iterator& operator--() requires bidirectional_range<Base>; constexpr iterator operator--(int) requires bidirectional_range<Base>; constexpr iterator& operator+=(difference_type x) requires random_access_range<Base>; constexpr iterator& operator-=(difference_type x) requires random_access_range<Base>; constexpr decltype(auto) operator[](difference_type n) const requires random_access_range<Base> { return get<N>(*(current_ + n)); } friend constexpr bool operator==(const iterator& x, const iterator& y) requires equality_comparable<iterator_t<Base>>; friend constexpr bool operator<(const iterator& x, const iterator& y) requires random_access_range<Base>; friend constexpr bool operator>(const iterator& x, const iterator& y) requires random_access_range<Base>; friend constexpr bool operator<=(const iterator& x, const iterator& y) requires random_access_range<Base>; friend constexpr bool operator>=(const iterator& x, const iterator& y) requires random_access_range<Base>; friend constexpr auto operator<=>(const iterator& x, const iterator& y) requires random_access_range<Base> && three_way_comparable<iterator_t<Base>>; friend constexpr iterator operator+(const iterator& x, difference_type y) requires random_access_range<Base>; friend constexpr iterator operator+(difference_type x, const iterator& y) requires random_access_range<Base>; friend constexpr iterator operator-(const iterator& x, difference_type y) requires random_access_range<Base>; friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires random_access_range<Base>; }; }
constexpr explicit iterator(iterator_t<Base> current);
constexpr iterator(iterator<!Const> i)
requires Const && convertible_to<iterator_t<V>, iterator_t<Base>>;
constexpr iterator_t<Base> base() const&
requires copyable<iterator_t<Base>>;
constexpr iterator_t<Base> base() &&;
constexpr iterator& operator++();
friend constexpr bool operator==(const iterator& x, const iterator& y)
requires equality_comparable<Base>;
friend constexpr bool operator<(const iterator& x, const iterator& y)
requires random_access_range<Base>;
friend constexpr bool operator>(const iterator& x, const iterator& y)
requires random_access_range<Base>;
friend constexpr bool operator<=(const iterator& x, const iterator& y)
requires random_access_range<Base>;
friend constexpr bool operator>=(const iterator& x, const iterator& y)
requires random_access_range<Base>;
friend constexpr auto operator<=>(const iterator& x, const iterator& y)
requires random_access_range<Base> && three_way_comparable<iterator_t<Base>>;
friend constexpr iterator operator+(const iterator& x, difference_type y)
requires random_access_range<Base>;
friend constexpr iterator operator+(difference_type x, const iterator& y)
requires random_access_range<Base>;
constexpr iterator operator-(const iterator& x, difference_type y)
requires random_access_range<Base>;
namespace std::ranges { template<input_range V, size_t N> requires view<V> && has-tuple-element<range_value_t<V>, N> && has-tuple-element<remove_reference_t<range_reference_t<V>>, N> template<bool Const> class elements_view<V, N>::sentinel { // exposition only private: using Base = conditional_t<Const, const V, 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> other) requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>; constexpr sentinel_t<Base> base() const; friend constexpr bool operator==(const iterator<Const>& x, const sentinel& y); friend constexpr range_difference_t<Base> operator-(const iterator<Const>& x, const sentinel& y) requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>; friend constexpr range_difference_t<Base> operator-(const sentinel& x, const iterator<Const>& y) requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>; }; }
constexpr explicit sentinel(sentinel_t<Base> end);
constexpr sentinel(sentinel<!Const> other)
requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;
constexpr sentinel_t<Base> base() const;
friend constexpr bool operator==(const iterator<Const>& x, const sentinel& y);
friend constexpr range_difference_t<Base>
operator-(const iterator<Const>& x, const sentinel& y)
requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;
friend constexpr range_difference_t<Base>
operator-(const sentinel& x, const iterator<Const>& y)
requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;