VCCC  2024.05
VisualCamp Common C++ library
concat_with_view.hpp
Go to the documentation of this file.
1 //
2 // Created by YongGyu Lee on 2/20/24.
3 //
4 
5 #ifndef CONCAT_WITH_VIEW_HPP
6 #define CONCAT_WITH_VIEW_HPP
7 
8 #include <functional>
9 #include <tuple>
10 #include <type_traits>
11 #include <utility>
12 
14 #include "vccc/__iterator/next.hpp"
18 #include "vccc/__ranges/end.hpp"
30 #include "vccc/variant.hpp"
31 
32 namespace vccc {
33 namespace ranges {
34 namespace detail {
35 
36 template<typename Pattern, typename... Rngs>
37 using concat_with_compatible = conjunction<
38  has_typename_type<common_type<range_value_t<Pattern>, range_value_t<Rngs>...>>,
39  has_typename_type<common_reference<range_reference_t<Pattern>, range_reference_t<Rngs>...>>,
40  has_typename_type<common_reference<range_rvalue_reference_t<Pattern>, range_rvalue_reference_t<Rngs>...>>
41 >;
42 
43 } // namespace detail
44 
47 
48 template<typename Pattern, typename... Rngs>
49 struct concat_with_view : view_interface<concat_with_view<Pattern, Rngs...>> {
50  static_assert(sizeof...(Rngs) != 0, "Constraints not satisfied");
51  static_assert(conjunction<input_range<Rngs>...>::value, "Constraints not satisfied");
52  static_assert(view<Pattern>::value, "Constraints not satisfied");
53  static_assert(detail::concat_with_compatible<Pattern, Rngs...>::value, "Constraints not satisfied");
54 
55  private:
56  using difference_type_ = common_type_t<range_difference_t<Rngs>...>;
57  using BackBase = typename type_sequence<Rngs...>::back;
58 
59  static constexpr std::size_t cranges = sizeof...(Rngs);
60  std::tuple<Rngs...> bases_{};
61  Pattern pattern_;
62 
63  public:
64  template<bool IsConst>
65  struct iterator;
66 
67  template<bool Const>
68  struct sentinel {
69  private:
70  friend struct sentinel<!Const>;
71  friend struct iterator<Const>;
72  friend class concat_with_view;
73 
75  using Base = maybe_const<Const, BackBase>;
76  sentinel_t<Base> end_{};
77 
78  constexpr sentinel(Parent& parent)
79  : end_(ranges::end(std::get<cranges - 1>(parent.bases_))) {}
80 
81  public:
82  sentinel() = default;
83 
84  template<bool AntiConst, std::enable_if_t<conjunction<
85  bool_constant<((Const != AntiConst) && Const)>,
87  >::value, int> = 0>
88  constexpr sentinel(sentinel<AntiConst> that)
89  : end_(std::move(that.end_)) {}
90  };
91 
92  template<bool IsConst>
93  struct iterator {
96  std::conditional_t<
98  std::conditional_t<
100  std::conditional_t<
103  >>>;
107  using pointer = void;
108 
109  private:
110  friend struct iterator<!IsConst>;
111  using Parent = maybe_const<IsConst, concat_view>;
112  Parent* parent_;
114 
115  template<std::size_t N, std::enable_if_t<(N < cranges - 1), int> = 0>
116  void satisfy(std::integral_constant<std::size_t, N>) {
117  if (std::get<N>(its_) == ranges::end(std::get<N>(parent_->bases_))) {
118  its_.template emplace<N + 1>(ranges::begin(std::get<N + 1>(parent_->bases_)));
119  this->satisfy(std::integral_constant<size_t, N + 1>{});
120  }
121  }
122 
123  template<std::size_t N, std::enable_if_t<(N >= cranges - 1), int> = 0>
124  void satisfy(std::integral_constant<std::size_t, N>) { /* no op */ }
125 
126  struct next_raw_visitor {
128 
129  template<typename I, std::size_t N>
131  ++it;
132  pos->satisfy(std::integral_constant<size_t, N>{});
133  }
134 
135  template<typename U> void operator()(U&, in_place_index_t<variant_npos>) { /* no op */ }
136  };
137 
138  struct prev_raw_visitor {
140 
141  template<typename I>
143  --it;
144  }
145 
146  template<typename I, std::size_t N, std::enable_if_t<conjunction<
147  bool_constant<(N != 0)>,
149  >::value, int> = 0>
150  void operator()(I& it, in_place_index_t<N>) {
151  if (it == ranges::begin(std::get<N>(pos->parent_->bases_))) {
152  auto&& rng = std::get<N - 1>(pos->parent_->bases_);
153 
154  pos->its_.template emplace<N - 1>(ranges::next(ranges::begin(rng), ranges::end(rng)));
155  vccc::detail::variant_raw_visit(pos->its_.index(), pos->its_._base().storage(), *this);
156  } else {
157  --it;
158  }
159  }
160 
161  template<typename U> void operator()(U&, in_place_index_t<variant_npos>) { /* no op */ }
162  };
163 
164  struct advance_fwd_raw_visitor {
167 
170  ranges::advance(it, n);
171  }
172 
175  auto last = ranges::end(std::get<N>(pos->parent_->bases_));
176  // BUGBUG If distance(it, last) > n, then using bounded advance
177  // is O(n) when it need not be since the last iterator position
178  // is actually not interesting. Only the "rest" is needed, which
179  // can sometimes be O(1).
180  auto rest = ranges::advance(it, n, std::move(last));
181  pos->satisfy(std::integral_constant<size_t, N>{});
182  if (rest != 0) {
183  vccc::detail::variant_raw_visit(
184  pos->its_.index(), pos->its_._base().storage(), advance_fwd_raw_visitor{pos, rest});
185  }
186  }
187 
188  template<typename U> void operator()(U&, in_place_index_t<variant_npos>) { /* no op */ }
189  };
190 
191  struct advance_rev_raw_visitor {
194 
197  ranges::advance(it, n);
198  }
199 
202  auto first = ranges::begin(std::get<N>(pos->parent_->bases_));
203  if (it == first) {
204  auto&& rng = std::get<N - 1>(pos->parent_->bases_);
205  pos->its_.template emplace<N - 1>(ranges::next(ranges::begin(rng), ranges::end(rng)));
206  vccc::detail::variant_raw_visit(pos->its_.index(), pos->its_._base().storage(), *this);
207  } else {
208  auto rest = ranges::advance(it, n, std::move(first));
209  if (rest != 0) {
210  vccc::detail::variant_raw_visit(
211  pos->its_.index(), pos->its_._base().storage(), advance_rev_raw_visitor{pos, rest});
212  }
213  }
214  }
215 
216  template<typename U> void operator()(U&, in_place_index_t<variant_npos>) { /* no op */ }
217  };
218 
219  static difference_type distance_to_(std::integral_constant<size_t, cranges>, iterator const &, iterator const &) {
220  // unreachable
221  return -1;
222  }
223 
224  template<std::size_t N>
225  static difference_type distance_to_(std::integral_constant<size_t, N>, const iterator& from, const iterator& to) {
226  if (from.its_.index() > N)
227  return iterator::distance_to_(std::integral_constant<size_t, N + 1>{}, from, to);
228 
229  if (from.its_.index() == N) {
230  if (to.its_.index() == N)
231  return ranges::distance(vccc::detail::variant_raw_get(from.its_._base().storage(), in_place_index<N>),
232  vccc::detail::variant_raw_get(to.its_._base().storage(), in_place_index<N>));
233  return ranges::distance(vccc::detail::variant_raw_get(from.its_._base().storage(), in_place_index<N>),
234  ranges::end(std::get<N>(from.parent_->bases_)))
235  + iterator::distance_to_(std::integral_constant<size_t, N + 1>{}, from, to);
236  }
237 
238  if (from.its_.index() < N && to.its_.index() > N)
239  return ranges::distance(std::get<N>(from.parent_->bases_))
240  + iterator::distance_to_(std::integral_constant<size_t, N + 1>{}, from, to);
241 
242  return ranges::distance(ranges::begin(std::get<N>(from.parent_->bases_)),
243  vccc::detail::variant_raw_get(to.its_._base().storage(), in_place_index<N>));
244  }
245 
246  public:
247  iterator() = default;
248 
249  template<std::size_t I, typename It>
250  constexpr iterator(Parent* parent, in_place_index_t<I>, It&& it)
251  : parent_(parent)
252  , its_{in_place_index<I>, std::forward<It>(it)} // ranges::begin(std::get<0>(parent->bases_))
253  {
254  this->satisfy(std::integral_constant<size_t, I>{});
255  }
256 
257  // iterator(Parent* parent, end_tag)
258  // : parent_(parent)
259  // , its_{in_place_index<cranges - 1>, ranges::end(std::get<cranges - 1>(parent->bases_))} {}
260 
261 
262  template<bool Other, std::enable_if_t<conjunction<
263  bool_constant<(Other != IsConst && IsConst)>
264  >::value, int> = 0>
265  constexpr iterator(iterator<Other> that)
266  : parent_(that.parent_)
267  , its_(std::move(that.its_)) {}
268 
269  constexpr decltype(auto) operator*() const {
270  return its_.visit([](auto&& it) -> iterator::reference { return *it; });
271  }
272 
273  template<typename V = variant<iterator_t<maybe_const<IsConst, Rngs>>...>, std::enable_if_t<
274  equality_comparable<V>
275  ::value, int> = 0>
276  friend constexpr bool operator==(const iterator& x, const iterator& y) {
277  return x.its_ == y.its_;
278  }
279 
280  template<typename V = variant<iterator_t<maybe_const<IsConst, Rngs>>...>, std::enable_if_t<
281  equality_comparable<V>
282  ::value, int> = 0>
283  friend constexpr bool operator!=(const iterator& x, const iterator& y) {
284  return !(x == y);
285  }
286 
287  friend constexpr bool operator==(const iterator& x, const sentinel<IsConst>& y) {
288  return x.equal(y);
289  }
290 
291  friend constexpr bool operator!=(const iterator& x, const sentinel<IsConst>& y) {
292  return !(x == y);
293  }
294 
295  friend constexpr bool operator==(const sentinel<IsConst>& y, const iterator& x) {
296  return x == y;
297  }
298 
299  friend constexpr bool operator!=(const sentinel<IsConst>& y, const iterator& x) {
300  return !(x == y);
301  }
302 
303  constexpr bool equal(const sentinel<IsConst>& pos) const {
304  return its_.index() == cranges - 1 && std::get<cranges - 1>(its_) == pos.end_;
305  }
306 
307  constexpr iterator& operator++() {
308  vccc::detail::variant_raw_visit(its_.index(), its_._base().storage(), next_raw_visitor{this});
309  return *this;
310  }
311 
312  template<typename Dummy = void, std::enable_if_t<conjunction<
313  std::is_void<Dummy>,
315  >::value, int> = 0>
316  constexpr void operator++(int) {
317  ++*this;
318  }
319 
320  template<typename Dummy = void, std::enable_if_t<conjunction<
321  std::is_void<Dummy>,
323  >::value, int> = 0>
324  constexpr iterator operator++(int) {
325  auto tmp = *this;
326  ++*this;
327  return tmp;
328  }
329 
330  template<typename Dummy = void, std::enable_if_t<conjunction<
331  std::is_void<Dummy>,
333  >::value, int> = 0>
334  constexpr iterator& operator--() {
335  vccc::detail::variant_raw_visit(its_.index(), its_._base().storage(), prev_raw_visitor{this});
336  return *this;
337  }
338 
339  template<typename Dummy = void, std::enable_if_t<conjunction<
340  std::is_void<Dummy>,
342  >::value, int> = 0>
343  constexpr iterator& operator--(int) {
344  auto tmp = *this;
345  --*this;
346  return tmp;
347  }
348 
349  template<typename Dummy = void, std::enable_if_t<conjunction<
350  std::is_void<Dummy>,
352  >::value, int> = 0>
354  if (n > 0) {
355  vccc::detail::variant_raw_visit(its_.index(), its_._base().storage(), advance_fwd_raw_visitor{this, n});
356  } else if (n < 0) {
357  vccc::detail::variant_raw_visit(its_.index(), its_._base().storage(), advance_rev_raw_visitor{this, n});
358  }
359  return *this;
360  }
361 
362  template<typename Dummy = void, std::enable_if_t<conjunction<
363  std::is_void<Dummy>,
365  >::value, int> = 0>
367  *this += -n;
368  return *this;
369  }
370 
371  template<typename Dummy = void, std::enable_if_t<conjunction<
372  std::is_void<Dummy>,
374  >::value, int> = 0>
375  friend constexpr difference_type operator-(const iterator& x, const iterator& y) {
376  if (x.its_.index() <= y.its_.index())
377  return -iterator::distance_to_(std::integral_constant<std::size_t, 0>{}, x, y);
378  return iterator::distance_to_(std::integral_constant<std::size_t, 0>{}, y, x);
379  }
380 
381  };
382 
383 
384  concat_with_view() = default;
385 
386  explicit concat_with_view(Rngs... rngs)
387  : bases_{std::move(rngs)...} {}
388 
389  constexpr auto begin() {
390  using Const = conjunction<simple_view<Rngs>...>;
391  return iterator<Const::value>{this, in_place_index<0>, ranges::begin(std::get<0>(bases_))};
392  }
393 
394  template<typename Dummy = void, std::enable_if_t<conjunction<
395  std::is_void<Dummy>,
397  >::value, int> = 0>
398  constexpr iterator<true> begin() const {
399  return iterator<true>{this, in_place_index<0>, ranges::begin(std::get<0>(bases_))};
400  }
401 
402  template<typename Dummy = void, std::enable_if_t<conjunction<
403  std::is_void<Dummy>,
405  >::value, int> = 0>
406  constexpr auto end() {
407  using Const = conjunction<simple_view<Rngs>...>;
408  return iterator<Const::value>{this, in_place_index<cranges - 1>, ranges::end(std::get<cranges - 1>(bases_))};
409  }
410 
411  template<typename Dummy = void, std::enable_if_t<conjunction<
412  std::is_void<Dummy>,
414  >::value, int> = 0>
415  constexpr auto end() {
416  using Const = conjunction<simple_view<Rngs>...>;
417  return sentinel<Const::value>{*this};
418  }
419 
420  template<typename Dummy = void, std::enable_if_t<conjunction<
421  std::is_void<Dummy>,
423  >::value, int> = 0>
424  constexpr auto end() const {
425  return end_impl(conjunction<common_range<const Rngs>...>{});
426  }
427 
428  template<typename Dummy = void, std::enable_if_t<conjunction<
429  std::is_void<Dummy>,
431  >::value, int> = 0>
432  constexpr auto size() {
433  return vccc::tuple_fold_left(
434  vccc::tuple_transform(bases_, [](auto&& r) { return r.size(); }),
435  std::size_t{0},
436  std::plus<>{}
437  );
438  }
439 
440  template<typename Dummy = void, std::enable_if_t<conjunction<
441  std::is_void<Dummy>,
443  >::value, int> = 0>
444  constexpr auto size() const {
445  return vccc::tuple_fold_left(
446  vccc::tuple_transform(bases_, [](auto&& r) { return r.size(); }),
447  std::size_t{0},
448  std::plus<>{}
449  );
450  }
451 
452  private:
453  constexpr iterator<true> end_impl(std::true_type /* common_range */) const {
454  return iterator<true>{this, in_place_index<cranges - 1>, ranges::end(std::get<cranges - 1>(bases_))};
455  }
456 
457  constexpr sentinel<true> end_impl(std::false_type /* common_range */) const {
458  return sentinel<true>{*this};
459  }
460 };
461 
462 #if __cplusplus >= 201703L
463 
464 template<typename... Rng>
465 concat_view(Rng &&...) //
467 
468 #endif
469 
470 namespace views {
471 namespace detail {
472 
474  template<typename... R, std::enable_if_t<conjunction<
476  input_range<R>...
477  >::value, int> = 0>
478  constexpr auto operator()(R&&... rs) const {
479  return concat_with_view<all_t<R>...>{views::all(std::forward<R>(rs))...};
480  }
481 };
482 
483 } // namespace detail
484 
487 
489 
490 } // namespace views
491 
492 } // namespace ranges
493 } // namespace vccc
494 
495 #endif // CONCAT_WITH_VIEW_HPP
helper class template for defining a view, using the curiously recurring template pattern
Definition: view_interface.hpp:78
constexpr decltype(auto) back()
Definition: view_interface.hpp:255
a type-safe discriminated union
Definition: variant.hpp:589
constexpr std::size_t index() const noexcept
Definition: variant.hpp:662
constexpr decltype(auto) visit(Visitor &&vis) &
Definition: variant.hpp:707
constexpr VCCC_INLINE_OR_STATIC detail::advance_niebloid advance
Definition: advance.hpp:158
constexpr VCCC_INLINE_OR_STATIC detail::next_niebloid next
Definition: next.hpp:65
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
std::input_iterator_tag input_iterator_tag
Definition: iterator_tag.hpp:15
std::bidirectional_iterator_tag bidirectional_iterator_tag
Definition: iterator_tag.hpp:18
constexpr std::enable_if_t<(detail::ranges_to_1_tag< C, R, Args... >::value > 0), C > to(R &&r, Args &&... args)
Constructs an object of type C from the elements of r
Definition: to.hpp:446
constexpr iterator & operator--()
Definition: concat_with_view.hpp:334
constexpr iterator(Parent *parent, in_place_index_t< I >, It &&it)
Definition: concat_with_view.hpp:250
common_type_t< range_difference_t< Rngs >... > difference_type
Definition: concat_with_view.hpp:105
constexpr iterator & operator--(int)
Definition: concat_with_view.hpp:343
std::conditional_t< conjunction< random_access_range< Rngs >... >::value, random_access_iterator_tag, std::conditional_t< conjunction< bidirectional_range< Rngs >... >::value, bidirectional_iterator_tag, std::conditional_t< conjunction< forward_range< Rngs >... >::value, forward_iterator_tag, input_iterator_tag > >> iterator_concept
Definition: concat_with_view.hpp:103
void pointer
Definition: concat_with_view.hpp:107
constexpr friend bool operator==(const sentinel< IsConst > &y, const iterator &x)
Definition: concat_with_view.hpp:295
constexpr auto get(const subrange< I, S, K > &r)
Definition: subrange.hpp:371
constexpr auto size() const
Definition: concat_with_view.hpp:444
constexpr auto size()
Definition: concat_with_view.hpp:432
common_reference_t< range_reference_t< maybe_const< IsConst, Rngs > >... > reference
Definition: concat_with_view.hpp:106
constexpr friend difference_type operator-(const iterator &x, const iterator &y)
Definition: concat_with_view.hpp:375
constexpr void operator++(int)
Definition: concat_with_view.hpp:316
constexpr auto begin()
Definition: concat_with_view.hpp:389
concat_with_view(Rngs... rngs)
Definition: concat_with_view.hpp:386
typename sentinel< R >::type sentinel_t
Definition: sentinel_t.hpp:29
typename ranges::iterator< T >::type iterator_t
Definition: iterator_t.hpp:32
iterator * pos
Definition: concat_with_view.hpp:127
difference_type n
Definition: concat_with_view.hpp:166
constexpr VCCC_INLINE_OR_STATIC detail::begin_niebloid begin
returns an iterator to the beginning of a range
Definition: begin.hpp:116
constexpr friend bool operator==(const iterator &x, const iterator &y)
Definition: concat_with_view.hpp:276
void operator()(I &it, in_place_index_t< 0 >)
Definition: concat_with_view.hpp:196
constexpr VCCC_INLINE_OR_STATIC detail::distance_niebloid distance
Definition: distance.hpp:72
common_type_t< range_value_t< maybe_const< IsConst, Rngs > >... > value_type
Definition: concat_with_view.hpp:104
constexpr friend bool operator!=(const iterator &x, const iterator &y)
Definition: concat_with_view.hpp:283
constexpr auto end()
Definition: concat_with_view.hpp:406
void operator()(I &it, in_place_index_t< 0 >)
Definition: concat_with_view.hpp:142
constexpr iterator & operator-=(difference_type n)
Definition: concat_with_view.hpp:366
constexpr friend bool operator==(const iterator &x, const sentinel< IsConst > &y)
Definition: concat_with_view.hpp:287
constexpr VCCC_INLINE_OR_STATIC detail::concat_with_niebloid concat_with
concatenate ranges
Definition: concat_with_view.hpp:486
constexpr auto end() const
Definition: concat_with_view.hpp:424
void operator()(I &it, in_place_index_t< N >)
Definition: concat_with_view.hpp:174
constexpr friend bool operator!=(const sentinel< IsConst > &y, const iterator &x)
Definition: concat_with_view.hpp:299
constexpr iterator & operator+=(difference_type n)
Definition: concat_with_view.hpp:353
input_iterator_tag iterator_category
Definition: concat_with_view.hpp:94
constexpr iterator< true > begin() const
Definition: concat_with_view.hpp:398
void operator()(I &it, in_place_index_t< N >)
Definition: concat_with_view.hpp:130
constexpr VCCC_INLINE_OR_STATIC detail::end_niebloid end
returns a sentinel indicating the end of a range
Definition: end.hpp:120
void operator()(U &, in_place_index_t< variant_npos >)
Definition: concat_with_view.hpp:135
constexpr iterator(iterator< Other > that)
Definition: concat_with_view.hpp:265
constexpr bool equal(const sentinel< IsConst > &pos) const
Definition: concat_with_view.hpp:303
constexpr friend bool operator!=(const iterator &x, const sentinel< IsConst > &y)
Definition: concat_with_view.hpp:291
constexpr iterator & operator++()
Definition: concat_with_view.hpp:307
constexpr VCCC_INLINE_OR_STATIC detail::all_adaptor_closure all
a view that includes all elements of a range
Definition: all.hpp:82
void operator()(I &it, in_place_index_t< cranges - 1 >)
Definition: concat_with_view.hpp:169
constexpr auto tuple_fold_left(Tuple &&tuple, T &&init, F &&f)
Left fold operation for each tuple elements.
Definition: tuple_fold.hpp:52
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_reference< T... >::type common_reference_t
Definition: common_reference.hpp:54
typename common_type< T... >::type common_type_t
Definition: common_type.hpp:229
std::conditional_t< Const, const V, V > maybe_const
Definition: maybe_const.hpp:16
constexpr VCCC_INLINE_OR_STATIC in_place_index_t< I > in_place_index
Definition: in_place.hpp:53
#define VCCC_INLINE_OR_STATIC
Definition: inline_or_static.hpp:9
Definition: matrix.hpp:495
constexpr std::enable_if_t<(I< m *n), typename vccc::Matrix< T, m, n >::value_type & > get(vccc::Matrix< T, m, n > &matrix)
Definition: matrix.hpp:499
Definition: directory.h:12
constexpr VCCC_INLINE_OR_STATIC detail::element_niebloid< 0 > first
Definition: key_value.hpp:34
constexpr VCCC_INLINE_OR_STATIC detail::element_niebloid< 1 > value
Definition: key_value.hpp:35
specifies that a forward_iterator is a bidirectional iterator, supporting movement backwards
Definition: bidirectional_iterator.hpp:58
Definition: conjunction.hpp:22
Models std::convertible_to
Definition: convertible_to.hpp:38
Definition: in_place.hpp:35
Definition: negation.hpp:23
specifies a range whose iterator type satisfies bidirectional_iterator
Definition: bidirectional_range.hpp:49
Definition: common_range.hpp:41
Definition: concat_view.hpp:50
Definition: concat_with_view.hpp:93
constexpr iterator operator++(int)
Definition: concat_with_view.hpp:324
Definition: concat_with_view.hpp:68
Definition: concat_with_view.hpp:49
constexpr auto end()
Definition: concat_with_view.hpp:415
specifies a range whose iterator type satisfies forward_iterator
Definition: forward_range.hpp:47
specifies a range whose iterator type satisfies input_iterator
Definition: input_range.hpp:46
specifies a range whose iterator type satisfies random_access_iterator
Definition: random_access_range.hpp:48
specifies that a type is a range, that is, it provides a begin iterator and an end sentinel
Definition: range.hpp:53
specifies that a range knows its size in constant time
Definition: sized_range.hpp:38
specifies that a range is a view, that is, it has constant time copy/move/assignment
Definition: view.hpp:31
specifies the requirements for a range to be safely convertible to a view
Definition: viewable_range.hpp:59
Definition: concat_with_view.hpp:473
constexpr auto operator()(R &&... rs) const
Definition: concat_with_view.hpp:478
specifies that the - operator can be applied to an iterator and a sentinel to calculate their differe...
Definition: sized_sentinel_for.hpp:75
Definition: type_sequence.hpp:110