@@ -615,6 +615,11 @@ concept specialization_of_template_type_and_nttp = requires (X x) {
615
615
{ specialization_of_template_helper<C>(std::forward<X>(x)) } -> std::same_as<std::true_type>;
616
616
};
617
617
618
+ template <typename X>
619
+ concept boolean_testable = std::convertible_to<X, bool > && requires(X&& x) {
620
+ { !std::forward<X>(x) } -> std::convertible_to<bool >;
621
+ };
622
+
618
623
template <typename X>
619
624
concept dereferencable = requires (X x) { *x; };
620
625
@@ -705,6 +710,67 @@ auto pointer_eq(T const* a, T const* b) {
705
710
return std::compare_three_way{}(a, b) == std::strong_ordering::equal;
706
711
}
707
712
713
+ // -----------------------------------------------------------------------
714
+ //
715
+ // A type_find_if for iterating over types in parameter packs
716
+ //
717
+ // Note: the current implementation is a workaround for clang-12 internal error.
718
+ // Original implementation does not need type_it and is implemented
719
+ // using lambda with explicit parameter type list in the following way:
720
+ //
721
+ // template <typename... Ts, typename F>
722
+ // constexpr auto type_find_if(F&& fun)
723
+ // {
724
+ // std::size_t found = std::variant_npos;
725
+ // [&]<std::size_t... Is>(std::index_sequence<Is...>){
726
+ // if constexpr ((requires { {CPP2_FORWARD(fun).template operator()<Is, Ts>()} -> std::convertible_to<bool>;} && ...)) {
727
+ // (((CPP2_FORWARD(fun).template operator()<Is, Ts>()) && (found = Is, true)) || ...);
728
+ // }
729
+ // }(std::index_sequence_for<Ts...>());
730
+ // return found;
731
+ // }
732
+ //
733
+ // The workaround is not needed in gcc-12.1+, clang-13+, msvc 19.29+
734
+ //
735
+ // Note2: the internal if constexpr could have else with static_assert.
736
+ // Unfortunatelly I cannot make it work on MSVC.
737
+ //
738
+ // -----------------------------------------------------------------------
739
+ //
740
+ template <std::size_t Index, typename T>
741
+ struct type_it {
742
+ using type = T;
743
+ inline static const std::size_t index = Index;
744
+ };
745
+
746
+ template <typename ... Ts, typename F>
747
+ constexpr auto type_find_if (F&& fun)
748
+ {
749
+ std::size_t found = std::variant_npos;
750
+ [&]<std::size_t ... Is>(std::index_sequence<Is...>){
751
+ if constexpr ((requires { {CPP2_FORWARD (fun)(type_it<Is, Ts>{})} -> boolean_testable;} && ...)) {
752
+ ((CPP2_FORWARD (fun)(type_it<Is, Ts>{}) && (found = Is, true )) || ...);
753
+ }
754
+ }(std::index_sequence_for<Ts...>());
755
+ return found;
756
+ }
757
+
758
+ template <typename F, template <typename ...> class C , typename ... Ts>
759
+ constexpr auto type_find_if (C<Ts...>, F&& fun)
760
+ {
761
+ return type_find_if<Ts...>(CPP2_FORWARD (fun));
762
+ }
763
+
764
+ template <typename T, typename ... Ts>
765
+ constexpr auto variant_contains_type (std::variant<Ts...>)
766
+ {
767
+ if constexpr (is_any<T, Ts...>) {
768
+ return std::true_type{};
769
+ } else {
770
+ return std::false_type{};
771
+ }
772
+ }
773
+
708
774
709
775
// -----------------------------------------------------------------------
710
776
//
@@ -1625,6 +1691,63 @@ auto is( X const& x ) -> bool {
1625
1691
return Dynamic_cast<C const *>(&x) != nullptr ;
1626
1692
}
1627
1693
}
1694
+ else if constexpr (
1695
+ specialization_of_template<X, std::variant>
1696
+ )
1697
+ {
1698
+ /*
1699
+ I am adding two versions of the algorithm that check emptiness.
1700
+
1701
+ Taking into consideration the following code:
1702
+
1703
+ std::variant<std::monostate,
1704
+ std::variant<std::monostate,
1705
+ std::variant<std::monostate, int>
1706
+ >
1707
+ > v;
1708
+
1709
+ v = std::variant<std::monostate,
1710
+ std::variant<std::monostate, int>
1711
+ >{
1712
+ std::variant<std::monostate, int>{std::monostate{}}
1713
+ };
1714
+
1715
+ Recursive algorithm will consider it empty if any of these
1716
+ std::monostate will be set (no mather in which variant).
1717
+ This will be return the same as asking if it contains std::monostate.
1718
+
1719
+ is<empty>(v) == true;
1720
+ is<std::monostate>(v) == true;
1721
+
1722
+ Non-recursive algorithm will consider it empty only when top-level
1723
+ variant will set monostate. This will make it return different
1724
+ value then asking if it sontains std::monostate.
1725
+
1726
+ is<empty>(v) == false;
1727
+ is<std::monostate>(v) == true;
1728
+
1729
+ */
1730
+ if (x.valueless_by_exception ()) {
1731
+ return std::is_same_v<C, empty>;
1732
+ }
1733
+ if constexpr (
1734
+ std::is_same_v<C, empty>
1735
+ )
1736
+ {
1737
+ if constexpr (requires { {variant_contains_type<std::monostate>(std::declval<X>())} -> std::same_as<std::true_type>; }) {
1738
+ #if true // recursive check of emptyness (empty when top-level variant contains monostate or when contains variant that is empty)
1739
+ if (std::get_if<std::monostate>(&x) != nullptr )
1740
+ return true ;
1741
+ #else // non-recursive check of emptyness (empty only when top-level variant contains monostate)
1742
+ return std::get_if<std::monostate>(&x) != nullptr ;
1743
+ #endif
1744
+ }
1745
+ }
1746
+ return type_find_if (x, [&]<typename It>(It const &) -> bool {
1747
+ if (x.index () == It::index ) { return is<C>(std::get<It::index >(x));}
1748
+ return false ;
1749
+ }) != std::variant_npos;
1750
+ }
1628
1751
else if constexpr (
1629
1752
requires { *x; X (); }
1630
1753
&& std::is_same_v<C, empty>
@@ -1881,106 +2004,6 @@ constexpr auto operator_as( std::variant<Ts...> const& x ) -> decltype(auto) {
1881
2004
}
1882
2005
1883
2006
1884
- // is Type
1885
- //
1886
- template <typename ... Ts>
1887
- constexpr auto operator_is ( std::variant<Ts...> const & x ) {
1888
- return x.index ();
1889
- }
1890
-
1891
- template <typename T, typename ... Ts>
1892
- auto is ( std::variant<Ts...> const & x );
1893
-
1894
-
1895
- // is Value
1896
- //
1897
- template <typename ... Ts>
1898
- constexpr auto is ( std::variant<Ts...> const & x, auto && value ) -> bool
1899
- {
1900
- // Predicate case
1901
- if constexpr (requires{ bool { value (operator_as< 0 >(x)) }; }) { if (x.index () == 0 ) return value (operator_as< 0 >(x)); }
1902
- else if constexpr (requires{ bool { value (operator_as< 1 >(x)) }; }) { if (x.index () == 1 ) return value (operator_as< 1 >(x)); }
1903
- else if constexpr (requires{ bool { value (operator_as< 2 >(x)) }; }) { if (x.index () == 2 ) return value (operator_as< 2 >(x)); }
1904
- else if constexpr (requires{ bool { value (operator_as< 3 >(x)) }; }) { if (x.index () == 3 ) return value (operator_as< 3 >(x)); }
1905
- else if constexpr (requires{ bool { value (operator_as< 4 >(x)) }; }) { if (x.index () == 4 ) return value (operator_as< 4 >(x)); }
1906
- else if constexpr (requires{ bool { value (operator_as< 5 >(x)) }; }) { if (x.index () == 5 ) return value (operator_as< 5 >(x)); }
1907
- else if constexpr (requires{ bool { value (operator_as< 6 >(x)) }; }) { if (x.index () == 6 ) return value (operator_as< 6 >(x)); }
1908
- else if constexpr (requires{ bool { value (operator_as< 7 >(x)) }; }) { if (x.index () == 7 ) return value (operator_as< 7 >(x)); }
1909
- else if constexpr (requires{ bool { value (operator_as< 8 >(x)) }; }) { if (x.index () == 8 ) return value (operator_as< 8 >(x)); }
1910
- else if constexpr (requires{ bool { value (operator_as< 9 >(x)) }; }) { if (x.index () == 9 ) return value (operator_as< 9 >(x)); }
1911
- else if constexpr (requires{ bool { value (operator_as<10 >(x)) }; }) { if (x.index () == 10 ) return value (operator_as<10 >(x)); }
1912
- else if constexpr (requires{ bool { value (operator_as<11 >(x)) }; }) { if (x.index () == 11 ) return value (operator_as<11 >(x)); }
1913
- else if constexpr (requires{ bool { value (operator_as<12 >(x)) }; }) { if (x.index () == 12 ) return value (operator_as<12 >(x)); }
1914
- else if constexpr (requires{ bool { value (operator_as<13 >(x)) }; }) { if (x.index () == 13 ) return value (operator_as<13 >(x)); }
1915
- else if constexpr (requires{ bool { value (operator_as<14 >(x)) }; }) { if (x.index () == 14 ) return value (operator_as<14 >(x)); }
1916
- else if constexpr (requires{ bool { value (operator_as<15 >(x)) }; }) { if (x.index () == 15 ) return value (operator_as<15 >(x)); }
1917
- else if constexpr (requires{ bool { value (operator_as<16 >(x)) }; }) { if (x.index () == 16 ) return value (operator_as<16 >(x)); }
1918
- else if constexpr (requires{ bool { value (operator_as<17 >(x)) }; }) { if (x.index () == 17 ) return value (operator_as<17 >(x)); }
1919
- else if constexpr (requires{ bool { value (operator_as<18 >(x)) }; }) { if (x.index () == 18 ) return value (operator_as<18 >(x)); }
1920
- else if constexpr (requires{ bool { value (operator_as<19 >(x)) }; }) { if (x.index () == 19 ) return value (operator_as<19 >(x)); }
1921
- else if constexpr (std::is_function_v<decltype (value)> || requires{ &value.operator (); }) {
1922
- return false ;
1923
- }
1924
-
1925
- // Value case
1926
- else {
1927
- if constexpr (requires{ bool { operator_as< 0 >(x) == value }; }) { if (x.index () == 0 ) return operator_as< 0 >(x) == value; }
1928
- if constexpr (requires{ bool { operator_as< 1 >(x) == value }; }) { if (x.index () == 1 ) return operator_as< 1 >(x) == value; }
1929
- if constexpr (requires{ bool { operator_as< 2 >(x) == value }; }) { if (x.index () == 2 ) return operator_as< 2 >(x) == value; }
1930
- if constexpr (requires{ bool { operator_as< 3 >(x) == value }; }) { if (x.index () == 3 ) return operator_as< 3 >(x) == value; }
1931
- if constexpr (requires{ bool { operator_as< 4 >(x) == value }; }) { if (x.index () == 4 ) return operator_as< 4 >(x) == value; }
1932
- if constexpr (requires{ bool { operator_as< 5 >(x) == value }; }) { if (x.index () == 5 ) return operator_as< 5 >(x) == value; }
1933
- if constexpr (requires{ bool { operator_as< 6 >(x) == value }; }) { if (x.index () == 6 ) return operator_as< 6 >(x) == value; }
1934
- if constexpr (requires{ bool { operator_as< 7 >(x) == value }; }) { if (x.index () == 7 ) return operator_as< 7 >(x) == value; }
1935
- if constexpr (requires{ bool { operator_as< 8 >(x) == value }; }) { if (x.index () == 8 ) return operator_as< 8 >(x) == value; }
1936
- if constexpr (requires{ bool { operator_as< 9 >(x) == value }; }) { if (x.index () == 9 ) return operator_as< 9 >(x) == value; }
1937
- if constexpr (requires{ bool { operator_as<10 >(x) == value }; }) { if (x.index () == 10 ) return operator_as<10 >(x) == value; }
1938
- if constexpr (requires{ bool { operator_as<11 >(x) == value }; }) { if (x.index () == 11 ) return operator_as<11 >(x) == value; }
1939
- if constexpr (requires{ bool { operator_as<12 >(x) == value }; }) { if (x.index () == 12 ) return operator_as<12 >(x) == value; }
1940
- if constexpr (requires{ bool { operator_as<13 >(x) == value }; }) { if (x.index () == 13 ) return operator_as<13 >(x) == value; }
1941
- if constexpr (requires{ bool { operator_as<14 >(x) == value }; }) { if (x.index () == 14 ) return operator_as<14 >(x) == value; }
1942
- if constexpr (requires{ bool { operator_as<15 >(x) == value }; }) { if (x.index () == 15 ) return operator_as<15 >(x) == value; }
1943
- if constexpr (requires{ bool { operator_as<16 >(x) == value }; }) { if (x.index () == 16 ) return operator_as<16 >(x) == value; }
1944
- if constexpr (requires{ bool { operator_as<17 >(x) == value }; }) { if (x.index () == 17 ) return operator_as<17 >(x) == value; }
1945
- if constexpr (requires{ bool { operator_as<18 >(x) == value }; }) { if (x.index () == 18 ) return operator_as<18 >(x) == value; }
1946
- if constexpr (requires{ bool { operator_as<19 >(x) == value }; }) { if (x.index () == 19 ) return operator_as<19 >(x) == value; }
1947
- }
1948
- return false ;
1949
- }
1950
-
1951
-
1952
- // as
1953
- //
1954
- template <typename T, typename ... Ts>
1955
- auto is ( std::variant<Ts...> const & x ) {
1956
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 0 >(x)), T >) { if (x.index () == 0 ) return true ; }
1957
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 1 >(x)), T >) { if (x.index () == 1 ) return true ; }
1958
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 2 >(x)), T >) { if (x.index () == 2 ) return true ; }
1959
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 3 >(x)), T >) { if (x.index () == 3 ) return true ; }
1960
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 4 >(x)), T >) { if (x.index () == 4 ) return true ; }
1961
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 5 >(x)), T >) { if (x.index () == 5 ) return true ; }
1962
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 6 >(x)), T >) { if (x.index () == 6 ) return true ; }
1963
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 7 >(x)), T >) { if (x.index () == 7 ) return true ; }
1964
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 8 >(x)), T >) { if (x.index () == 8 ) return true ; }
1965
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 9 >(x)), T >) { if (x.index () == 9 ) return true ; }
1966
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<10 >(x)), T >) { if (x.index () == 10 ) return true ; }
1967
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<11 >(x)), T >) { if (x.index () == 11 ) return true ; }
1968
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<12 >(x)), T >) { if (x.index () == 12 ) return true ; }
1969
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<13 >(x)), T >) { if (x.index () == 13 ) return true ; }
1970
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<14 >(x)), T >) { if (x.index () == 14 ) return true ; }
1971
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<15 >(x)), T >) { if (x.index () == 15 ) return true ; }
1972
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<16 >(x)), T >) { if (x.index () == 16 ) return true ; }
1973
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<17 >(x)), T >) { if (x.index () == 17 ) return true ; }
1974
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<18 >(x)), T >) { if (x.index () == 18 ) return true ; }
1975
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<19 >(x)), T >) { if (x.index () == 19 ) return true ; }
1976
- if constexpr (std::is_same_v< T, empty > ) {
1977
- if (x.valueless_by_exception ()) return true ;
1978
- // Need to guard this with is_any otherwise the get_if is illegal
1979
- if constexpr (is_any<std::monostate, Ts...>) return std::get_if<std::monostate>(&x) != nullptr ;
1980
- }
1981
- return false ;
1982
- }
1983
-
1984
2007
template <typename T, typename ... Ts>
1985
2008
auto as ( std::variant<Ts...> && x ) -> decltype(auto ) {
1986
2009
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