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 30 #include <range/v3/functional/compose.hpp> 31 #include <range/v3/functional/identity.hpp> 32 #include <range/v3/functional/invoke.hpp> 33 #include <range/v3/iterator/concepts.hpp> 34 #include <range/v3/iterator/traits.hpp> 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> 45 struct emplaced_index_t : meta::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 { bad_variant_accessranges::bad_variant_access61 explicit bad_variant_access(std::string const & what_arg) 62 : std::logic_error(what_arg) 63 {} bad_variant_accessranges::bad_variant_access64 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> 70 struct indexed_element 71 { 72 private: 73 std::add_pointer_t<T> t_; 74 75 public: indexed_elementranges::indexed_element76 constexpr explicit indexed_element(T & t) noexcept 77 : t_(std::addressof(t)) 78 {} getranges::indexed_element79 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: indexed_elementranges::indexed_element91 constexpr explicit indexed_element(T && t) noexcept 92 : t_(std::addressof(t)) 93 {} getranges::indexed_element94 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 { getranges::indexed_element102 void get() const noexcept 103 {} 104 }; 105 106 /// \cond 107 namespace detail 108 { 109 struct indexed_element_fn; 110 111 template(typename I, typename S, typename O)( 112 /// \pre 113 requires (!sized_sentinel_for<S, I>)) // 114 O uninitialized_copy(I first, S last, O out) 115 { 116 for(; first != last; ++first, ++out) 117 ::new((void *)std::addressof(*out)) iter_value_t<O>(*first); 118 return out; 119 } 120 121 template(typename I, typename S, typename O)( 122 /// \pre 123 requires sized_sentinel_for<S, I>) 124 O uninitialized_copy(I first, S last, O out) 125 { 126 return std::uninitialized_copy_n(first, (last - first), out); 127 } 128 129 template<typename I, typename O> 130 O uninitialized_copy(I first, I last, O out) 131 { 132 return std::uninitialized_copy(first, last, out); 133 } 134 135 template<typename T, typename Index> 136 struct indexed_datum 137 { 138 private: 139 template<typename, typename> 140 friend struct indexed_datum; 141 T datum_; 142 143 public: 144 CPP_member CPP_ctorranges::detail::indexed_datum145 constexpr CPP_ctor(indexed_datum)()( // 146 noexcept(std::is_nothrow_default_constructible<T>::value) // 147 requires default_constructible<T>) 148 : datum_{} 149 {} 150 template(typename... Ts)( 151 /// \pre 152 requires constructible_from<T, Ts...> AND (sizeof...(Ts) != 0)) // 153 constexpr indexed_datum(Ts &&... ts) noexcept( 154 std::is_nothrow_constructible<T, Ts...>::value) 155 : datum_(static_cast<Ts &&>(ts)...) 156 {} 157 template(typename U)( 158 /// \pre 159 requires (!same_as<T, U>) AND convertible_to<U, T>) 160 constexpr indexed_datum(indexed_datum<U, Index> that) // 161 noexcept(std::is_nothrow_constructible<T, U>::value) // 162 : datum_(std::move(that.datum_)) 163 {} 164 constexpr auto ref() noexcept 165 { 166 return indexed_element<T, Index::value>{datum_}; 167 } 168 constexpr auto ref() const noexcept 169 { 170 return indexed_element<T const, Index::value>{datum_}; 171 } 172 constexpr T & get() noexcept 173 { 174 return datum_; 175 } 176 constexpr T const & get() const noexcept 177 { 178 return datum_; 179 } 180 }; 181 182 template<typename T, std::size_t N, typename Index> 183 struct indexed_datum<T[N], Index>; 184 185 template<typename T, typename Index> 186 struct indexed_datum<T &, Index> 187 { 188 private: 189 template<typename, typename> 190 friend struct indexed_datum; 191 T * t_; 192 193 public: 194 constexpr indexed_datum(T & t) noexcept 195 : t_(std::addressof(t)) 196 {} 197 constexpr T & get() const noexcept 198 { 199 return *t_; 200 } 201 constexpr auto ref() const noexcept 202 { 203 return indexed_element<T &, Index::value>{*t_}; 204 } 205 }; 206 template<typename T, typename Index> 207 struct indexed_datum<T &&, Index> 208 { 209 private: 210 template<typename, typename> 211 friend struct indexed_datum; 212 T * t_; 213 214 public: 215 constexpr indexed_datum(T && t) noexcept 216 : t_(std::addressof(t)) 217 {} 218 constexpr T && get() const noexcept 219 { 220 return static_cast<T &&>(*t_); 221 } 222 constexpr auto ref() const noexcept 223 { 224 return indexed_element<T &&, Index::value>{static_cast<T &&>(*t_)}; 225 } 226 }; 227 template<typename Index> 228 struct indexed_datum<void, Index> 229 { 230 void get() const noexcept 231 {} 232 constexpr indexed_element<void, Index::value> ref() const noexcept 233 { 234 return {}; 235 } 236 }; 237 238 template<std::size_t Index, typename... Ts> 239 using variant_datum_t = 240 detail::indexed_datum<meta::at_c<meta::list<Ts...>, Index>, 241 meta::size_t<Index>>; 242 243 using variant_nil = indexed_datum<void, meta::npos>; 244 245 template<typename Ts, 246 bool Trivial = meta::apply< 247 meta::quote<meta::and_>, 248 meta::transform<Ts, meta::quote<std::is_trivially_destructible>>>:: 249 type::value> 250 struct variant_data_ 251 { 252 using type = indexed_datum<void, meta::npos>; 253 }; 254 255 template<typename T, typename... Ts> 256 struct variant_data_<meta::list<T, Ts...>, true> 257 { 258 struct type 259 { 260 using head_t = T; 261 using tail_t = meta::_t<variant_data_<meta::list<Ts...>>>; 262 union 263 { 264 head_t head; 265 tail_t tail; 266 }; 267 268 type() noexcept 269 {} 270 template<typename... Args> 271 constexpr type(meta::size_t<0>, Args &&... args) noexcept( 272 std::is_nothrow_constructible<head_t, Args...>::value) 273 : head{((Args &&) args)...} 274 {} 275 template<std::size_t N, typename... Args> 276 constexpr type(meta::size_t<N>, Args &&... args) noexcept( 277 std::is_nothrow_constructible<tail_t, meta::size_t<N - 1>, 278 Args...>::value) 279 : tail{meta::size_t<N - 1>{}, ((Args &&) args)...} 280 {} 281 }; 282 }; 283 284 template<typename T, typename... Ts> 285 struct variant_data_<meta::list<T, Ts...>, false> 286 { 287 struct type 288 { 289 using head_t = T; 290 using tail_t = meta::_t<variant_data_<meta::list<Ts...>>>; 291 union 292 { 293 head_t head; 294 tail_t tail; 295 }; 296 297 type() noexcept 298 {} 299 ~type() 300 {} 301 template<typename... Args> 302 constexpr type(meta::size_t<0>, Args &&... args) noexcept( 303 std::is_nothrow_constructible<head_t, Args...>::value) 304 : head{((Args &&) args)...} 305 {} 306 template<std::size_t N, typename... Args> 307 constexpr type(meta::size_t<N>, Args &&... args) noexcept( 308 std::is_nothrow_constructible<tail_t, meta::size_t<N - 1>, 309 Args...>::value) 310 : tail{meta::size_t<N - 1>{}, ((Args &&) args)...} 311 {} 312 }; 313 }; 314 315 template<typename... Ts> 316 using variant_data = meta::_t<variant_data_<meta::transform< 317 meta::list<Ts...>, meta::as_list<meta::make_index_sequence<sizeof...(Ts)>>, 318 meta::quote<indexed_datum>>>>; 319 320 inline std::size_t variant_move_copy_(std::size_t, variant_nil, variant_nil) 321 { 322 return 0; 323 } 324 template<typename Data0, typename Data1> 325 std::size_t variant_move_copy_(std::size_t n, Data0 & self, Data1 && that) 326 { 327 using Head = typename Data0::head_t; 328 return 0 == n 329 ? ((void)::new((void *)&self.head) Head(((Data1 &&) that).head), 0) 330 : variant_move_copy_(n - 1, self.tail, ((Data1 &&) that).tail) + 1; 331 } 332 constexpr bool variant_equal_(std::size_t, variant_nil, variant_nil) 333 { 334 return true; 335 } 336 template<typename Data0, typename Data1> 337 constexpr bool variant_equal_(std::size_t n, Data0 const & self, 338 Data1 const & that) 339 { 340 return n == 0 ? self.head.get() == that.head.get() 341 : variant_equal_(n - 1, self.tail, that.tail); 342 } 343 template<typename Fun, typename Proj = indexed_element_fn> 344 constexpr int variant_visit_(std::size_t, variant_nil, Fun, Proj = {}) 345 { 346 return (RANGES_EXPECT(false), 0); 347 } 348 template<typename Data, typename Fun, typename Proj = indexed_element_fn> 349 constexpr int variant_visit_(std::size_t n, Data & self, Fun fun, Proj proj = {}) 350 { 351 return 0 == n ? ((void)invoke(fun, invoke(proj, self.head)), 0) 352 : detail::variant_visit_( 353 n - 1, self.tail, detail::move(fun), detail::move(proj)); 354 } 355 356 struct get_datum_fn 357 { 358 template<typename T> 359 decltype(auto) operator()(T && t) const noexcept 360 { 361 return t.get(); 362 } 363 }; 364 365 struct indexed_element_fn 366 { 367 template<typename T> 368 decltype(auto) operator()(T && t) const noexcept 369 { 370 return t.ref(); 371 } 372 }; 373 374 struct empty_variant_tag 375 {}; 376 377 struct variant_core_access 378 { 379 template<typename... Ts> 380 static constexpr variant_data<Ts...> & data(variant<Ts...> & var) noexcept 381 { 382 return var.data_(); 383 } 384 template<typename... Ts> 385 static constexpr variant_data<Ts...> const & data( 386 variant<Ts...> const & var) noexcept 387 { 388 return var.data_(); 389 } 390 template<typename... Ts> 391 static constexpr variant_data<Ts...> && data(variant<Ts...> && var) noexcept 392 { 393 return detail::move(var.data_()); 394 } 395 template<typename... Ts> 396 static variant<Ts...> make_empty(meta::id<variant<Ts...>> = {}) noexcept 397 { 398 return variant<Ts...>{empty_variant_tag{}}; 399 } 400 }; 401 402 struct delete_fn 403 { 404 template<typename T> 405 void operator()(T const & t) const noexcept 406 { 407 t.~T(); 408 } 409 }; 410 411 template<std::size_t N, typename... Ts> 412 struct construct_fn 413 { 414 std::tuple<Ts...> args_; 415 416 template<typename U, std::size_t... Is> 417 void construct_(U & u, meta::index_sequence<Is...>) noexcept( 418 std::is_nothrow_constructible<U, Ts...>::value) 419 { 420 ::new((void *)std::addressof(u)) 421 U(static_cast<Ts &&>(std::get<Is>(args_))...); 422 } 423 424 construct_fn(Ts &&... ts) noexcept( 425 std::is_nothrow_constructible<std::tuple<Ts...>, Ts...>::value) 426 : args_{static_cast<Ts &&>(ts)...} 427 {} 428 template<typename U, std::size_t M> 429 [[noreturn]] meta::if_c<N != M> operator()( 430 indexed_datum<U, meta::size_t<M>> &) noexcept 431 { 432 RANGES_EXPECT(false); 433 } 434 template<typename U> 435 meta::if_<std::is_object<U>> operator()( 436 indexed_datum<U, meta::size_t<N>> & 437 u) noexcept(std::is_nothrow_constructible<U, Ts...>::value) 438 { 439 this->construct_(u.get(), meta::make_index_sequence<sizeof...(Ts)>{}); 440 } 441 template<typename U> 442 meta::if_<meta::not_<std::is_object<U>>> operator()( 443 indexed_datum<U, meta::size_t<N>> & 444 u) noexcept(std::is_nothrow_constructible<detail::decay_t<U>, 445 Ts...>::value) 446 { 447 this->construct_(u, meta::make_index_sequence<sizeof...(Ts)>{}); 448 } 449 }; 450 451 template<typename T, std::size_t N> 452 struct get_fn 453 { 454 T ** t_; 455 456 template<typename U, std::size_t M> 457 [[noreturn]] meta::if_c<M != N> operator()(indexed_element<U, M>) const 458 { 459 throw bad_variant_access("bad variant access"); 460 } 461 template<typename U> 462 void operator()(indexed_element<U, N> t) const noexcept 463 { 464 *t_ = std::addressof(t.get()); 465 } 466 template<typename U> 467 void operator()(indexed_element<U &&, N> t) const noexcept 468 { 469 U && u = t.get(); 470 *t_ = std::addressof(u); 471 } 472 void operator()(indexed_element<void, N>) const noexcept 473 {} 474 }; 475 476 template<typename Variant, std::size_t N> 477 struct emplace_fn 478 { 479 Variant * var_; 480 // clang-format off 481 template<typename...Ts> 482 auto CPP_auto_fun(operator())(Ts &&...ts) (const) 483 ( 484 return var_->template emplace<N>(static_cast<Ts &&>(ts)...) 485 ) 486 // clang-format on 487 }; 488 489 template<typename Fun, typename Variant> 490 struct variant_visitor 491 { 492 Fun fun_; 493 Variant * var_; 494 495 // clang-format off 496 template<typename U, std::size_t N> 497 auto CPP_auto_fun(operator())(indexed_element<U, N> u) 498 ( 499 return compose(emplace_fn<Variant, N>{var_}, fun_)(u) 500 ) 501 // clang-format on 502 }; 503 504 template<typename Variant, typename Fun> 505 variant_visitor<Fun, Variant> make_variant_visitor( 506 Variant & var, 507 Fun fun) noexcept(std::is_nothrow_move_constructible<Fun>::value) 508 { 509 return {detail::move(fun), &var}; 510 } 511 512 template<typename To, typename From> 513 struct unique_visitor; 514 515 template<typename... To, typename... From> 516 struct unique_visitor<variant<To...>, variant<From...>> 517 { 518 variant<To...> * var_; 519 520 template<typename T, std::size_t N> 521 void operator()(indexed_element<T, N> t) const 522 { 523 using E = meta::at_c<meta::list<From...>, N>; 524 static_assert(RANGES_IS_SAME(T const, E const), 525 "Is indexed_element broken?"); 526 using F = meta::find<meta::list<To...>, E>; 527 static constexpr std::size_t M = sizeof...(To) - F::size(); 528 compose(emplace_fn<variant<To...>, M>{var_}, get_datum_fn{})(t); 529 } 530 }; 531 532 template<typename T> 533 constexpr T & variant_deref_(T * t) noexcept 534 { 535 return *t; 536 } 537 inline void variant_deref_(void const volatile *) noexcept 538 {} 539 540 template<typename Variant> 541 struct variant_get 542 { 543 ////////////////////////////////////////////////////////////////////////////// 544 // get 545 template<std::size_t N> 546 friend meta::_t< 547 std::add_lvalue_reference<meta::at_c<meta::as_list<Variant>, N>>> 548 get(Variant & var) 549 { 550 using elem_t = meta::_t< 551 std::remove_reference<meta::at_c<meta::as_list<Variant>, N>>>; 552 elem_t * elem = nullptr; 553 auto & data_var = detail::variant_core_access::data(var); 554 detail::variant_visit_( 555 var.index(), data_var, detail::get_fn<elem_t, N>{&elem}); 556 return detail::variant_deref_(elem); 557 } 558 template<std::size_t N> 559 friend meta::_t< 560 std::add_lvalue_reference<meta::at_c<meta::as_list<Variant>, N> const>> 561 get(Variant const & var) 562 { 563 using elem_t = meta::_t< 564 std::remove_reference<meta::at_c<meta::as_list<Variant>, N> const>>; 565 elem_t * elem = nullptr; 566 auto & data_var = detail::variant_core_access::data(var); 567 detail::variant_visit_( 568 var.index(), data_var, detail::get_fn<elem_t, N>{&elem}); 569 return detail::variant_deref_(elem); 570 } 571 template<std::size_t N> 572 friend meta::_t< 573 std::add_rvalue_reference<meta::at_c<meta::as_list<Variant>, N>>> 574 get(Variant && var) 575 { 576 using elem_t = meta::_t< 577 std::remove_reference<meta::at_c<meta::as_list<Variant>, N>>>; 578 elem_t * elem = nullptr; 579 auto & data_var = detail::variant_core_access::data(var); 580 detail::variant_visit_( 581 var.index(), data_var, detail::get_fn<elem_t, N>{&elem}); 582 using res_t = meta::_t< 583 std::add_rvalue_reference<meta::at_c<meta::as_list<Variant>, N>>>; 584 return static_cast<res_t>(detail::variant_deref_(elem)); 585 } 586 }; 587 588 template<typename Variant, 589 bool Trivial = std::is_trivially_destructible<meta::apply< 590 meta::quote<variant_data>, meta::as_list<Variant>>>::value> 591 struct variant_base : variant_get<Variant> 592 { 593 ~variant_base() 594 { 595 static_cast<Variant *>(this)->clear_(); 596 } 597 }; 598 template<typename... Ts> 599 struct variant_base<variant<Ts...>, true> : variant_get<variant<Ts...>> 600 {}; 601 602 template<typename Fun, typename Types, typename Indices, typename = void> 603 struct variant_visit_results 604 {}; 605 template<typename Fun, typename... Ts, std::size_t... Is> 606 struct variant_visit_results< 607 Fun, meta::list<Ts...>, meta::index_sequence<Is...>, 608 meta::void_<invoke_result_t<Fun &, indexed_element<Ts, Is>>...>> 609 { 610 using type = variant<invoke_result_t<Fun &, indexed_element<Ts, Is>>...>; 611 }; 612 template<typename Fun, typename... Ts> 613 using variant_visit_results_t = 614 meta::_t<variant_visit_results<Fun, meta::list<Ts...>, 615 meta::make_index_sequence<sizeof...(Ts)>>>; 616 } // namespace detail 617 /// \endcond 618 619 /// \addtogroup group-utility 620 /// @{ 621 template<typename... Ts> 622 struct variant 623 : private detail::variant_data<Ts...> 624 , private detail::variant_base<variant<Ts...>> 625 { 626 private: 627 friend detail::variant_core_access; 628 template<typename...> 629 friend struct variant; 630 friend detail::variant_base<variant, false>; 631 template<std::size_t Index> 632 using datum_t = detail::variant_datum_t<Index, Ts...>; 633 template<typename T> 634 using add_const_t = meta::if_<std::is_void<T>, void, T const>; 635 using unbox_fn = detail::get_datum_fn; 636 637 detail::variant_data<Ts...> & data_() & noexcept 638 { 639 return *this; 640 } 641 detail::variant_data<Ts...> const & data_() const & noexcept 642 { 643 return *this; 644 } 645 detail::variant_data<Ts...> && data_() && noexcept 646 { 647 return static_cast<detail::variant_data<Ts...> &&>(*this); 648 } 649 650 std::size_t index_; 651 652 void clear_() noexcept 653 { 654 if(valid()) 655 { 656 detail::variant_visit_(index_, data_(), detail::delete_fn{}, identity{}); 657 index_ = (std::size_t)-1; 658 } 659 } 660 template<typename That> 661 void assign_(That && that) 662 { 663 if(that.valid()) 664 index_ = detail::variant_move_copy_( 665 that.index_, data_(), ((That &&) that).data_()); 666 } 667 constexpr variant(detail::empty_variant_tag) noexcept 668 : detail::variant_data<Ts...>{} 669 , index_((std::size_t)-1) 670 {} 671 template(typename... Args)( 672 /// \pre 673 requires (sizeof...(Args) == sizeof...(Ts))) // 674 static constexpr bool all_convertible_to(int) noexcept 675 { 676 return and_v<convertible_to<Args, Ts>...>; 677 } 678 template<typename... Args> 679 static constexpr bool all_convertible_to(long) noexcept 680 { 681 return false; 682 } 683 684 public: 685 CPP_member 686 constexpr CPP_ctor(variant)()( // 687 noexcept(std::is_nothrow_default_constructible<datum_t<0>>::value) // 688 requires default_constructible<datum_t<0>>) 689 : variant{emplaced_index<0>} 690 {} 691 template(std::size_t N, typename... Args)( 692 /// \pre 693 requires constructible_from<datum_t<N>, Args...>) 694 constexpr variant(emplaced_index_t<N>, Args &&... args) noexcept( 695 std::is_nothrow_constructible<datum_t<N>, Args...>::value) 696 : detail::variant_data<Ts...>{meta::size_t<N>{}, static_cast<Args &&>(args)...} 697 , index_(N) 698 {} 699 template(std::size_t N, typename T, typename... Args)( 700 /// \pre 701 requires constructible_from<datum_t<N>, std::initializer_list<T> &, 702 Args...>) 703 constexpr variant( 704 emplaced_index_t<N>, std::initializer_list<T> il, 705 Args &&... args) noexcept(std:: 706 is_nothrow_constructible< 707 datum_t<N>, std::initializer_list<T> &, 708 Args...>::value) 709 : detail::variant_data<Ts...>{meta::size_t<N>{}, 710 il, 711 static_cast<Args &&>(args)...} 712 , index_(N) 713 {} 714 template(std::size_t N)( 715 /// \pre 716 requires constructible_from<datum_t<N>, meta::nil_>) 717 constexpr variant(emplaced_index_t<N>, meta::nil_) 718 noexcept(std::is_nothrow_constructible<datum_t<N>, meta::nil_>::value) 719 : detail::variant_data<Ts...>{meta::size_t<N>{}, meta::nil_{}} 720 , index_(N) 721 {} 722 variant(variant && that) 723 : detail::variant_data<Ts...>{} 724 , index_(detail::variant_move_copy_(that.index(), data_(), 725 std::move(that.data_()))) 726 {} 727 variant(variant const & that) 728 : detail::variant_data<Ts...>{} 729 , index_(detail::variant_move_copy_(that.index(), data_(), that.data_())) 730 {} 731 template(typename... Args)( 732 /// \pre 733 requires (!same_as<variant<Args...>, variant>) AND 734 (all_convertible_to<Args...>(0))) // 735 variant(variant<Args...> that) 736 : detail::variant_data<Ts...>{} 737 , index_(detail::variant_move_copy_(that.index(), data_(), 738 std::move(that.data_()))) 739 {} 740 variant & operator=(variant && that) 741 { 742 // TODO do a simple move assign when index()==that.index() 743 this->clear_(); 744 this->assign_(detail::move(that)); 745 return *this; 746 } 747 variant & operator=(variant const & that) 748 { 749 // TODO do a simple copy assign when index()==that.index() 750 this->clear_(); 751 this->assign_(that); 752 return *this; 753 } 754 template(typename... Args)( 755 /// \pre 756 requires (!same_as<variant<Args...>, variant>) AND 757 (all_convertible_to<Args...>(0))) 758 variant & operator=(variant<Args...> that) 759 { 760 // TODO do a simple copy assign when index()==that.index() // 761 this->clear_(); 762 this->assign_(that); 763 return *this; 764 } 765 static constexpr std::size_t size() noexcept 766 { 767 return sizeof...(Ts); 768 } 769 template(std::size_t N, typename... Args)( 770 /// \pre 771 requires constructible_from<datum_t<N>, Args...>) 772 void emplace(Args &&... args) 773 { 774 this->clear_(); 775 detail::construct_fn<N, Args &&...> fn{static_cast<Args &&>(args)...}; 776 detail::variant_visit_(N, data_(), std::ref(fn), identity{}); 777 index_ = N; 778 } 779 constexpr bool valid() const noexcept 780 { 781 return index() != (std::size_t)-1; 782 } 783 constexpr std::size_t index() const noexcept 784 { 785 return index_; 786 } 787 template<typename Fun> 788 detail::variant_visit_results_t<composed<Fun, unbox_fn>, Ts...> visit(Fun fun) 789 { 790 detail::variant_visit_results_t<composed<Fun, unbox_fn>, Ts...> res{ 791 detail::empty_variant_tag{}}; 792 detail::variant_visit_(index_, 793 data_(), 794 detail::make_variant_visitor( 795 res, compose(detail::move(fun), unbox_fn{}))); 796 return res; 797 } 798 template<typename Fun> 799 detail::variant_visit_results_t<composed<Fun, unbox_fn>, add_const_t<Ts>...> 800 visit(Fun fun) const 801 { 802 detail::variant_visit_results_t<composed<Fun, unbox_fn>, add_const_t<Ts>...> 803 res{detail::empty_variant_tag{}}; 804 detail::variant_visit_(index_, 805 data_(), 806 detail::make_variant_visitor( 807 res, compose(detail::move(fun), unbox_fn{}))); 808 return res; 809 } 810 template<typename Fun> 811 detail::variant_visit_results_t<Fun, Ts...> visit_i(Fun fun) 812 { 813 detail::variant_visit_results_t<Fun, Ts...> res{detail::empty_variant_tag{}}; 814 detail::variant_visit_( 815 index_, data_(), detail::make_variant_visitor(res, detail::move(fun))); 816 return res; 817 } 818 template<typename Fun> 819 detail::variant_visit_results_t<Fun, add_const_t<Ts>...> visit_i(Fun fun) const 820 { 821 detail::variant_visit_results_t<Fun, add_const_t<Ts>...> res{ 822 detail::empty_variant_tag{}}; 823 detail::variant_visit_( 824 index_, data_(), detail::make_variant_visitor(res, detail::move(fun))); 825 return res; 826 } 827 }; 828 829 template(typename... Ts, typename... Us)( 830 /// \pre 831 requires and_v<equality_comparable_with<Ts, Us>...>) 832 bool operator==(variant<Ts...> const & lhs, variant<Us...> const & rhs) 833 { 834 return (!lhs.valid() && !rhs.valid()) || 835 (lhs.index() == rhs.index() && 836 detail::variant_equal_(lhs.index(), 837 detail::variant_core_access::data(lhs), 838 detail::variant_core_access::data(rhs))); 839 } 840 841 template(typename... Ts, typename... Us)( 842 /// \pre 843 requires and_v<equality_comparable_with<Ts, Us>...>) 844 bool operator!=(variant<Ts...> const & lhs, variant<Us...> const & rhs) 845 { 846 return !(lhs == rhs); 847 } 848 849 ////////////////////////////////////////////////////////////////////////////////////// 850 // emplace 851 template(std::size_t N, typename... Ts, typename... Args)( 852 /// \pre 853 requires constructible_from<detail::variant_datum_t<N, Ts...>, Args...>) 854 void emplace(variant<Ts...> & var, Args &&... args) 855 { 856 var.template emplace<N>(static_cast<Args &&>(args)...); 857 } 858 859 ////////////////////////////////////////////////////////////////////////////////////// 860 // variant_unique 861 template<typename Var> 862 struct variant_unique 863 {}; 864 865 template<typename... Ts> 866 struct variant_unique<variant<Ts...>> 867 { 868 using type = meta::apply<meta::quote<variant>, meta::unique<meta::list<Ts...>>>; 869 }; 870 871 template<typename Var> 872 using variant_unique_t = meta::_t<variant_unique<Var>>; 873 874 ////////////////////////////////////////////////////////////////////////////////////// 875 // unique_variant 876 template<typename... Ts> 877 variant_unique_t<variant<Ts...>> unique_variant(variant<Ts...> const & var) 878 { 879 using From = variant<Ts...>; 880 using To = variant_unique_t<From>; 881 auto res = detail::variant_core_access::make_empty(meta::id<To>{}); 882 var.visit_i(detail::unique_visitor<To, From>{&res}); 883 RANGES_EXPECT(res.valid()); 884 return res; 885 } 886 /// @} 887 } // namespace ranges 888 889 RANGES_DIAGNOSTIC_PUSH 890 RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS 891 892 namespace std 893 { 894 template<typename... Ts> 895 struct tuple_size<::ranges::variant<Ts...>> : tuple_size<tuple<Ts...>> 896 {}; 897 898 template<size_t I, typename... Ts> 899 struct tuple_element<I, ::ranges::variant<Ts...>> : tuple_element<I, tuple<Ts...>> 900 {}; 901 } // namespace std 902 903 RANGES_DIAGNOSTIC_POP 904 905 #include <range/v3/detail/epilogue.hpp> 906 907 #endif 908