@@ -379,6 +379,11 @@ concept specialization_of_template_type_and_nttp = requires (X x) {
379
379
template <template <typename ...> class C >
380
380
concept type_trait = std::derived_from<C<int >, std::true_type> || std::derived_from<C<int >, std::false_type>;
381
381
382
+ template <typename X>
383
+ concept boolean_testable = std::convertible_to<X, bool > && requires (X&& x) {
384
+ { !std::forward<X>(x) } -> std::convertible_to<bool >;
385
+ };
386
+
382
387
template <typename X>
383
388
concept polymorphic = std::is_polymorphic_v<std::remove_cvref_t <X>>;
384
389
@@ -484,6 +489,66 @@ struct aligned_storage {
484
489
alignas (Align) unsigned char data[Len];
485
490
};
486
491
492
+ // -----------------------------------------------------------------------
493
+ //
494
+ // A type_find_if for iterating over types in parameter packs
495
+ //
496
+ // Note: the current implementation is a workaround for clang-12 internal error.
497
+ // Original implementation does not need type_it and is implemented
498
+ // using lambda with explicit parameter type list in the following way:
499
+ //
500
+ // template <typename... Ts, typename F>
501
+ // constexpr auto type_find_if(F&& fun)
502
+ // {
503
+ // std::size_t found = std::variant_npos;
504
+ // [&]<std::size_t... Is>(std::index_sequence<Is...>){
505
+ // if constexpr ((requires { {CPP2_FORWARD(fun).template operator()<Is, Ts>()} -> std::convertible_to<bool>;} && ...)) {
506
+ // (((CPP2_FORWARD(fun).template operator()<Is, Ts>()) && (found = Is, true)) || ...);
507
+ // }
508
+ // }(std::index_sequence_for<Ts...>());
509
+ // return found;
510
+ // }
511
+ //
512
+ // The workaround is not needed in gcc-12.1+, clang-13+, msvc 19.29+
513
+ //
514
+ // Note2: the internal if constexpr could have else with static_assert.
515
+ // Unfortunatelly I cannot make it work on MSVC.
516
+ //
517
+ // -----------------------------------------------------------------------
518
+ //
519
+ template <std::size_t Index, typename T>
520
+ struct type_it {
521
+ using type = T;
522
+ inline static const std::size_t index = Index;
523
+ };
524
+
525
+ template <typename ... Ts, typename F>
526
+ constexpr auto type_find_if (F&& fun)
527
+ {
528
+ std::size_t found = std::variant_npos;
529
+ [&]<std::size_t ... Is>(std::index_sequence<Is...>){
530
+ if constexpr ((requires { {CPP2_FORWARD (fun)(type_it<Is, Ts>{})} -> boolean_testable;} && ...)) {
531
+ ((CPP2_FORWARD (fun)(type_it<Is, Ts>{}) && (found = Is, true )) || ...);
532
+ }
533
+ }(std::index_sequence_for<Ts...>());
534
+ return found;
535
+ }
536
+
537
+ template <typename F, template <typename ...> class C , typename ... Ts>
538
+ constexpr auto type_find_if (C<Ts...>, F&& fun)
539
+ {
540
+ return type_find_if<Ts...>(CPP2_FORWARD (fun));
541
+ }
542
+
543
+ template <typename T, typename ... Ts>
544
+ constexpr auto variant_contains_type (std::variant<Ts...>)
545
+ {
546
+ if constexpr (is_any<T, Ts...>) {
547
+ return std::true_type{};
548
+ } else {
549
+ return std::false_type{};
550
+ }
551
+ }
487
552
488
553
// -----------------------------------------------------------------------
489
554
//
@@ -849,6 +914,26 @@ using in =
849
914
>;
850
915
851
916
917
+ template <class T , class U >
918
+ [[nodiscard]] constexpr auto && forward_like(U&& x) noexcept
919
+ {
920
+ constexpr bool is_adding_const = std::is_const_v<std::remove_reference_t <T>>;
921
+ if constexpr (std::is_lvalue_reference_v<T&&>)
922
+ {
923
+ if constexpr (is_adding_const)
924
+ return std::as_const (x);
925
+ else
926
+ return static_cast <U&>(x);
927
+ }
928
+ else
929
+ {
930
+ if constexpr (is_adding_const)
931
+ return std::move (std::as_const (x));
932
+ else
933
+ return std::move (x);
934
+ }
935
+ }
936
+
852
937
// -----------------------------------------------------------------------
853
938
//
854
939
// Initialization: These are closely related...
@@ -1615,104 +1700,79 @@ constexpr auto operator_as( std::variant<Ts...> const& x ) -> decltype(auto) {
1615
1700
}
1616
1701
}
1617
1702
1703
+ // -------------------------------------------------------------------------------------------------------------
1704
+ // forward declarations needed for recursive calls
1705
+ //
1618
1706
1619
- // is Type
1707
+ template <specialization_of_template<std::variant> T, typename C>
1708
+ constexpr auto is ( T&& x, C&& value );
1709
+
1710
+ // std::variant variable is Template
1620
1711
//
1621
- template <typename ... Ts>
1622
- constexpr auto operator_is ( std::variant<Ts...> const & x ) {
1623
- return x.index ();
1712
+
1713
+ template <template <typename ...> class C , specialization_of_template<std::variant> T>
1714
+ requires (!specialization_of_template<T, C>)
1715
+ constexpr auto is ( T&& x ) {
1716
+ return type_find_if (x, [&]<typename It>(It const &) -> bool {
1717
+ if (x.index () == It::index) { return is<C>(forward_like<T>(std::get<It::index>(x)));}
1718
+ return false ;
1719
+ }) != std::variant_npos;
1624
1720
}
1625
1721
1626
- template <typename T, typename ... Ts>
1627
- auto is ( std::variant<Ts...> const & x );
1722
+ template <template <typename ...> class C , typename ... Ts>
1723
+ requires std::same_as<C<Ts...>, std::variant<Ts...>>
1724
+ constexpr auto is ( std::variant<Ts...> const & ) -> std::true_type {
1725
+ return {};
1726
+ }
1628
1727
1728
+ template <template <typename , auto ...> class C , specialization_of_template<std::variant> T>
1729
+ constexpr auto is ( T&& x ) {
1730
+ return type_find_if (x, [&]<typename It>(It const &) -> bool {
1731
+ if (x.index () == It::index) { return is<C>(forward_like<T>(std::get<It::index>(x)));}
1732
+ return false ;
1733
+ }) != std::variant_npos || specialization_of_template_type_and_nttp<T, C>;
1734
+ }
1629
1735
1630
- // is Value
1736
+ // std::variant variable is Value
1631
1737
//
1632
- template <typename ... Ts>
1633
- constexpr auto is ( std::variant<Ts...> const & x, auto && value ) -> bool
1634
- {
1635
- // Predicate case
1636
- if constexpr (requires { bool { value (operator_as< 0 >(x)) }; }) { if (x.index () == 0 ) return value (operator_as< 0 >(x)); }
1637
- else if constexpr (requires { bool { value (operator_as< 1 >(x)) }; }) { if (x.index () == 1 ) return value (operator_as< 1 >(x)); }
1638
- else if constexpr (requires { bool { value (operator_as< 2 >(x)) }; }) { if (x.index () == 2 ) return value (operator_as< 2 >(x)); }
1639
- else if constexpr (requires { bool { value (operator_as< 3 >(x)) }; }) { if (x.index () == 3 ) return value (operator_as< 3 >(x)); }
1640
- else if constexpr (requires { bool { value (operator_as< 4 >(x)) }; }) { if (x.index () == 4 ) return value (operator_as< 4 >(x)); }
1641
- else if constexpr (requires { bool { value (operator_as< 5 >(x)) }; }) { if (x.index () == 5 ) return value (operator_as< 5 >(x)); }
1642
- else if constexpr (requires { bool { value (operator_as< 6 >(x)) }; }) { if (x.index () == 6 ) return value (operator_as< 6 >(x)); }
1643
- else if constexpr (requires { bool { value (operator_as< 7 >(x)) }; }) { if (x.index () == 7 ) return value (operator_as< 7 >(x)); }
1644
- else if constexpr (requires { bool { value (operator_as< 8 >(x)) }; }) { if (x.index () == 8 ) return value (operator_as< 8 >(x)); }
1645
- else if constexpr (requires { bool { value (operator_as< 9 >(x)) }; }) { if (x.index () == 9 ) return value (operator_as< 9 >(x)); }
1646
- else if constexpr (requires { bool { value (operator_as<10 >(x)) }; }) { if (x.index () == 10 ) return value (operator_as<10 >(x)); }
1647
- else if constexpr (requires { bool { value (operator_as<11 >(x)) }; }) { if (x.index () == 11 ) return value (operator_as<11 >(x)); }
1648
- else if constexpr (requires { bool { value (operator_as<12 >(x)) }; }) { if (x.index () == 12 ) return value (operator_as<12 >(x)); }
1649
- else if constexpr (requires { bool { value (operator_as<13 >(x)) }; }) { if (x.index () == 13 ) return value (operator_as<13 >(x)); }
1650
- else if constexpr (requires { bool { value (operator_as<14 >(x)) }; }) { if (x.index () == 14 ) return value (operator_as<14 >(x)); }
1651
- else if constexpr (requires { bool { value (operator_as<15 >(x)) }; }) { if (x.index () == 15 ) return value (operator_as<15 >(x)); }
1652
- else if constexpr (requires { bool { value (operator_as<16 >(x)) }; }) { if (x.index () == 16 ) return value (operator_as<16 >(x)); }
1653
- else if constexpr (requires { bool { value (operator_as<17 >(x)) }; }) { if (x.index () == 17 ) return value (operator_as<17 >(x)); }
1654
- else if constexpr (requires { bool { value (operator_as<18 >(x)) }; }) { if (x.index () == 18 ) return value (operator_as<18 >(x)); }
1655
- else if constexpr (requires { bool { value (operator_as<19 >(x)) }; }) { if (x.index () == 19 ) return value (operator_as<19 >(x)); }
1656
- else if constexpr (std::is_function_v<decltype (value)> || requires { &value.operator (); }) {
1657
- return false ;
1658
- }
1659
1738
1660
- // Value case
1661
- else {
1662
- if constexpr (requires { bool { operator_as< 0 >(x) == value }; }) { if (x.index () == 0 ) return operator_as< 0 >(x) == value; }
1663
- if constexpr (requires { bool { operator_as< 1 >(x) == value }; }) { if (x.index () == 1 ) return operator_as< 1 >(x) == value; }
1664
- if constexpr (requires { bool { operator_as< 2 >(x) == value }; }) { if (x.index () == 2 ) return operator_as< 2 >(x) == value; }
1665
- if constexpr (requires { bool { operator_as< 3 >(x) == value }; }) { if (x.index () == 3 ) return operator_as< 3 >(x) == value; }
1666
- if constexpr (requires { bool { operator_as< 4 >(x) == value }; }) { if (x.index () == 4 ) return operator_as< 4 >(x) == value; }
1667
- if constexpr (requires { bool { operator_as< 5 >(x) == value }; }) { if (x.index () == 5 ) return operator_as< 5 >(x) == value; }
1668
- if constexpr (requires { bool { operator_as< 6 >(x) == value }; }) { if (x.index () == 6 ) return operator_as< 6 >(x) == value; }
1669
- if constexpr (requires { bool { operator_as< 7 >(x) == value }; }) { if (x.index () == 7 ) return operator_as< 7 >(x) == value; }
1670
- if constexpr (requires { bool { operator_as< 8 >(x) == value }; }) { if (x.index () == 8 ) return operator_as< 8 >(x) == value; }
1671
- if constexpr (requires { bool { operator_as< 9 >(x) == value }; }) { if (x.index () == 9 ) return operator_as< 9 >(x) == value; }
1672
- if constexpr (requires { bool { operator_as<10 >(x) == value }; }) { if (x.index () == 10 ) return operator_as<10 >(x) == value; }
1673
- if constexpr (requires { bool { operator_as<11 >(x) == value }; }) { if (x.index () == 11 ) return operator_as<11 >(x) == value; }
1674
- if constexpr (requires { bool { operator_as<12 >(x) == value }; }) { if (x.index () == 12 ) return operator_as<12 >(x) == value; }
1675
- if constexpr (requires { bool { operator_as<13 >(x) == value }; }) { if (x.index () == 13 ) return operator_as<13 >(x) == value; }
1676
- if constexpr (requires { bool { operator_as<14 >(x) == value }; }) { if (x.index () == 14 ) return operator_as<14 >(x) == value; }
1677
- if constexpr (requires { bool { operator_as<15 >(x) == value }; }) { if (x.index () == 15 ) return operator_as<15 >(x) == value; }
1678
- if constexpr (requires { bool { operator_as<16 >(x) == value }; }) { if (x.index () == 16 ) return operator_as<16 >(x) == value; }
1679
- if constexpr (requires { bool { operator_as<17 >(x) == value }; }) { if (x.index () == 17 ) return operator_as<17 >(x) == value; }
1680
- if constexpr (requires { bool { operator_as<18 >(x) == value }; }) { if (x.index () == 18 ) return operator_as<18 >(x) == value; }
1681
- if constexpr (requires { bool { operator_as<19 >(x) == value }; }) { if (x.index () == 19 ) return operator_as<19 >(x) == value; }
1739
+ template <specialization_of_template<std::variant> T, typename C>
1740
+ constexpr auto is ( T&& x, C&& value ) {
1741
+ if constexpr (std::same_as<T,C>) {
1742
+ return x == value;
1743
+ } else {
1744
+ return type_find_if (x, [&]<typename It>(It const &) -> bool {
1745
+ if (x.index () == It::index) { return is (forward_like<T>(std::get<It::index>(x)), std::forward<C>(value));}
1746
+ return false ;
1747
+ }) != std::variant_npos;
1682
1748
}
1683
- return false ;
1684
1749
}
1685
1750
1686
-
1687
- // as
1751
+ // std::variant variable is Type
1688
1752
//
1689
- template <typename T, typename ... Ts>
1690
- auto is ( std::variant<Ts...> const & x ) {
1691
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 0 >(x)), T >) { if (x.index () == 0 ) return true ; }
1692
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 1 >(x)), T >) { if (x.index () == 1 ) return true ; }
1693
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 2 >(x)), T >) { if (x.index () == 2 ) return true ; }
1694
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 3 >(x)), T >) { if (x.index () == 3 ) return true ; }
1695
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 4 >(x)), T >) { if (x.index () == 4 ) return true ; }
1696
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 5 >(x)), T >) { if (x.index () == 5 ) return true ; }
1697
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 6 >(x)), T >) { if (x.index () == 6 ) return true ; }
1698
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 7 >(x)), T >) { if (x.index () == 7 ) return true ; }
1699
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 8 >(x)), T >) { if (x.index () == 8 ) return true ; }
1700
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 9 >(x)), T >) { if (x.index () == 9 ) return true ; }
1701
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<10 >(x)), T >) { if (x.index () == 10 ) return true ; }
1702
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<11 >(x)), T >) { if (x.index () == 11 ) return true ; }
1703
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<12 >(x)), T >) { if (x.index () == 12 ) return true ; }
1704
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<13 >(x)), T >) { if (x.index () == 13 ) return true ; }
1705
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<14 >(x)), T >) { if (x.index () == 14 ) return true ; }
1706
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<15 >(x)), T >) { if (x.index () == 15 ) return true ; }
1707
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<16 >(x)), T >) { if (x.index () == 16 ) return true ; }
1708
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<17 >(x)), T >) { if (x.index () == 17 ) return true ; }
1709
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<18 >(x)), T >) { if (x.index () == 18 ) return true ; }
1710
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<19 >(x)), T >) { if (x.index () == 19 ) return true ; }
1711
- if constexpr (std::is_same_v< T, empty > ) {
1712
- if (x.valueless_by_exception ()) return true ;
1713
- // Need to guard this with is_any otherwise the get_if is illegal
1714
- if constexpr (is_any<std::monostate, Ts...>) return std::get_if<std::monostate>(&x) != nullptr ;
1753
+ template <specialization_of_template<std::variant> T, specialization_of_template<std::variant> C>
1754
+ constexpr auto is ( C&& ) {
1755
+ if constexpr (std::same_as<std::remove_cvref_t <T>, std::remove_cvref_t <C>>) {
1756
+ return std::true_type{};
1757
+ } else {
1758
+ return std::false_type{};
1715
1759
}
1760
+ }
1761
+
1762
+ template <typename C, specialization_of_template<std::variant> T>
1763
+ auto is ( T&& x ) {
1764
+ return type_find_if (x, [&]<typename It>(It const &) -> bool {
1765
+ if (x.index () == It::index) { return is<C>(std::get<It::index>(x));}
1766
+ return false ;
1767
+ }) != std::variant_npos;
1768
+ }
1769
+
1770
+ template <std::same_as<empty> C, specialization_of_template<std::variant> T>
1771
+ auto is ( T&& x ) {
1772
+ if (x.valueless_by_exception ())
1773
+ return true ;
1774
+ if constexpr (requires { {variant_contains_type<std::monostate>(std::declval<T>())} -> std::same_as<std::true_type>; })
1775
+ return std::get_if<std::monostate>(&x) != nullptr ;
1716
1776
return false ;
1717
1777
}
1718
1778
0 commit comments