Horizon
variant.hpp
1 // Range v3 library
2 //
3 // Copyright Eric Niebler 2014-present
4 //
5 // Use, modification and distribution is subject to the
6 // Boost Software License, Version 1.0. (See accompanying
7 // file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
9 //
10 // Project home: https://github.com/ericniebler/range-v3
11 //
12 
13 #ifndef RANGES_V3_DETAIL_VARIANT_HPP
14 #define RANGES_V3_DETAIL_VARIANT_HPP
15 
16 #include <iterator>
17 #include <memory>
18 #include <new>
19 #include <stdexcept>
20 #include <tuple>
21 #include <type_traits>
22 #include <utility>
23 
24 #include <meta/meta.hpp>
25 
26 #include <concepts/concepts.hpp>
27 
28 #include <range/v3/range_fwd.hpp>
29 
35 #include <range/v3/utility/get.hpp>
36 
37 #include <range/v3/detail/prologue.hpp>
38 
39 namespace ranges
40 {
41  template<std::size_t I>
42  struct emplaced_index_t;
43 
44  template<std::size_t I>
46  {};
47 
48 #if RANGES_CXX_INLINE_VARIABLES < RANGES_CXX_INLINE_VARIABLES_17
49  namespace
50  {
51  template<std::size_t I>
52  constexpr auto & emplaced_index = static_const<emplaced_index_t<I>>::value;
53  }
54 #else // RANGES_CXX_INLINE_VARIABLES >= RANGES_CXX_INLINE_VARIABLES_17
55  template<std::size_t I>
56  inline constexpr emplaced_index_t<I> emplaced_index{};
57 #endif // RANGES_CXX_INLINE_VARIABLES
58 
59  struct bad_variant_access : std::logic_error
60  {
61  explicit bad_variant_access(std::string const & what_arg)
62  : std::logic_error(what_arg)
63  {}
64  explicit bad_variant_access(char const * what_arg)
65  : std::logic_error(what_arg)
66  {}
67  };
68 
69  template<typename T, std::size_t Index>
71  {
72  private:
73  std::add_pointer_t<T> t_;
74 
75  public:
76  constexpr explicit indexed_element(T & t) noexcept
77  : t_(std::addressof(t))
78  {}
79  constexpr T & get() const noexcept
80  {
81  return *t_;
82  }
83  };
84  template<typename T, std::size_t Index>
85  struct indexed_element<T &&, Index>
86  {
87  private:
88  T * t_;
89 
90  public:
91  constexpr explicit indexed_element(T && t) noexcept
92  : t_(std::addressof(t))
93  {}
94  constexpr T && get() const noexcept
95  {
96  return static_cast<T &&>(*t_);
97  }
98  };
99  template<std::size_t Index>
100  struct indexed_element<void, Index>
101  {
102  void get() const noexcept
103  {}
104  };
105 
107  namespace detail
108  {
109  struct indexed_element_fn;
110 
111  template(typename I, typename S, typename O)(
112  requires (!sized_sentinel_for<S, I>)) //
113  O uninitialized_copy(I first, S last, O out)
114  {
115  for(; first != last; ++first, ++out)
116  ::new((void *)std::addressof(*out)) iter_value_t<O>(*first);
117  return out;
118  }
119 
120  template(typename I, typename S, typename O)(
121  requires sized_sentinel_for<S, I>)
122  O uninitialized_copy(I first, S last, O out)
123  {
124  return std::uninitialized_copy_n(first, (last - first), out);
125  }
126 
127  template<typename I, typename O>
128  O uninitialized_copy(I first, I last, O out)
129  {
130  return std::uninitialized_copy(first, last, out);
131  }
132 
133  template<typename T, typename Index>
134  struct indexed_datum
135  {
136  private:
137  template<typename, typename>
138  friend struct indexed_datum;
139  T datum_;
140 
141  public:
142  CPP_member
143  constexpr CPP_ctor(indexed_datum)()( //
144  noexcept(std::is_nothrow_default_constructible<T>::value) //
145  requires default_constructible<T>)
146  : datum_{}
147  {}
148  template(typename... Ts)(
149  requires constructible_from<T, Ts...> AND (sizeof...(Ts) != 0)) //
150  constexpr indexed_datum(Ts &&... ts) noexcept(
151  std::is_nothrow_constructible<T, Ts...>::value)
152  : datum_(static_cast<Ts &&>(ts)...)
153  {}
154  template(typename U)(
155  requires (!same_as<T, U>) AND convertible_to<U, T>)
156  constexpr indexed_datum(indexed_datum<U, Index> that) //
157  noexcept(std::is_nothrow_constructible<T, U>::value) //
158  : datum_(std::move(that.datum_))
159  {}
160  constexpr auto ref() noexcept
161  {
162  return indexed_element<T, Index::value>{datum_};
163  }
164  constexpr auto ref() const noexcept
165  {
166  return indexed_element<T const, Index::value>{datum_};
167  }
168  constexpr T & get() noexcept
169  {
170  return datum_;
171  }
172  constexpr T const & get() const noexcept
173  {
174  return datum_;
175  }
176  };
177 
178  template<typename T, std::size_t N, typename Index>
179  struct indexed_datum<T[N], Index>;
180 
181  template<typename T, typename Index>
182  struct indexed_datum<T &, Index>
183  {
184  private:
185  template<typename, typename>
186  friend struct indexed_datum;
187  T * t_;
188 
189  public:
190  constexpr indexed_datum(T & t) noexcept
191  : t_(std::addressof(t))
192  {}
193  constexpr T & get() const noexcept
194  {
195  return *t_;
196  }
197  constexpr auto ref() const noexcept
198  {
199  return indexed_element<T &, Index::value>{*t_};
200  }
201  };
202  template<typename T, typename Index>
203  struct indexed_datum<T &&, Index>
204  {
205  private:
206  template<typename, typename>
207  friend struct indexed_datum;
208  T * t_;
209 
210  public:
211  constexpr indexed_datum(T && t) noexcept
212  : t_(std::addressof(t))
213  {}
214  constexpr T && get() const noexcept
215  {
216  return static_cast<T &&>(*t_);
217  }
218  constexpr auto ref() const noexcept
219  {
220  return indexed_element<T &&, Index::value>{static_cast<T &&>(*t_)};
221  }
222  };
223  template<typename Index>
224  struct indexed_datum<void, Index>
225  {
226  void get() const noexcept
227  {}
228  constexpr indexed_element<void, Index::value> ref() const noexcept
229  {
230  return {};
231  }
232  };
233 
234  template<std::size_t Index, typename... Ts>
235  using variant_datum_t =
236  detail::indexed_datum<meta::at_c<meta::list<Ts...>, Index>,
238 
239  using variant_nil = indexed_datum<void, meta::npos>;
240 
241  template<typename Ts,
242  bool Trivial = meta::apply<
245  type::value>
246  struct variant_data_
247  {
248  using type = indexed_datum<void, meta::npos>;
249  };
250 
251  template<typename T, typename... Ts>
252  struct variant_data_<meta::list<T, Ts...>, true>
253  {
254  struct type
255  {
256  using head_t = T;
257  using tail_t = meta::_t<variant_data_<meta::list<Ts...>>>;
258  union
259  {
260  head_t head;
261  tail_t tail;
262  };
263 
264  type() noexcept
265  {}
266  template<typename... Args>
267  constexpr type(meta::size_t<0>, Args &&... args) noexcept(
268  std::is_nothrow_constructible<head_t, Args...>::value)
269  : head{((Args &&) args)...}
270  {}
271  template<std::size_t N, typename... Args>
272  constexpr type(meta::size_t<N>, Args &&... args) noexcept(
273  std::is_nothrow_constructible<tail_t, meta::size_t<N - 1>,
274  Args...>::value)
275  : tail{meta::size_t<N - 1>{}, ((Args &&) args)...}
276  {}
277  };
278  };
279 
280  template<typename T, typename... Ts>
281  struct variant_data_<meta::list<T, Ts...>, false>
282  {
283  struct type
284  {
285  using head_t = T;
286  using tail_t = meta::_t<variant_data_<meta::list<Ts...>>>;
287  union
288  {
289  head_t head;
290  tail_t tail;
291  };
292 
293  type() noexcept
294  {}
295  ~type()
296  {}
297  template<typename... Args>
298  constexpr type(meta::size_t<0>, Args &&... args) noexcept(
299  std::is_nothrow_constructible<head_t, Args...>::value)
300  : head{((Args &&) args)...}
301  {}
302  template<std::size_t N, typename... Args>
303  constexpr type(meta::size_t<N>, Args &&... args) noexcept(
304  std::is_nothrow_constructible<tail_t, meta::size_t<N - 1>,
305  Args...>::value)
306  : tail{meta::size_t<N - 1>{}, ((Args &&) args)...}
307  {}
308  };
309  };
310 
311  template<typename... Ts>
312  using variant_data = meta::_t<variant_data_<meta::transform<
313  meta::list<Ts...>, meta::as_list<meta::make_index_sequence<sizeof...(Ts)>>,
315 
316  inline std::size_t variant_move_copy_(std::size_t, variant_nil, variant_nil)
317  {
318  return 0;
319  }
320  template<typename Data0, typename Data1>
321  std::size_t variant_move_copy_(std::size_t n, Data0 & self, Data1 && that)
322  {
323  using Head = typename Data0::head_t;
324  return 0 == n
325  ? ((void)::new((void *)&self.head) Head(((Data1 &&) that).head), 0)
326  : variant_move_copy_(n - 1, self.tail, ((Data1 &&) that).tail) + 1;
327  }
328  constexpr bool variant_equal_(std::size_t, variant_nil, variant_nil)
329  {
330  return true;
331  }
332  template<typename Data0, typename Data1>
333  constexpr bool variant_equal_(std::size_t n, Data0 const & self,
334  Data1 const & that)
335  {
336  return n == 0 ? self.head.get() == that.head.get()
337  : variant_equal_(n - 1, self.tail, that.tail);
338  }
339  template<typename Fun, typename Proj = indexed_element_fn>
340  constexpr int variant_visit_(std::size_t, variant_nil, Fun, Proj = {})
341  {
342  return (RANGES_EXPECT(false), 0);
343  }
344  template<typename Data, typename Fun, typename Proj = indexed_element_fn>
345  constexpr int variant_visit_(std::size_t n, Data & self, Fun fun, Proj proj = {})
346  {
347  return 0 == n ? ((void)invoke(fun, invoke(proj, self.head)), 0)
348  : detail::variant_visit_(
349  n - 1, self.tail, detail::move(fun), detail::move(proj));
350  }
351 
352  struct get_datum_fn
353  {
354  template<typename T>
355  decltype(auto) operator()(T && t) const noexcept
356  {
357  return t.get();
358  }
359  };
360 
361  struct indexed_element_fn
362  {
363  template<typename T>
364  decltype(auto) operator()(T && t) const noexcept
365  {
366  return t.ref();
367  }
368  };
369 
370  struct empty_variant_tag
371  {};
372 
373  struct variant_core_access
374  {
375  template<typename... Ts>
376  static constexpr variant_data<Ts...> & data(variant<Ts...> & var) noexcept
377  {
378  return var.data_();
379  }
380  template<typename... Ts>
381  static constexpr variant_data<Ts...> const & data(
382  variant<Ts...> const & var) noexcept
383  {
384  return var.data_();
385  }
386  template<typename... Ts>
387  static constexpr variant_data<Ts...> && data(variant<Ts...> && var) noexcept
388  {
389  return detail::move(var.data_());
390  }
391  template<typename... Ts>
392  static variant<Ts...> make_empty(meta::id<variant<Ts...>> = {}) noexcept
393  {
394  return variant<Ts...>{empty_variant_tag{}};
395  }
396  };
397 
398  struct delete_fn
399  {
400  template<typename T>
401  void operator()(T const & t) const noexcept
402  {
403  t.~T();
404  }
405  };
406 
407  template<std::size_t N, typename... Ts>
408  struct construct_fn
409  {
410  std::tuple<Ts...> args_;
411 
412  template<typename U, std::size_t... Is>
413  void construct_(U & u, meta::index_sequence<Is...>) noexcept(
414  std::is_nothrow_constructible<U, Ts...>::value)
415  {
416  ::new((void *)std::addressof(u))
417  U(static_cast<Ts &&>(std::get<Is>(args_))...);
418  }
419 
420  construct_fn(Ts &&... ts) noexcept(
421  std::is_nothrow_constructible<std::tuple<Ts...>, Ts...>::value)
422  : args_{static_cast<Ts &&>(ts)...}
423  {}
424  template<typename U, std::size_t M>
425  [[noreturn]] meta::if_c<N != M> operator()(
426  indexed_datum<U, meta::size_t<M>> &) noexcept
427  {
428  RANGES_EXPECT(false);
429  }
430  template<typename U>
431  meta::if_<std::is_object<U>> operator()(
432  indexed_datum<U, meta::size_t<N>> &
433  u) noexcept(std::is_nothrow_constructible<U, Ts...>::value)
434  {
435  this->construct_(u.get(), meta::make_index_sequence<sizeof...(Ts)>{});
436  }
437  template<typename U>
439  indexed_datum<U, meta::size_t<N>> &
440  u) noexcept(std::is_nothrow_constructible<detail::decay_t<U>,
441  Ts...>::value)
442  {
443  this->construct_(u, meta::make_index_sequence<sizeof...(Ts)>{});
444  }
445  };
446 
447  template<typename T, std::size_t N>
448  struct get_fn
449  {
450  T ** t_;
451 
452  template<typename U, std::size_t M>
453  [[noreturn]] meta::if_c<M != N> operator()(indexed_element<U, M>) const
454  {
455  throw bad_variant_access("bad variant access");
456  }
457  template<typename U>
458  void operator()(indexed_element<U, N> t) const noexcept
459  {
460  *t_ = std::addressof(t.get());
461  }
462  template<typename U>
463  void operator()(indexed_element<U &&, N> t) const noexcept
464  {
465  U && u = t.get();
466  *t_ = std::addressof(u);
467  }
468  void operator()(indexed_element<void, N>) const noexcept
469  {}
470  };
471 
472  template<typename Variant, std::size_t N>
473  struct emplace_fn
474  {
475  Variant * var_;
476  // clang-format off
477  template<typename...Ts>
478  auto CPP_auto_fun(operator())(Ts &&...ts) (const)
479  (
480  return var_->template emplace<N>(static_cast<Ts &&>(ts)...)
481  )
482  // clang-format on
483  };
484 
485  template<typename Fun, typename Variant>
486  struct variant_visitor
487  {
488  Fun fun_;
489  Variant * var_;
490 
491  // clang-format off
492  template<typename U, std::size_t N>
493  auto CPP_auto_fun(operator())(indexed_element<U, N> u)
494  (
495  return compose(emplace_fn<Variant, N>{var_}, fun_)(u)
496  )
497  // clang-format on
498  };
499 
500  template<typename Variant, typename Fun>
501  variant_visitor<Fun, Variant> make_variant_visitor(
502  Variant & var,
503  Fun fun) noexcept(std::is_nothrow_move_constructible<Fun>::value)
504  {
505  return {detail::move(fun), &var};
506  }
507 
508  template<typename To, typename From>
509  struct unique_visitor;
510 
511  template<typename... To, typename... From>
512  struct unique_visitor<variant<To...>, variant<From...>>
513  {
514  variant<To...> * var_;
515 
516  template<typename T, std::size_t N>
517  void operator()(indexed_element<T, N> t) const
518  {
519  using E = meta::at_c<meta::list<From...>, N>;
520  static_assert(RANGES_IS_SAME(T const, E const),
521  "Is indexed_element broken?");
522  using F = meta::find<meta::list<To...>, E>;
523  static constexpr std::size_t M = sizeof...(To) - F::size();
524  compose(emplace_fn<variant<To...>, M>{var_}, get_datum_fn{})(t);
525  }
526  };
527 
528  template<typename T>
529  constexpr T & variant_deref_(T * t) noexcept
530  {
531  return *t;
532  }
533  inline void variant_deref_(void const volatile *) noexcept
534  {}
535 
536  template<typename Variant>
537  struct variant_get
538  {
540  // get
541  template<std::size_t N>
542  friend meta::_t<
543  std::add_lvalue_reference<meta::at_c<meta::as_list<Variant>, N>>>
544  get(Variant & var)
545  {
546  using elem_t = meta::_t<
547  std::remove_reference<meta::at_c<meta::as_list<Variant>, N>>>;
548  elem_t * elem = nullptr;
549  auto & data_var = detail::variant_core_access::data(var);
550  detail::variant_visit_(
551  var.index(), data_var, detail::get_fn<elem_t, N>{&elem});
552  return detail::variant_deref_(elem);
553  }
554  template<std::size_t N>
555  friend meta::_t<
556  std::add_lvalue_reference<meta::at_c<meta::as_list<Variant>, N> const>>
557  get(Variant const & var)
558  {
559  using elem_t = meta::_t<
560  std::remove_reference<meta::at_c<meta::as_list<Variant>, N> const>>;
561  elem_t * elem = nullptr;
562  auto & data_var = detail::variant_core_access::data(var);
563  detail::variant_visit_(
564  var.index(), data_var, detail::get_fn<elem_t, N>{&elem});
565  return detail::variant_deref_(elem);
566  }
567  template<std::size_t N>
568  friend meta::_t<
569  std::add_rvalue_reference<meta::at_c<meta::as_list<Variant>, N>>>
570  get(Variant && var)
571  {
572  using elem_t = meta::_t<
573  std::remove_reference<meta::at_c<meta::as_list<Variant>, N>>>;
574  elem_t * elem = nullptr;
575  auto & data_var = detail::variant_core_access::data(var);
576  detail::variant_visit_(
577  var.index(), data_var, detail::get_fn<elem_t, N>{&elem});
578  using res_t = meta::_t<
579  std::add_rvalue_reference<meta::at_c<meta::as_list<Variant>, N>>>;
580  return static_cast<res_t>(detail::variant_deref_(elem));
581  }
582  };
583 
584  template<typename Variant,
585  bool Trivial = std::is_trivially_destructible<meta::apply<
587  struct variant_base : variant_get<Variant>
588  {
589  ~variant_base()
590  {
591  static_cast<Variant *>(this)->clear_();
592  }
593  };
594  template<typename... Ts>
595  struct variant_base<variant<Ts...>, true> : variant_get<variant<Ts...>>
596  {};
597 
598  template<typename Fun, typename Types, typename Indices, typename = void>
599  struct variant_visit_results
600  {};
601  template<typename Fun, typename... Ts, std::size_t... Is>
602  struct variant_visit_results<
603  Fun, meta::list<Ts...>, meta::index_sequence<Is...>,
604  meta::void_<invoke_result_t<Fun &, indexed_element<Ts, Is>>...>>
605  {
606  using type = variant<invoke_result_t<Fun &, indexed_element<Ts, Is>>...>;
607  };
608  template<typename Fun, typename... Ts>
609  using variant_visit_results_t =
610  meta::_t<variant_visit_results<Fun, meta::list<Ts...>,
611  meta::make_index_sequence<sizeof...(Ts)>>>;
612  } // namespace detail
614 
617  template<typename... Ts>
618  struct variant
619  : private detail::variant_data<Ts...>
620  , private detail::variant_base<variant<Ts...>>
621  {
622  private:
623  friend detail::variant_core_access;
624  template<typename...>
625  friend struct variant;
626  friend detail::variant_base<variant, false>;
627  template<std::size_t Index>
628  using datum_t = detail::variant_datum_t<Index, Ts...>;
629  template<typename T>
630  using add_const_t = meta::if_<std::is_void<T>, void, T const>;
631  using unbox_fn = detail::get_datum_fn;
632 
633  detail::variant_data<Ts...> & data_() & noexcept
634  {
635  return *this;
636  }
637  detail::variant_data<Ts...> const & data_() const & noexcept
638  {
639  return *this;
640  }
641  detail::variant_data<Ts...> && data_() && noexcept
642  {
643  return static_cast<detail::variant_data<Ts...> &&>(*this);
644  }
645 
646  std::size_t index_;
647 
648  void clear_() noexcept
649  {
650  if(valid())
651  {
652  detail::variant_visit_(index_, data_(), detail::delete_fn{}, identity{});
653  index_ = (std::size_t)-1;
654  }
655  }
656  template<typename That>
657  void assign_(That && that)
658  {
659  if(that.valid())
660  index_ = detail::variant_move_copy_(
661  that.index_, data_(), ((That &&) that).data_());
662  }
663  constexpr variant(detail::empty_variant_tag) noexcept
664  : detail::variant_data<Ts...>{}
665  , index_((std::size_t)-1)
666  {}
667  template(typename... Args)(
668  requires (sizeof...(Args) == sizeof...(Ts))) //
669  static constexpr bool all_convertible_to(int) noexcept
670  {
671  return and_v<convertible_to<Args, Ts>...>;
672  }
673  template<typename... Args>
674  static constexpr bool all_convertible_to(long) noexcept
675  {
676  return false;
677  }
678 
679  public:
680  CPP_member
681  constexpr CPP_ctor(variant)()( //
682  noexcept(std::is_nothrow_default_constructible<datum_t<0>>::value) //
683  requires default_constructible<datum_t<0>>)
684  : variant{emplaced_index<0>}
685  {}
686  template(std::size_t N, typename... Args)(
687  requires constructible_from<datum_t<N>, Args...>)
688  constexpr variant(emplaced_index_t<N>, Args &&... args) noexcept(
689  std::is_nothrow_constructible<datum_t<N>, Args...>::value)
690  : detail::variant_data<Ts...>{meta::size_t<N>{}, static_cast<Args &&>(args)...}
691  , index_(N)
692  {}
693  template(std::size_t N, typename T, typename... Args)(
694  requires constructible_from<datum_t<N>, std::initializer_list<T> &,
695  Args...>)
696  constexpr variant(
697  emplaced_index_t<N>, std::initializer_list<T> il,
698  Args &&... args) noexcept(std::
699  is_nothrow_constructible<
700  datum_t<N>, std::initializer_list<T> &,
701  Args...>::value)
702  : detail::variant_data<Ts...>{meta::size_t<N>{},
703  il,
704  static_cast<Args &&>(args)...}
705  , index_(N)
706  {}
707  template(std::size_t N)(
708  requires constructible_from<datum_t<N>, meta::nil_>)
710  noexcept(std::is_nothrow_constructible<datum_t<N>, meta::nil_>::value)
711  : detail::variant_data<Ts...>{meta::size_t<N>{}, meta::nil_{}}
712  , index_(N)
713  {}
714  variant(variant && that)
715  : detail::variant_data<Ts...>{}
716  , index_(detail::variant_move_copy_(that.index(), data_(),
717  std::move(that.data_())))
718  {}
719  variant(variant const & that)
720  : detail::variant_data<Ts...>{}
721  , index_(detail::variant_move_copy_(that.index(), data_(), that.data_()))
722  {}
723  template(typename... Args)(
724  requires (!same_as<variant<Args...>, variant>) AND
725  (all_convertible_to<Args...>(0))) //
727  : detail::variant_data<Ts...>{}
728  , index_(detail::variant_move_copy_(that.index(), data_(),
729  std::move(that.data_())))
730  {}
731  variant & operator=(variant && that)
732  {
733  // TODO do a simple move assign when index()==that.index()
734  this->clear_();
735  this->assign_(detail::move(that));
736  return *this;
737  }
738  variant & operator=(variant const & that)
739  {
740  // TODO do a simple copy assign when index()==that.index()
741  this->clear_();
742  this->assign_(that);
743  return *this;
744  }
745  template(typename... Args)(
746  requires (!same_as<variant<Args...>, variant>) AND
747  (all_convertible_to<Args...>(0)))
748  variant & operator=(variant<Args...> that)
749  {
750  // TODO do a simple copy assign when index()==that.index() //
751  this->clear_();
752  this->assign_(that);
753  return *this;
754  }
755  static constexpr std::size_t size() noexcept
756  {
757  return sizeof...(Ts);
758  }
759  template(std::size_t N, typename... Args)(
760  requires constructible_from<datum_t<N>, Args...>)
761  void emplace(Args &&... args)
762  {
763  this->clear_();
764  detail::construct_fn<N, Args &&...> fn{static_cast<Args &&>(args)...};
765  detail::variant_visit_(N, data_(), std::ref(fn), identity{});
766  index_ = N;
767  }
768  constexpr bool valid() const noexcept
769  {
770  return index() != (std::size_t)-1;
771  }
772  constexpr std::size_t index() const noexcept
773  {
774  return index_;
775  }
776  template<typename Fun>
777  detail::variant_visit_results_t<composed<Fun, unbox_fn>, Ts...> visit(Fun fun)
778  {
779  detail::variant_visit_results_t<composed<Fun, unbox_fn>, Ts...> res{
780  detail::empty_variant_tag{}};
781  detail::variant_visit_(index_,
782  data_(),
783  detail::make_variant_visitor(
784  res, compose(detail::move(fun), unbox_fn{})));
785  return res;
786  }
787  template<typename Fun>
788  detail::variant_visit_results_t<composed<Fun, unbox_fn>, add_const_t<Ts>...>
789  visit(Fun fun) const
790  {
791  detail::variant_visit_results_t<composed<Fun, unbox_fn>, add_const_t<Ts>...>
792  res{detail::empty_variant_tag{}};
793  detail::variant_visit_(index_,
794  data_(),
795  detail::make_variant_visitor(
796  res, compose(detail::move(fun), unbox_fn{})));
797  return res;
798  }
799  template<typename Fun>
800  detail::variant_visit_results_t<Fun, Ts...> visit_i(Fun fun)
801  {
802  detail::variant_visit_results_t<Fun, Ts...> res{detail::empty_variant_tag{}};
803  detail::variant_visit_(
804  index_, data_(), detail::make_variant_visitor(res, detail::move(fun)));
805  return res;
806  }
807  template<typename Fun>
808  detail::variant_visit_results_t<Fun, add_const_t<Ts>...> visit_i(Fun fun) const
809  {
810  detail::variant_visit_results_t<Fun, add_const_t<Ts>...> res{
811  detail::empty_variant_tag{}};
812  detail::variant_visit_(
813  index_, data_(), detail::make_variant_visitor(res, detail::move(fun)));
814  return res;
815  }
816  };
817 
818  template(typename... Ts, typename... Us)(
819  requires and_v<equality_comparable_with<Ts, Us>...>)
820  bool operator==(variant<Ts...> const & lhs, variant<Us...> const & rhs)
821  {
822  return (!lhs.valid() && !rhs.valid()) ||
823  (lhs.index() == rhs.index() &&
824  detail::variant_equal_(lhs.index(),
825  detail::variant_core_access::data(lhs),
826  detail::variant_core_access::data(rhs)));
827  }
828 
829  template(typename... Ts, typename... Us)(
830  requires and_v<equality_comparable_with<Ts, Us>...>)
831  bool operator!=(variant<Ts...> const & lhs, variant<Us...> const & rhs)
832  {
833  return !(lhs == rhs);
834  }
835 
837  // emplace
838  template(std::size_t N, typename... Ts, typename... Args)(
839  requires constructible_from<detail::variant_datum_t<N, Ts...>, Args...>)
840  void emplace(variant<Ts...> & var, Args &&... args)
841  {
842  var.template emplace<N>(static_cast<Args &&>(args)...);
843  }
844 
846  // variant_unique
847  template<typename Var>
849  {};
850 
851  template<typename... Ts>
852  struct variant_unique<variant<Ts...>>
853  {
855  };
856 
857  template<typename Var>
858  using variant_unique_t = meta::_t<variant_unique<Var>>;
859 
861  // unique_variant
862  template<typename... Ts>
863  variant_unique_t<variant<Ts...>> unique_variant(variant<Ts...> const & var)
864  {
865  using From = variant<Ts...>;
866  using To = variant_unique_t<From>;
867  auto res = detail::variant_core_access::make_empty(meta::id<To>{});
868  var.visit_i(detail::unique_visitor<To, From>{&res});
869  RANGES_EXPECT(res.valid());
870  return res;
871  }
873 } // namespace ranges
874 
875 RANGES_DIAGNOSTIC_PUSH
876 RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
877 
878 namespace std
879 {
880  template<typename... Ts>
881  struct tuple_size<::ranges::variant<Ts...>> : tuple_size<tuple<Ts...>>
882  {};
883 
884  template<size_t I, typename... Ts>
885  struct tuple_element<I, ::ranges::variant<Ts...>> : tuple_element<I, tuple<Ts...>>
886  {};
887 } // namespace std
888 
889 RANGES_DIAGNOSTIC_POP
890 
891 #include <range/v3/detail/epilogue.hpp>
892 
893 #endif
CPP_concept type
\concept type
Definition: concepts.hpp:838
_t< detail::make_indices_< N, index_sequence< 0 >, detail::strategy_(1, N)> > make_index_sequence
Generate index_sequence containing integer constants [0,1,2,...,N-1].
Definition: meta.hpp:473
std::integral_constant< std::size_t, N > size_t
An integral constant wrapper for std::size_t.
Definition: meta.hpp:163
typename T::type _t
Type alias for T::type.
Definition: meta.hpp:141
_t< extension::apply< Fn, L > > apply
Applies the invocable Fn using the types in the type list L as arguments.
Definition: meta.hpp:1030
typename Fn::template invoke< Args... > invoke
Evaluate the invocable Fn with the arguments Args.
Definition: meta.hpp:541
_t< detail::at_< L, N > > at_c
Return the N th element in the meta::list L.
Definition: meta.hpp:1962
front< Pair > first
Retrieve the first element of the pair Pair.
Definition: meta.hpp:2251
meta::size_t< L::size()> size
An integral constant wrapper that is the size of the meta::list L.
Definition: meta.hpp:1696
_t< detail::as_list_< detail::uncvref_t< Sequence > >> as_list
Turn a type into an instance of meta::list in a way determined by meta::apply.
Definition: meta.hpp:2961
_t< detail::_if_< list< Args... > >> if_
Select one type or another depending on a compile-time Boolean.
Definition: meta.hpp:1247
drop< L, min< find_index< L, T >, size< L > >> find
Return the tail of the list L starting at the first occurrence of T, if any such element exists; the ...
Definition: meta.hpp:2388
void void_
An alias for void.
Definition: meta.hpp:597
_t< detail::transform_< list< Args... > >> transform
Return a new meta::list constructed by transforming all the elements in L with the unary invocable Fn...
Definition: meta.hpp:1855
fold< L, list<>, quote_trait< detail::insert_back_ > > unique
Return a new meta::list where all duplicate elements have been removed.
Definition: meta.hpp:3157
Tiny meta-programming library.
Tiny metaprogramming library.
Definition: meta.hpp:116
A trait that always returns its argument T.
Definition: meta.hpp:558
A container for a sequence of compile-time integer constants.
Definition: meta.hpp:434
A list of types.
Definition: meta.hpp:1684
An empty type.
Definition: meta.hpp:135
Turn a template C into an invocable.
Definition: meta.hpp:913
Definition: variant.hpp:60
Definition: variant.hpp:46
Definition: identity.hpp:25
Definition: variant.hpp:71
Definition: static_const.hpp:22
Definition: variant.hpp:849
Definition: variant.hpp:621