VCCC  2024.05
VisualCamp Common C++ library
zip_view.hpp
Go to the documentation of this file.
1 //
2 // Created by YongGyu Lee on 4/8/24.
3 //
4 
5 #ifndef VCCC_RANGES_VIEWS_ZIP_VIEW_HPP_
6 #define VCCC_RANGES_VIEWS_ZIP_VIEW_HPP_
7 
8 #include <algorithm>
9 #include <tuple>
10 #include <type_traits>
11 #include <utility>
12 
21 #include "vccc/__ranges/begin.hpp"
33 #include "vccc/__ranges/size.hpp"
34 #include "vccc/__ranges/view.hpp"
37 #include "vccc/__tuple/apply.hpp"
50 
51 namespace vccc {
52 namespace ranges {
53 namespace detail {
54 
55 template<bool AllForward /* true */>
56 struct zip_view_iterator_category {
57  using iterator_category = input_iterator_tag;
58 };
59 
60 template<>
61 struct zip_view_iterator_category<false> {
62 #if __cplusplus < 202002L
63  using iterator_category = iterator_ignore;
64 #endif
65 };
66 
67 template<typename R>
68 struct min_tuple_distance_fn {
69  template<typename T1, typename T2>
70  R operator()(const T1& t1, const T2& t2) const {
71  static_assert(std::tuple_size<remove_cvref_t<T1>>::value ==
72  std::tuple_size<remove_cvref_t<T2>>::value, "Size doesn't match");
73 
74  return call(t1, t2, std::make_index_sequence<std::tuple_size<remove_cvref_t<T2>>::value>{});
75  }
76 
77  private:
78  template<typename T1, typename T2, std::size_t... I>
79  R call(const T1& t1, const T2& t2, std::index_sequence<I...>) const {
80  return (ranges::min)({R(std::get<I>(t1) - std::get<I>(t2))...});
81  }
82 };
83 
84 template<typename... Rs>
85 struct zip_is_common
86  : disjunction<
87  conjunction<
88  bool_constant<sizeof...(Rs) == 1>,
89  common_range<Rs>...
90  >,
91  conjunction<
92  negation<
93  conjunction<bidirectional_range<Rs>...>
94  >,
95  common_range<Rs>...
96  >,
97  conjunction<
98  random_access_range<Rs>...,
99  sized_range<Rs>...
100  >
101  > {};
102 
103 } // namespace detail
104 
107 
108 template<typename... Views>
109 class zip_view : public view_interface<zip_view<Views...>> {
110  static constexpr std::size_t kViewCount = sizeof...(Views);
111  using tuple_index_sequence = std::index_sequence_for<Views...>;
112 
113  public:
114  static_assert(sizeof...(Views) > 0, "Constraints not satisfied");
115  static_assert(conjunction<input_range<Views>...>::value, "Constraints not satisfied");
116  static_assert(conjunction<view<Views>...>::value, "Constraints not satisfied");
117 
118  template<bool Const> class iterator;
119  template<bool Const> class sentinel;
120 
121 
122  template<bool Const>
123  class iterator : public detail::zip_view_iterator_category<conjunction<forward_range<maybe_const<Const, Views>>...>::value> {
127 
128  friend class iterator<true>;
129  friend class sentinel<true>;
130  friend class sentinel<false>;
131  friend class zip_view;
132 
133  struct tuple_deref_fn {
134  template<typename I>
135  constexpr decltype(auto) operator()(I& i) const {
136  return *i;
137  }
138  };
139 
140  public:
142  std::conditional_t<
144  std::conditional_t<
146  std::conditional_t<
149  >>>;
150  using value_type = std::tuple<maybe_const<Const, Views>...>;
152 
153 #if __cplusplus < 202002L
154  using pointer = void;
156  std::declval<std::tuple<iterator_t<maybe_const<Const, Views>>...>&>(),
157  std::declval<tuple_deref_fn>()
158  ));
159 #endif
160 
161  iterator() = default;
162 
163  template<bool AntiConst, std::enable_if_t<conjunction<
164  bool_constant<((Const != AntiConst) && Const)>,
166  >::value, int> = 0>
168  : current_(std::move(i.current_)) {}
169 
170  constexpr decltype(auto) operator*() const {
171  return vccc::tuple_transform(current_, [](auto& i) -> decltype(auto) { return *i; });
172  }
173 
174 
175  template<typename Dummy = void, std::enable_if_t<conjunction<std::is_void<Dummy>,
176  all_random_access
177  >::value, int> = 0>
178  constexpr decltype(auto) operator[](difference_type n) const {
179  return vccc::tuple_transform(
180  current_,
181  [&](auto& i) -> decltype(auto) {
182  static_assert(std::is_lvalue_reference<decltype(i)>::value, "Invalid type");
183  using I = remove_cvref_t<decltype(i)>;
184  return i[iter_difference_t<I>(n)];
185  }
186  );
187  }
188 
189  constexpr iterator& operator++() {
190  vccc::tuple_for_each(current_, [](auto& i) { ++i; });
191  return *this;
192  }
193 
194  template<typename AF = all_forward, std::enable_if_t<!AF::value, int> = 0>
195  constexpr void operator++(int) {
196  ++*this;
197  }
198 
199  template<typename AF = all_forward, std::enable_if_t<AF::value, int> = 0>
200  constexpr iterator operator++(int) {
201  auto tmp = *this;
202  ++*this;
203  return tmp;
204  }
205 
206  template<typename AB = all_bidirectional, std::enable_if_t<AB::value, int> = 0>
207  constexpr iterator& operator--() {
208  vccc::tuple_for_each(current_, [](auto& i) { --i; });
209  }
210 
211  template<typename AB = all_bidirectional, std::enable_if_t<AB::value, int> = 0>
212  constexpr iterator operator--(int) {
213  auto tmp = *this;
214  --*this;
215  return tmp;
216  }
217 
218  template<typename AR = all_random_access, std::enable_if_t<AR::value, int> = 0>
220  vccc::tuple_for_each(current_, [&](auto& i) {
221  static_assert(std::is_lvalue_reference<decltype(i)>::value, "Invalid type");
222  using I = remove_cvref_t<decltype(i)>;
223  i += iter_difference_t<I>(n);
224  });
225  return *this;
226  }
227 
228  template<typename AR = all_random_access, std::enable_if_t<AR::value, int> = 0>
230  vccc::tuple_for_each(current_, [&](auto& i) {
231  static_assert(std::is_lvalue_reference<decltype(i)>::value, "Invalid type");
232  using I = remove_cvref_t<decltype(i)>;
233  i -= iter_difference_t<I>(n);
234  });
235  return *this;
236  }
237 
238  template<typename Dummy = void, std::enable_if_t<conjunction<std::is_void<Dummy>,
239  equality_comparable<iterator_t<maybe_const<Const, Views>>>...
240  >::value, int> = 0>
241  friend constexpr bool operator==(const iterator& x, const iterator& y) {
242  return x.equal(y);
243  }
244 
245  template<typename Dummy = void, std::enable_if_t<conjunction<std::is_void<Dummy>,
246  equality_comparable<iterator_t<maybe_const<Const, Views>>>...
247  >::value, int> = 0>
248  friend constexpr bool operator!=(const iterator& x, const iterator& y) {
249  return !(x == y);
250  }
251 
252  template<typename AR = all_random_access, std::enable_if_t<AR::value, int> = 0>
253  friend constexpr bool operator<(const iterator& x, const iterator& y) {
254  return x.current_ < y.current_;
255  }
256 
257  template<typename AR = all_random_access, std::enable_if_t<AR::value, int> = 0>
258  friend constexpr bool operator<=(const iterator& x, const iterator& y) {
259  using namespace rel_ops;
260  return x.current_ <= y.current_;
261  }
262 
263  template<typename AR = all_random_access, std::enable_if_t<AR::value, int> = 0>
264  friend constexpr bool operator>(const iterator& x, const iterator& y) {
265  using namespace rel_ops;
266  return x.current_ > y.current_;
267  }
268 
269  template<typename AR = all_random_access, std::enable_if_t<AR::value, int> = 0>
270  friend constexpr bool operator>=(const iterator& x, const iterator& y) {
271  using namespace rel_ops;
272  return x.current_ >= y.current_;
273  }
274 
275  template<typename AR = all_random_access, std::enable_if_t<AR::value, int> = 0>
276  friend constexpr iterator operator+(const iterator& i, difference_type n) {
277  auto r = i;
278  r += n;
279  return r;
280  }
281 
282  template<typename AR = all_random_access, std::enable_if_t<AR::value, int> = 0>
283  friend constexpr iterator operator+(difference_type n, const iterator& i) {
284  auto r = i;
285  r += n;
286  return r;
287  }
288 
289  template<typename AR = all_random_access, std::enable_if_t<AR::value, int> = 0>
290  friend constexpr iterator operator-(const iterator& i, difference_type n) {
291  auto r = i;
292  r -= n;
293  return r;
294  }
295 
296  template<typename Dummy = void, std::enable_if_t<conjunction<std::is_void<Dummy>,
297  sized_sentinel_for<iterator_t<maybe_const<Const, Views>>,
298  iterator_t<maybe_const<Const, Views>>>
299  ...
300  >::value, int> = 0>
301  friend constexpr difference_type operator-(const iterator& i, const iterator& j) {
302  return detail::min_tuple_distance_fn<difference_type>{}(i.current_, j.current_);
303  }
304 
305  friend constexpr auto iter_move(const iterator& i)
306  noexcept(conjunction<
307  bool_constant<noexcept(
309  std::declval<const iterator_t<maybe_const<Const, Views>>&>()
310  )
311  )>...,
312  std::is_nothrow_move_constructible<
314  >...
315  >::value)
316  {
317  return vccc::tuple_transform(i.current_, ranges::iter_move);
318  }
319 
320  template<typename IS = conjunction<
322  std::enable_if_t<IS::value, int> = 0>
323  friend constexpr void iter_swap(const iterator& x, const iterator& y)
324  noexcept(conjunction<
326  std::declval<const iterator_t<maybe_const<Const, Views>>&>(),
327  std::declval<const iterator_t<maybe_const<Const, Views>>&>()
328  ))>...
329  >::value)
330  {
331  x.iter_swap_impl(y, tuple_index_sequence{});
332  }
333 
334  private:
335  template<typename Tuple>
336  constexpr explicit iterator(in_place_t, Tuple&& tup)
337  : current_(std::forward<Tuple>(tup)) {}
338 
339  constexpr bool equal(const iterator& other) const {
340  return equal_1(other, all_bidirectional{});
341  }
342 
343  constexpr bool equal_1(const iterator& other, std::true_type /* all_bidirectional */) const {
344  return current_ == other.current_;
345  }
346 
347  constexpr bool equal_1(const iterator& other, std::false_type /* all_bidirectional */) const {
348  return equal_2(other, in_place_index_t<0>{});
349  }
350 
351  template<typename OtherTuple, std::size_t I, std::enable_if_t<I != kViewCount, int> = 0>
352  constexpr bool equal_2(const OtherTuple& t, in_place_index_t<I>) const {
353  return bool(std::get<I>(current_) == std::get<I>(t))
354  ? true
355  : equal_2(t, in_place_index_t<I + 1>{});
356  }
357 
358  template<typename OtherTuple>
359  constexpr bool equal_2(const OtherTuple&, in_place_index_t<kViewCount>) const {
360  return false;
361  }
362 
363  template<std::size_t... I>
364  constexpr void iter_swap_impl(const iterator& other, std::index_sequence<I...>) const {
365  int dummy[] = {
366  (ranges::iter_swap(std::get<I>(current_), std::get<I>(other.current_)), 0)...
367  };
368  (void)dummy;
369  }
370 
371  std::tuple<iterator_t<maybe_const<Const, Views>>...> current_{};
372  };
373 
374  template<bool Const>
375  class sentinel {
376  friend class zip_view;
377 
378  public:
379  sentinel() = default;
380 
381  template<bool AntiConst, std::enable_if_t<conjunction<
382  bool_constant<((Const != AntiConst) && Const)>,
384  >::value, int> = 0>
386  : end_(std::move(i.end_)) {}
387 
388  template<bool OtherConst, std::enable_if_t<conjunction<
389  sentinel_for<
392  >...
393  >::value, int> = 0>
394  friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y) {
395  return y.is_equal(x);
396  }
397 
398  template<bool OtherConst, std::enable_if_t<conjunction<
399  sentinel_for<
402  >...
403  >::value, int> = 0>
404  friend constexpr bool operator==(const sentinel& y, const iterator<OtherConst>& x) {
405  return x == y;
406  }
407 
408  template<bool OtherConst, std::enable_if_t<conjunction<
409  sentinel_for<
412  >...
413  >::value, int> = 0>
414  friend constexpr bool operator!=(const iterator<OtherConst>& x, const sentinel& y) {
415  return !(x == y);
416  }
417 
418  template<bool OtherConst, std::enable_if_t<conjunction<
419  sentinel_for<
422  >...
423  >::value, int> = 0>
424  friend constexpr bool operator!=(const sentinel& y, const iterator<OtherConst>& x) {
425  return !(x == y);
426  }
427 
428  template<bool OtherConst, std::enable_if_t<conjunction<
432  >...
433  >::value, int> = 0>
437  return detail::min_tuple_distance_fn<R>{}(x.current_, y.end_);
438  }
439 
440  template<bool OtherConst, std::enable_if_t<conjunction<
444  >...
445  >::value, int> = 0>
448  return -(x - y);
449  }
450 
451  private:
452  template<typename Tuple>
453  constexpr explicit sentinel(in_place_t, Tuple&& tup)
454  : end_(std::forward<Tuple>(tup)) {}
455 
456  template<bool OtherConst>
457  constexpr bool is_equal(const iterator<OtherConst>& i) const {
458  return i.equal_2(end_, in_place_index_t<0>{});
459  }
460 
461  std::tuple<sentinel_t<maybe_const<Const, Views>>...> end_{};
462  };
463 
464  zip_view() = default;
465 
466  constexpr zip_view(Views... views)
467  : views_(std::move(views)...) {}
468 
469  template<typename Dummy = void, std::enable_if_t<conjunction<std::is_void<Dummy>,
470  negation<
471  simple_view<Views>
472  >...
473  >::value, int> = 0>
474  constexpr auto begin() {
476  }
477 
478  template<typename Dummy = void, std::enable_if_t<conjunction<std::is_void<Dummy>,
479  range<const Views>...
480  >::value, int> = 0>
481  constexpr auto begin() const {
483  }
484 
485  template<typename Dummy = void, std::enable_if_t<conjunction<std::is_void<Dummy>,
486  negation<
487  simple_view<Views>
488  >...
489  >::value, int> = 0>
490  constexpr auto end() {
491  return end_impl<false>(*this, detail::zip_is_common<Views...>{}, conjunction<random_access_range<Views>...>{});
492  }
493 
494  template<typename Dummy = void, std::enable_if_t<conjunction<std::is_void<Dummy>,
495  range<const Views>...
496  >::value, int> = 0>
497  constexpr auto end() const {
498  return end_impl<true>(*this, detail::zip_is_common<const Views...>{}, conjunction<random_access_range<const Views>...>{});
499  }
500 
501  template<typename Dummy = void, std::enable_if_t<conjunction<std::is_void<Dummy>,
502  sized_range<Views>...
503  >::value, int> = 0>
504  constexpr auto size() {
505  return vccc::apply(
506  [](auto... sizes) {
507  using CT = std::make_unsigned_t<common_type_t<decltype(sizes)...>>;
508  return (ranges::min)({CT(sizes)...});
509  },
511  );
512  }
513 
514  template<typename Dummy = void, std::enable_if_t<conjunction<std::is_void<Dummy>,
515  sized_range<const Views>...
516  >::value, int> = 0>
517  constexpr auto size() const {
518  return vccc::apply(
519  [](auto... sizes) {
520  using CT = std::make_unsigned_t<common_type_t<decltype(sizes)...>>;
521  return (ranges::min)({CT(sizes)...});
522  },
524  );
525  }
526 
527  private:
528  template<bool Const, typename Self, typename Any>
529  static constexpr auto end_impl(Self&& self, std::false_type /* zip_is_common */, Any) {
531  }
532 
533  template<bool Const, typename Self>
534  static constexpr auto end_impl(Self&& self, std::true_type /* zip_is_common */, std::true_type /* random_access_range */) {
535  return self.begin() + iter_difference_t<iterator<Const>>(self.size());
536  }
537 
538  template<bool Const, typename Self>
539  static constexpr auto end_impl(Self&& self, std::true_type /* zip_is_common */, std::false_type /* random_access_range */) {
540  return iterator<Const>(in_place, vccc::tuple_transform(self.views_, ranges::end));
541  }
542 
543  std::tuple<Views...> views_{};
544 };
545 
546 #if __cplusplus >= 201703L
547 
548 template<typename... Rs>
549 zip_view(Rs&&...) -> zip_view<views::all_t<Rs>...>;
550 
551 #endif
552 
554 
555 } // namespace ranges
556 } // namespace vccc
557 
558 #endif // VCCC_RANGES_VIEWS_ZIP_VIEW_HPP_
helper class template for defining a view, using the curiously recurring template pattern
Definition: view_interface.hpp:78
Definition: zip_view.hpp:123
constexpr iterator & operator--()
Definition: zip_view.hpp:207
common_type_t< range_difference_t< maybe_const< Const, Views > >... > difference_type
Definition: zip_view.hpp:151
constexpr friend iterator operator+(const iterator &i, difference_type n)
Definition: zip_view.hpp:276
friend class iterator< true >
Definition: zip_view.hpp:128
constexpr friend iterator operator-(const iterator &i, difference_type n)
Definition: zip_view.hpp:290
void pointer
Definition: zip_view.hpp:154
constexpr void operator++(int)
Definition: zip_view.hpp:195
constexpr friend void iter_swap(const iterator &x, const iterator &y) noexcept(conjunction< bool_constant< noexcept(ranges::iter_swap(std::declval< const iterator_t< maybe_const< Const, Views >> & >(), std::declval< const iterator_t< maybe_const< Const, Views >> & >()))>... >::value)
Definition: zip_view.hpp:323
std::tuple< maybe_const< Const, Views >... > value_type
Definition: zip_view.hpp:150
constexpr friend auto iter_move(const iterator &i) noexcept(conjunction< bool_constant< noexcept(ranges::iter_move(std::declval< const iterator_t< maybe_const< Const, Views >> & >()))>..., std::is_nothrow_move_constructible< range_rvalue_reference_t< maybe_const< Const, Views >> >... >::value)
Definition: zip_view.hpp:305
constexpr iterator(iterator< AntiConst > i)
Definition: zip_view.hpp:167
constexpr friend bool operator<(const iterator &x, const iterator &y)
Definition: zip_view.hpp:253
constexpr friend bool operator==(const iterator &x, const iterator &y)
Definition: zip_view.hpp:241
decltype(vccc::tuple_transform(std::declval< std::tuple< iterator_t< maybe_const< Const, Views > >... > & >(), std::declval< tuple_deref_fn >())) reference
Definition: zip_view.hpp:158
constexpr friend bool operator!=(const iterator &x, const iterator &y)
Definition: zip_view.hpp:248
constexpr iterator & operator-=(difference_type n)
Definition: zip_view.hpp:229
constexpr iterator & operator+=(difference_type n)
Definition: zip_view.hpp:219
constexpr iterator operator--(int)
Definition: zip_view.hpp:212
constexpr friend bool operator>(const iterator &x, const iterator &y)
Definition: zip_view.hpp:264
constexpr friend bool operator<=(const iterator &x, const iterator &y)
Definition: zip_view.hpp:258
constexpr friend iterator operator+(difference_type n, const iterator &i)
Definition: zip_view.hpp:283
constexpr iterator operator++(int)
Definition: zip_view.hpp:200
constexpr friend bool operator>=(const iterator &x, const iterator &y)
Definition: zip_view.hpp:270
friend class zip_view
Definition: zip_view.hpp:131
constexpr friend difference_type operator-(const iterator &i, const iterator &j)
Definition: zip_view.hpp:301
std::conditional_t< all_random_access::value, random_access_iterator_tag, std::conditional_t< all_bidirectional::value, bidirectional_iterator_tag, std::conditional_t< all_forward::value, forward_iterator_tag, input_iterator_tag > >> iterator_concept
Definition: zip_view.hpp:149
constexpr iterator & operator++()
Definition: zip_view.hpp:189
Definition: zip_view.hpp:375
constexpr friend bool operator==(const sentinel &y, const iterator< OtherConst > &x)
Definition: zip_view.hpp:404
constexpr sentinel(sentinel< AntiConst > i)
Definition: zip_view.hpp:385
constexpr friend bool operator!=(const sentinel &y, const iterator< OtherConst > &x)
Definition: zip_view.hpp:424
constexpr friend bool operator==(const iterator< OtherConst > &x, const sentinel &y)
Definition: zip_view.hpp:394
constexpr friend bool operator!=(const iterator< OtherConst > &x, const sentinel &y)
Definition: zip_view.hpp:414
constexpr friend common_type_t< range_difference_t< maybe_const< OtherConst, Views > >... > operator-(const sentinel &y, const iterator< OtherConst > &x)
Definition: zip_view.hpp:447
constexpr friend common_type_t< range_difference_t< maybe_const< OtherConst, Views > >... > operator-(const iterator< OtherConst > &x, const sentinel &y)
Definition: zip_view.hpp:435
Definition: zip_view.hpp:109
constexpr zip_view(Views... views)
Definition: zip_view.hpp:466
constexpr auto size() const
Definition: zip_view.hpp:517
constexpr auto size()
Definition: zip_view.hpp:504
constexpr auto end()
Definition: zip_view.hpp:490
constexpr auto end() const
Definition: zip_view.hpp:497
constexpr auto begin() const
Definition: zip_view.hpp:481
constexpr auto begin()
Definition: zip_view.hpp:474
constexpr VCCC_INLINE_OR_STATIC detail::min_niebloid min
Definition: min.hpp:90
constexpr VCCC_INLINE_OR_STATIC detail_iter_move::iter_move_niebloid iter_move
Definition: iter_move.hpp:92
constexpr VCCC_INLINE_OR_STATIC detail_iter_swap::iter_swap_niebloid iter_swap
Definition: iter_swap.hpp:90
std::forward_iterator_tag forward_iterator_tag
Definition: iterator_tag.hpp:17
std::random_access_iterator_tag random_access_iterator_tag
Definition: iterator_tag.hpp:19
typename iter_difference< T >::type iter_difference_t
Computes the difference type of T
Definition: iter_difference_t.hpp:49
std::input_iterator_tag input_iterator_tag
Definition: iterator_tag.hpp:15
std::bidirectional_iterator_tag bidirectional_iterator_tag
Definition: iterator_tag.hpp:18
typename sentinel< R >::type sentinel_t
Definition: sentinel_t.hpp:29
typename ranges::iterator< T >::type iterator_t
Definition: iterator_t.hpp:32
constexpr VCCC_INLINE_OR_STATIC detail::begin_niebloid begin
returns an iterator to the beginning of a range
Definition: begin.hpp:116
typename range_rvalue_reference< R >::type range_rvalue_reference_t
Used to obtain the rvalue reference type of the iterator type of range type R.
Definition: range_rvalue_reference_t.hpp:38
constexpr VCCC_INLINE_OR_STATIC detail::size_niebloid size
returns the size of a container or array
Definition: size.hpp:145
constexpr VCCC_INLINE_OR_STATIC detail::end_niebloid end
returns a sentinel indicating the end of a range
Definition: end.hpp:120
constexpr decltype(auto) apply(F &&f, Tuple &&t)
calls a function with the elements of tuple of arguments
Definition: apply.hpp:89
constexpr std::enable_if_t< detail::tuple_for_each_invocable< Tuple, F >::value > tuple_for_each(Tuple &&t, F &&f)
Definition: tuple_for_each.hpp:76
constexpr auto tuple_transform(Tuple &&t, F &&f) noexcept(noexcept(detail::tuple_transform_impl(std::forward< Tuple >(t), std::forward< F >(f), std::make_index_sequence< std::tuple_size< remove_cvref_t< Tuple >>::value >{})))
Constructs a new tuple with each elements transformed.
Definition: tuple_transform.hpp:36
std::integral_constant< bool, v > bool_constant
Definition: bool_constant.hpp:19
typename common_type< T... >::type common_type_t
Definition: common_type.hpp:229
typename remove_cvref< T >::type remove_cvref_t
Definition: remove_cvref.hpp:24
std::conditional_t< Const, const V, V > maybe_const
Definition: maybe_const.hpp:16
constexpr VCCC_INLINE_OR_STATIC in_place_t in_place
Definition: in_place.hpp:47
Definition: matrix.hpp:495
Definition: directory.h:12
constexpr VCCC_INLINE_OR_STATIC detail::element_niebloid< 1 > value
Definition: key_value.hpp:35
Definition: conjunction.hpp:22
Models std::convertible_to
Definition: convertible_to.hpp:38
Definition: in_place.hpp:35
in-place construction tag
Definition: in_place.hpp:25
Definition: indirectly_swappable.hpp:46
specifies a range whose iterator type satisfies input_iterator
Definition: input_range.hpp:46
Definition: sentinel_t.hpp:18
specifies that a range is a view, that is, it has constant time copy/move/assignment
Definition: view.hpp:31
Definition: sentinel_for.hpp:24
specifies that the - operator can be applied to an iterator and a sentinel to calculate their differe...
Definition: sized_sentinel_for.hpp:75