Horizon
Loading...
Searching...
No Matches
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
29
36
37#include <range/v3/detail/prologue.hpp>
38
39namespace 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>
848 struct variant_unique
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
875RANGES_DIAGNOSTIC_PUSH
876RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
877
878namespace 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
889RANGES_DIAGNOSTIC_POP
890
891#include <range/v3/detail/epilogue.hpp>
892
893#endif
The sized_sentinel_for concept.
_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
_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:621