@@ -655,6 +655,11 @@ concept specialization_of_template_type_and_nttp = requires (X x) {
655
655
{ specialization_of_template_helper<C>(std::forward<X>(x)) } -> std::same_as<std::true_type>;
656
656
};
657
657
658
+ template <typename X>
659
+ concept boolean_testable = std::convertible_to<X, bool > && requires (X&& x) {
660
+ { !std::forward<X>(x) } -> std::convertible_to<bool >;
661
+ };
662
+
658
663
template <typename X>
659
664
concept dereferencable = requires (X x) { *x; };
660
665
@@ -738,6 +743,67 @@ auto pointer_eq(T const* a, T const* b) {
738
743
return std::compare_three_way{}(a, b) == std::strong_ordering::equal;
739
744
}
740
745
746
+ // -----------------------------------------------------------------------
747
+ //
748
+ // A type_find_if for iterating over types in parameter packs
749
+ //
750
+ // Note: the current implementation is a workaround for clang-12 internal error.
751
+ // Original implementation does not need type_it and is implemented
752
+ // using lambda with explicit parameter type list in the following way:
753
+ //
754
+ // template <typename... Ts, typename F>
755
+ // constexpr auto type_find_if(F&& fun)
756
+ // {
757
+ // std::size_t found = std::variant_npos;
758
+ // [&]<std::size_t... Is>(std::index_sequence<Is...>){
759
+ // if constexpr ((requires { {CPP2_FORWARD(fun).template operator()<Is, Ts>()} -> std::convertible_to<bool>;} && ...)) {
760
+ // (((CPP2_FORWARD(fun).template operator()<Is, Ts>()) && (found = Is, true)) || ...);
761
+ // }
762
+ // }(std::index_sequence_for<Ts...>());
763
+ // return found;
764
+ // }
765
+ //
766
+ // The workaround is not needed in gcc-12.1+, clang-13+, msvc 19.29+
767
+ //
768
+ // Note2: the internal if constexpr could have else with static_assert.
769
+ // Unfortunatelly I cannot make it work on MSVC.
770
+ //
771
+ // -----------------------------------------------------------------------
772
+ //
773
+ template <std::size_t Index, typename T>
774
+ struct type_it {
775
+ using type = T;
776
+ inline static const std::size_t index = Index;
777
+ };
778
+
779
+ template <typename ... Ts, typename F>
780
+ constexpr auto type_find_if (F&& fun)
781
+ {
782
+ std::size_t found = std::variant_npos;
783
+ [&]<std::size_t ... Is>(std::index_sequence<Is...>){
784
+ if constexpr ((requires { {CPP2_FORWARD (fun)(type_it<Is, Ts>{})} -> boolean_testable;} && ...)) {
785
+ ((CPP2_FORWARD (fun)(type_it<Is, Ts>{}) && (found = Is, true )) || ...);
786
+ }
787
+ }(std::index_sequence_for<Ts...>());
788
+ return found;
789
+ }
790
+
791
+ template <typename F, template <typename ...> class C , typename ... Ts>
792
+ constexpr auto type_find_if (C<Ts...> const &, F&& fun)
793
+ {
794
+ return type_find_if<Ts...>(CPP2_FORWARD (fun));
795
+ }
796
+
797
+ template <typename T, typename ... Ts>
798
+ constexpr auto variant_contains_type (std::variant<Ts...>)
799
+ {
800
+ if constexpr (is_any<T, Ts...>) {
801
+ return std::true_type{};
802
+ } else {
803
+ return std::false_type{};
804
+ }
805
+ }
806
+
741
807
742
808
// -----------------------------------------------------------------------
743
809
//
@@ -1650,6 +1716,28 @@ constexpr auto is( X const& x ) -> auto {
1650
1716
{
1651
1717
return Dynamic_cast<C const *>(&x) != nullptr ;
1652
1718
}
1719
+ else if constexpr (
1720
+ specialization_of_template<X, std::variant>
1721
+ )
1722
+ {
1723
+ if (x.valueless_by_exception ()) {
1724
+ return std::is_same_v<C, empty>;
1725
+ }
1726
+ if constexpr (
1727
+ std::is_same_v<C, empty>
1728
+ )
1729
+ {
1730
+ if constexpr (requires { {variant_contains_type<std::monostate>(std::declval<X>())} -> std::same_as<std::true_type>; }) {
1731
+ return std::get_if<std::monostate>(&x) != nullptr ;
1732
+ }
1733
+ }
1734
+ return type_find_if (x, [&]<typename It>(It const &) -> bool {
1735
+ if constexpr (It::index < 20 ) {
1736
+ if (x.index () == It::index) { return std::is_same_v<C, std::variant_alternative_t <It::index, X>>;}
1737
+ }
1738
+ return false ;
1739
+ }) != std::variant_npos;
1740
+ }
1653
1741
else if constexpr (
1654
1742
(
1655
1743
std::is_same_v<X, std::nullptr_t >
@@ -1700,6 +1788,20 @@ inline constexpr auto is( auto const& x, auto&& value ) -> bool
1700
1788
else if constexpr (requires { bool {x == value}; }) {
1701
1789
return x == value;
1702
1790
}
1791
+ else if constexpr (specialization_of_template<decltype (x), std::variant> ) {
1792
+ return type_find_if (x, [&]<typename It>(It const &) -> bool {
1793
+ if constexpr (It::index < 20 ) { // TODO: remove after refactor
1794
+ if (x.index () == It::index) {
1795
+ if constexpr (valid_predicate<decltype (value), decltype (std::get<It::index>(x))>) {
1796
+ return value (std::get<It::index>(x));
1797
+ } else if constexpr ( requires { bool {std::get<It::index>(x) == value}; } ) {
1798
+ return std::get<It::index>(x) == value;
1799
+ }
1800
+ }
1801
+ }
1802
+ return false ;
1803
+ }) != std::variant_npos;
1804
+ }
1703
1805
return false ;
1704
1806
}
1705
1807
@@ -1919,106 +2021,6 @@ constexpr auto operator_as( std::variant<Ts...> const& x ) -> decltype(auto) {
1919
2021
}
1920
2022
1921
2023
1922
- // is Type
1923
- //
1924
- template <typename ... Ts>
1925
- constexpr auto operator_is ( std::variant<Ts...> const & x ) {
1926
- return x.index ();
1927
- }
1928
-
1929
- template <typename T, typename ... Ts>
1930
- auto is ( std::variant<Ts...> const & x );
1931
-
1932
-
1933
- // is Value
1934
- //
1935
- template <typename ... Ts>
1936
- constexpr auto is ( std::variant<Ts...> const & x, auto && value ) -> bool
1937
- {
1938
- // Predicate case
1939
- if constexpr (requires { bool { value (operator_as< 0 >(x)) }; }) { if (x.index () == 0 ) return value (operator_as< 0 >(x)); }
1940
- else if constexpr (requires { bool { value (operator_as< 1 >(x)) }; }) { if (x.index () == 1 ) return value (operator_as< 1 >(x)); }
1941
- else if constexpr (requires { bool { value (operator_as< 2 >(x)) }; }) { if (x.index () == 2 ) return value (operator_as< 2 >(x)); }
1942
- else if constexpr (requires { bool { value (operator_as< 3 >(x)) }; }) { if (x.index () == 3 ) return value (operator_as< 3 >(x)); }
1943
- else if constexpr (requires { bool { value (operator_as< 4 >(x)) }; }) { if (x.index () == 4 ) return value (operator_as< 4 >(x)); }
1944
- else if constexpr (requires { bool { value (operator_as< 5 >(x)) }; }) { if (x.index () == 5 ) return value (operator_as< 5 >(x)); }
1945
- else if constexpr (requires { bool { value (operator_as< 6 >(x)) }; }) { if (x.index () == 6 ) return value (operator_as< 6 >(x)); }
1946
- else if constexpr (requires { bool { value (operator_as< 7 >(x)) }; }) { if (x.index () == 7 ) return value (operator_as< 7 >(x)); }
1947
- else if constexpr (requires { bool { value (operator_as< 8 >(x)) }; }) { if (x.index () == 8 ) return value (operator_as< 8 >(x)); }
1948
- else if constexpr (requires { bool { value (operator_as< 9 >(x)) }; }) { if (x.index () == 9 ) return value (operator_as< 9 >(x)); }
1949
- else if constexpr (requires { bool { value (operator_as<10 >(x)) }; }) { if (x.index () == 10 ) return value (operator_as<10 >(x)); }
1950
- else if constexpr (requires { bool { value (operator_as<11 >(x)) }; }) { if (x.index () == 11 ) return value (operator_as<11 >(x)); }
1951
- else if constexpr (requires { bool { value (operator_as<12 >(x)) }; }) { if (x.index () == 12 ) return value (operator_as<12 >(x)); }
1952
- else if constexpr (requires { bool { value (operator_as<13 >(x)) }; }) { if (x.index () == 13 ) return value (operator_as<13 >(x)); }
1953
- else if constexpr (requires { bool { value (operator_as<14 >(x)) }; }) { if (x.index () == 14 ) return value (operator_as<14 >(x)); }
1954
- else if constexpr (requires { bool { value (operator_as<15 >(x)) }; }) { if (x.index () == 15 ) return value (operator_as<15 >(x)); }
1955
- else if constexpr (requires { bool { value (operator_as<16 >(x)) }; }) { if (x.index () == 16 ) return value (operator_as<16 >(x)); }
1956
- else if constexpr (requires { bool { value (operator_as<17 >(x)) }; }) { if (x.index () == 17 ) return value (operator_as<17 >(x)); }
1957
- else if constexpr (requires { bool { value (operator_as<18 >(x)) }; }) { if (x.index () == 18 ) return value (operator_as<18 >(x)); }
1958
- else if constexpr (requires { bool { value (operator_as<19 >(x)) }; }) { if (x.index () == 19 ) return value (operator_as<19 >(x)); }
1959
- else if constexpr (std::is_function_v<decltype (value)> || requires { &value.operator (); }) {
1960
- return false ;
1961
- }
1962
-
1963
- // Value case
1964
- else {
1965
- if constexpr (requires { bool { operator_as< 0 >(x) == value }; }) { if (x.index () == 0 ) return operator_as< 0 >(x) == value; }
1966
- if constexpr (requires { bool { operator_as< 1 >(x) == value }; }) { if (x.index () == 1 ) return operator_as< 1 >(x) == value; }
1967
- if constexpr (requires { bool { operator_as< 2 >(x) == value }; }) { if (x.index () == 2 ) return operator_as< 2 >(x) == value; }
1968
- if constexpr (requires { bool { operator_as< 3 >(x) == value }; }) { if (x.index () == 3 ) return operator_as< 3 >(x) == value; }
1969
- if constexpr (requires { bool { operator_as< 4 >(x) == value }; }) { if (x.index () == 4 ) return operator_as< 4 >(x) == value; }
1970
- if constexpr (requires { bool { operator_as< 5 >(x) == value }; }) { if (x.index () == 5 ) return operator_as< 5 >(x) == value; }
1971
- if constexpr (requires { bool { operator_as< 6 >(x) == value }; }) { if (x.index () == 6 ) return operator_as< 6 >(x) == value; }
1972
- if constexpr (requires { bool { operator_as< 7 >(x) == value }; }) { if (x.index () == 7 ) return operator_as< 7 >(x) == value; }
1973
- if constexpr (requires { bool { operator_as< 8 >(x) == value }; }) { if (x.index () == 8 ) return operator_as< 8 >(x) == value; }
1974
- if constexpr (requires { bool { operator_as< 9 >(x) == value }; }) { if (x.index () == 9 ) return operator_as< 9 >(x) == value; }
1975
- if constexpr (requires { bool { operator_as<10 >(x) == value }; }) { if (x.index () == 10 ) return operator_as<10 >(x) == value; }
1976
- if constexpr (requires { bool { operator_as<11 >(x) == value }; }) { if (x.index () == 11 ) return operator_as<11 >(x) == value; }
1977
- if constexpr (requires { bool { operator_as<12 >(x) == value }; }) { if (x.index () == 12 ) return operator_as<12 >(x) == value; }
1978
- if constexpr (requires { bool { operator_as<13 >(x) == value }; }) { if (x.index () == 13 ) return operator_as<13 >(x) == value; }
1979
- if constexpr (requires { bool { operator_as<14 >(x) == value }; }) { if (x.index () == 14 ) return operator_as<14 >(x) == value; }
1980
- if constexpr (requires { bool { operator_as<15 >(x) == value }; }) { if (x.index () == 15 ) return operator_as<15 >(x) == value; }
1981
- if constexpr (requires { bool { operator_as<16 >(x) == value }; }) { if (x.index () == 16 ) return operator_as<16 >(x) == value; }
1982
- if constexpr (requires { bool { operator_as<17 >(x) == value }; }) { if (x.index () == 17 ) return operator_as<17 >(x) == value; }
1983
- if constexpr (requires { bool { operator_as<18 >(x) == value }; }) { if (x.index () == 18 ) return operator_as<18 >(x) == value; }
1984
- if constexpr (requires { bool { operator_as<19 >(x) == value }; }) { if (x.index () == 19 ) return operator_as<19 >(x) == value; }
1985
- }
1986
- return false ;
1987
- }
1988
-
1989
-
1990
- // as
1991
- //
1992
- template <typename T, typename ... Ts>
1993
- auto is ( std::variant<Ts...> const & x ) {
1994
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 0 >(x)), T >) { if (x.index () == 0 ) return true ; }
1995
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 1 >(x)), T >) { if (x.index () == 1 ) return true ; }
1996
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 2 >(x)), T >) { if (x.index () == 2 ) return true ; }
1997
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 3 >(x)), T >) { if (x.index () == 3 ) return true ; }
1998
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 4 >(x)), T >) { if (x.index () == 4 ) return true ; }
1999
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 5 >(x)), T >) { if (x.index () == 5 ) return true ; }
2000
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 6 >(x)), T >) { if (x.index () == 6 ) return true ; }
2001
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 7 >(x)), T >) { if (x.index () == 7 ) return true ; }
2002
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 8 >(x)), T >) { if (x.index () == 8 ) return true ; }
2003
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 9 >(x)), T >) { if (x.index () == 9 ) return true ; }
2004
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<10 >(x)), T >) { if (x.index () == 10 ) return true ; }
2005
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<11 >(x)), T >) { if (x.index () == 11 ) return true ; }
2006
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<12 >(x)), T >) { if (x.index () == 12 ) return true ; }
2007
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<13 >(x)), T >) { if (x.index () == 13 ) return true ; }
2008
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<14 >(x)), T >) { if (x.index () == 14 ) return true ; }
2009
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<15 >(x)), T >) { if (x.index () == 15 ) return true ; }
2010
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<16 >(x)), T >) { if (x.index () == 16 ) return true ; }
2011
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<17 >(x)), T >) { if (x.index () == 17 ) return true ; }
2012
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<18 >(x)), T >) { if (x.index () == 18 ) return true ; }
2013
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<19 >(x)), T >) { if (x.index () == 19 ) return true ; }
2014
- if constexpr (std::is_same_v< T, empty > ) {
2015
- if (x.valueless_by_exception ()) return true ;
2016
- // Need to guard this with is_any otherwise the get_if is illegal
2017
- if constexpr (is_any<std::monostate, Ts...>) return std::get_if<std::monostate>(&x) != nullptr ;
2018
- }
2019
- return false ;
2020
- }
2021
-
2022
2024
template <typename T, typename ... Ts>
2023
2025
auto as ( std::variant<Ts...> && x ) -> decltype(auto ) {
2024
2026
if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 0 >(x)), T >) { if (x.index () == 0 ) return operator_as<0 >(x); }
0 commit comments