25 Ranges library [ranges]

25.7 Range adaptors [range.adaptors]

25.7.25 Zip view [range.zip]

25.7.25.2 Class template zip_view [range.zip.view]

namespace std::ranges { template<class... Rs> concept zip-is-common = // exposition only (sizeof...(Rs) == 1 && (common_range<Rs> && ...)) || (!(bidirectional_range<Rs> && ...) && (common_range<Rs> && ...)) || ((random_access_range<Rs> && ...) && (sized_range<Rs> && ...)); template<input_range... Views> requires (view<Views> && ...) && (sizeof...(Views) > 0) class zip_view : public view_interface<zip_view<Views...>> { tuple<Views...> views_; // exposition only // [range.zip.iterator], class template zip_view​::​iterator template<bool> class iterator; // exposition only // [range.zip.sentinel], class template zip_view​::​sentinel template<bool> class sentinel; // exposition only public: zip_view() = default; constexpr explicit zip_view(Views... views); constexpr auto begin() requires (!(simple-view<Views> && ...)) { return iterator<false>(tuple-transform(ranges::begin, views_)); } constexpr auto begin() const requires (range<const Views> && ...) { return iterator<true>(tuple-transform(ranges::begin, views_)); } constexpr auto end() requires (!(simple-view<Views> && ...)) { if constexpr (!zip-is-common<Views...>) { return sentinel<false>(tuple-transform(ranges::end, views_)); } else if constexpr ((random_access_range<Views> && ...)) { return begin() + iter_difference_t<iterator<false>>(size()); } else { return iterator<false>(tuple-transform(ranges::end, views_)); } } constexpr auto end() const requires (range<const Views> && ...) { if constexpr (!zip-is-common<const Views...>) { return sentinel<true>(tuple-transform(ranges::end, views_)); } else if constexpr ((random_access_range<const Views> && ...)) { return begin() + iter_difference_t<iterator<true>>(size()); } else { return iterator<true>(tuple-transform(ranges::end, views_)); } } constexpr auto size() requires (sized_range<Views> && ...); constexpr auto size() const requires (sized_range<const Views> && ...); }; template<class... Rs> zip_view(Rs&&...) -> zip_view<views::all_t<Rs>...>; }
Two zip_view objects have the same underlying sequence if and only if the corresponding elements of views_ are equal ([concepts.equality]) and have the same underlying sequence.
[Note 1: 
In particular, comparison of iterators obtained from zip_view objects that do not have the same underlying sequence is not required to produce meaningful results ([iterator.concept.forward]).
— end note]
constexpr explicit zip_view(Views... views);
Effects: Initializes views_ with std​::​move(views)....
constexpr auto size() requires (sized_range<Views> && ...); constexpr auto size() const requires (sized_range<const Views> && ...);
Effects: Equivalent to: return apply([](auto... sizes) { using CT = make-unsigned-like-t<common_type_t<decltype(sizes)...>>; return ranges::min({CT(sizes)...}); }, tuple-transform(ranges::size, views_));