@@ -649,6 +649,11 @@ concept specialization_of_template_type_and_nttp = requires (X x) {
649
649
{ specialization_of_template_helper<C>(std::forward<X>(x)) } -> std::same_as<std::true_type>;
650
650
};
651
651
652
+ template <typename X>
653
+ concept boolean_testable = std::convertible_to<X, bool > && requires(X&& x) {
654
+ { !std::forward<X>(x) } -> std::convertible_to<bool >;
655
+ };
656
+
652
657
template <typename X>
653
658
concept dereferencable = requires (X x) { *x; };
654
659
@@ -732,6 +737,67 @@ auto pointer_eq(T const* a, T const* b) {
732
737
return std::compare_three_way{}(a, b) == std::strong_ordering::equal;
733
738
}
734
739
740
+ // -----------------------------------------------------------------------
741
+ //
742
+ // A type_find_if for iterating over types in parameter packs
743
+ //
744
+ // Note: the current implementation is a workaround for clang-12 internal error.
745
+ // Original implementation does not need type_it and is implemented
746
+ // using lambda with explicit parameter type list in the following way:
747
+ //
748
+ // template <typename... Ts, typename F>
749
+ // constexpr auto type_find_if(F&& fun)
750
+ // {
751
+ // std::size_t found = std::variant_npos;
752
+ // [&]<std::size_t... Is>(std::index_sequence<Is...>){
753
+ // if constexpr ((requires { {CPP2_FORWARD(fun).template operator()<Is, Ts>()} -> std::convertible_to<bool>;} && ...)) {
754
+ // (((CPP2_FORWARD(fun).template operator()<Is, Ts>()) && (found = Is, true)) || ...);
755
+ // }
756
+ // }(std::index_sequence_for<Ts...>());
757
+ // return found;
758
+ // }
759
+ //
760
+ // The workaround is not needed in gcc-12.1+, clang-13+, msvc 19.29+
761
+ //
762
+ // Note2: the internal if constexpr could have else with static_assert.
763
+ // Unfortunatelly I cannot make it work on MSVC.
764
+ //
765
+ // -----------------------------------------------------------------------
766
+ //
767
+ template <std::size_t Index, typename T>
768
+ struct type_it {
769
+ using type = T;
770
+ inline static const std::size_t index = Index;
771
+ };
772
+
773
+ template <typename ... Ts, typename F>
774
+ constexpr auto type_find_if (F&& fun)
775
+ {
776
+ std::size_t found = std::variant_npos;
777
+ [&]<std::size_t ... Is>(std::index_sequence<Is...>){
778
+ if constexpr ((requires { {CPP2_FORWARD (fun)(type_it<Is, Ts>{})} -> boolean_testable;} && ...)) {
779
+ ((CPP2_FORWARD (fun)(type_it<Is, Ts>{}) && (found = Is, true )) || ...);
780
+ }
781
+ }(std::index_sequence_for<Ts...>());
782
+ return found;
783
+ }
784
+
785
+ template <typename F, template <typename ...> class C , typename ... Ts>
786
+ constexpr auto type_find_if (C<Ts...>, F&& fun)
787
+ {
788
+ return type_find_if<Ts...>(CPP2_FORWARD (fun));
789
+ }
790
+
791
+ template <typename T, typename ... Ts>
792
+ constexpr auto variant_contains_type (std::variant<Ts...>)
793
+ {
794
+ if constexpr (is_any<T, Ts...>) {
795
+ return std::true_type{};
796
+ } else {
797
+ return std::false_type{};
798
+ }
799
+ }
800
+
735
801
736
802
// -----------------------------------------------------------------------
737
803
//
@@ -1652,6 +1718,62 @@ auto is( X const& x ) -> bool {
1652
1718
return Dynamic_cast<C const *>(&x) != nullptr ;
1653
1719
}
1654
1720
}
1721
+ else if constexpr (
1722
+ specialization_of_template<X, std::variant>
1723
+ )
1724
+ {
1725
+ /*
1726
+ I am adding two versions of the algorithm that check emptiness.
1727
+
1728
+ Taking into consideration the following code:
1729
+
1730
+ std::variant<std::monostate,
1731
+ std::variant<std::monostate,
1732
+ std::variant<std::monostate, int>
1733
+ >
1734
+ > v;
1735
+
1736
+ v = std::variant<std::monostate,
1737
+ std::variant<std::monostate, int>
1738
+ >{
1739
+ std::variant<std::monostate, int>{std::monostate{}}
1740
+ };
1741
+
1742
+ If any of this 'std::monostate' is set (regardless of which variant),
1743
+ the recursive algorithm will consider it empty.
1744
+ This will be returned the same as asking if it contains std::monostate.
1745
+
1746
+ is<empty>(v) == true;
1747
+ is<std::monostate>(v) == true;
1748
+
1749
+ A non-recursive algorithm will consider it empty only when the top-level variant is set monostable.
1750
+ This will make it return a different value than asking if it contains std::monostate.
1751
+
1752
+ is<empty>(v) == false;
1753
+ is<std::monostate>(v) == true;
1754
+
1755
+ */
1756
+ if (x.valueless_by_exception ()) {
1757
+ return std::is_same_v<C, empty>;
1758
+ }
1759
+ if constexpr (
1760
+ std::is_same_v<C, empty>
1761
+ )
1762
+ {
1763
+ if constexpr (requires { {variant_contains_type<std::monostate>(std::declval<X>())} -> std::same_as<std::true_type>; }) {
1764
+ #if true // recursive check of emptyness (empty when top-level variant contains monostate or when contains variant that is empty)
1765
+ if (std::get_if<std::monostate>(&x) != nullptr )
1766
+ return true ;
1767
+ #else // non-recursive check of emptyness (empty only when top-level variant contains monostate)
1768
+ return std::get_if<std::monostate>(&x) != nullptr ;
1769
+ #endif
1770
+ }
1771
+ }
1772
+ return type_find_if (x, [&]<typename It>(It const &) -> bool {
1773
+ if (x.index () == It::index ) { return is<C>(std::get<It::index >(x));}
1774
+ return false ;
1775
+ }) != std::variant_npos;
1776
+ }
1655
1777
else if constexpr (
1656
1778
requires { *x; X (); }
1657
1779
&& std::is_same_v<C, empty>
@@ -1908,106 +2030,6 @@ constexpr auto operator_as( std::variant<Ts...> const& x ) -> decltype(auto) {
1908
2030
}
1909
2031
1910
2032
1911
- // is Type
1912
- //
1913
- template <typename ... Ts>
1914
- constexpr auto operator_is ( std::variant<Ts...> const & x ) {
1915
- return x.index ();
1916
- }
1917
-
1918
- template <typename T, typename ... Ts>
1919
- auto is ( std::variant<Ts...> const & x );
1920
-
1921
-
1922
- // is Value
1923
- //
1924
- template <typename ... Ts>
1925
- constexpr auto is ( std::variant<Ts...> const & x, auto && value ) -> bool
1926
- {
1927
- // Predicate case
1928
- if constexpr (requires{ bool { value (operator_as< 0 >(x)) }; }) { if (x.index () == 0 ) return value (operator_as< 0 >(x)); }
1929
- else if constexpr (requires{ bool { value (operator_as< 1 >(x)) }; }) { if (x.index () == 1 ) return value (operator_as< 1 >(x)); }
1930
- else if constexpr (requires{ bool { value (operator_as< 2 >(x)) }; }) { if (x.index () == 2 ) return value (operator_as< 2 >(x)); }
1931
- else if constexpr (requires{ bool { value (operator_as< 3 >(x)) }; }) { if (x.index () == 3 ) return value (operator_as< 3 >(x)); }
1932
- else if constexpr (requires{ bool { value (operator_as< 4 >(x)) }; }) { if (x.index () == 4 ) return value (operator_as< 4 >(x)); }
1933
- else if constexpr (requires{ bool { value (operator_as< 5 >(x)) }; }) { if (x.index () == 5 ) return value (operator_as< 5 >(x)); }
1934
- else if constexpr (requires{ bool { value (operator_as< 6 >(x)) }; }) { if (x.index () == 6 ) return value (operator_as< 6 >(x)); }
1935
- else if constexpr (requires{ bool { value (operator_as< 7 >(x)) }; }) { if (x.index () == 7 ) return value (operator_as< 7 >(x)); }
1936
- else if constexpr (requires{ bool { value (operator_as< 8 >(x)) }; }) { if (x.index () == 8 ) return value (operator_as< 8 >(x)); }
1937
- else if constexpr (requires{ bool { value (operator_as< 9 >(x)) }; }) { if (x.index () == 9 ) return value (operator_as< 9 >(x)); }
1938
- else if constexpr (requires{ bool { value (operator_as<10 >(x)) }; }) { if (x.index () == 10 ) return value (operator_as<10 >(x)); }
1939
- else if constexpr (requires{ bool { value (operator_as<11 >(x)) }; }) { if (x.index () == 11 ) return value (operator_as<11 >(x)); }
1940
- else if constexpr (requires{ bool { value (operator_as<12 >(x)) }; }) { if (x.index () == 12 ) return value (operator_as<12 >(x)); }
1941
- else if constexpr (requires{ bool { value (operator_as<13 >(x)) }; }) { if (x.index () == 13 ) return value (operator_as<13 >(x)); }
1942
- else if constexpr (requires{ bool { value (operator_as<14 >(x)) }; }) { if (x.index () == 14 ) return value (operator_as<14 >(x)); }
1943
- else if constexpr (requires{ bool { value (operator_as<15 >(x)) }; }) { if (x.index () == 15 ) return value (operator_as<15 >(x)); }
1944
- else if constexpr (requires{ bool { value (operator_as<16 >(x)) }; }) { if (x.index () == 16 ) return value (operator_as<16 >(x)); }
1945
- else if constexpr (requires{ bool { value (operator_as<17 >(x)) }; }) { if (x.index () == 17 ) return value (operator_as<17 >(x)); }
1946
- else if constexpr (requires{ bool { value (operator_as<18 >(x)) }; }) { if (x.index () == 18 ) return value (operator_as<18 >(x)); }
1947
- else if constexpr (requires{ bool { value (operator_as<19 >(x)) }; }) { if (x.index () == 19 ) return value (operator_as<19 >(x)); }
1948
- else if constexpr (std::is_function_v<decltype (value)> || requires{ &value.operator (); }) {
1949
- return false ;
1950
- }
1951
-
1952
- // Value case
1953
- else {
1954
- if constexpr (requires{ bool { operator_as< 0 >(x) == value }; }) { if (x.index () == 0 ) return operator_as< 0 >(x) == value; }
1955
- if constexpr (requires{ bool { operator_as< 1 >(x) == value }; }) { if (x.index () == 1 ) return operator_as< 1 >(x) == value; }
1956
- if constexpr (requires{ bool { operator_as< 2 >(x) == value }; }) { if (x.index () == 2 ) return operator_as< 2 >(x) == value; }
1957
- if constexpr (requires{ bool { operator_as< 3 >(x) == value }; }) { if (x.index () == 3 ) return operator_as< 3 >(x) == value; }
1958
- if constexpr (requires{ bool { operator_as< 4 >(x) == value }; }) { if (x.index () == 4 ) return operator_as< 4 >(x) == value; }
1959
- if constexpr (requires{ bool { operator_as< 5 >(x) == value }; }) { if (x.index () == 5 ) return operator_as< 5 >(x) == value; }
1960
- if constexpr (requires{ bool { operator_as< 6 >(x) == value }; }) { if (x.index () == 6 ) return operator_as< 6 >(x) == value; }
1961
- if constexpr (requires{ bool { operator_as< 7 >(x) == value }; }) { if (x.index () == 7 ) return operator_as< 7 >(x) == value; }
1962
- if constexpr (requires{ bool { operator_as< 8 >(x) == value }; }) { if (x.index () == 8 ) return operator_as< 8 >(x) == value; }
1963
- if constexpr (requires{ bool { operator_as< 9 >(x) == value }; }) { if (x.index () == 9 ) return operator_as< 9 >(x) == value; }
1964
- if constexpr (requires{ bool { operator_as<10 >(x) == value }; }) { if (x.index () == 10 ) return operator_as<10 >(x) == value; }
1965
- if constexpr (requires{ bool { operator_as<11 >(x) == value }; }) { if (x.index () == 11 ) return operator_as<11 >(x) == value; }
1966
- if constexpr (requires{ bool { operator_as<12 >(x) == value }; }) { if (x.index () == 12 ) return operator_as<12 >(x) == value; }
1967
- if constexpr (requires{ bool { operator_as<13 >(x) == value }; }) { if (x.index () == 13 ) return operator_as<13 >(x) == value; }
1968
- if constexpr (requires{ bool { operator_as<14 >(x) == value }; }) { if (x.index () == 14 ) return operator_as<14 >(x) == value; }
1969
- if constexpr (requires{ bool { operator_as<15 >(x) == value }; }) { if (x.index () == 15 ) return operator_as<15 >(x) == value; }
1970
- if constexpr (requires{ bool { operator_as<16 >(x) == value }; }) { if (x.index () == 16 ) return operator_as<16 >(x) == value; }
1971
- if constexpr (requires{ bool { operator_as<17 >(x) == value }; }) { if (x.index () == 17 ) return operator_as<17 >(x) == value; }
1972
- if constexpr (requires{ bool { operator_as<18 >(x) == value }; }) { if (x.index () == 18 ) return operator_as<18 >(x) == value; }
1973
- if constexpr (requires{ bool { operator_as<19 >(x) == value }; }) { if (x.index () == 19 ) return operator_as<19 >(x) == value; }
1974
- }
1975
- return false ;
1976
- }
1977
-
1978
-
1979
- // as
1980
- //
1981
- template <typename T, typename ... Ts>
1982
- auto is ( std::variant<Ts...> const & x ) {
1983
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 0 >(x)), T >) { if (x.index () == 0 ) return true ; }
1984
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 1 >(x)), T >) { if (x.index () == 1 ) return true ; }
1985
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 2 >(x)), T >) { if (x.index () == 2 ) return true ; }
1986
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 3 >(x)), T >) { if (x.index () == 3 ) return true ; }
1987
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 4 >(x)), T >) { if (x.index () == 4 ) return true ; }
1988
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 5 >(x)), T >) { if (x.index () == 5 ) return true ; }
1989
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 6 >(x)), T >) { if (x.index () == 6 ) return true ; }
1990
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 7 >(x)), T >) { if (x.index () == 7 ) return true ; }
1991
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 8 >(x)), T >) { if (x.index () == 8 ) return true ; }
1992
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as< 9 >(x)), T >) { if (x.index () == 9 ) return true ; }
1993
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<10 >(x)), T >) { if (x.index () == 10 ) return true ; }
1994
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<11 >(x)), T >) { if (x.index () == 11 ) return true ; }
1995
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<12 >(x)), T >) { if (x.index () == 12 ) return true ; }
1996
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<13 >(x)), T >) { if (x.index () == 13 ) return true ; }
1997
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<14 >(x)), T >) { if (x.index () == 14 ) return true ; }
1998
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<15 >(x)), T >) { if (x.index () == 15 ) return true ; }
1999
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<16 >(x)), T >) { if (x.index () == 16 ) return true ; }
2000
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<17 >(x)), T >) { if (x.index () == 17 ) return true ; }
2001
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<18 >(x)), T >) { if (x.index () == 18 ) return true ; }
2002
- if constexpr (std::is_same_v< CPP2_TYPEOF (operator_as<19 >(x)), T >) { if (x.index () == 19 ) return true ; }
2003
- if constexpr (std::is_same_v< T, empty > ) {
2004
- if (x.valueless_by_exception ()) return true ;
2005
- // Need to guard this with is_any otherwise the get_if is illegal
2006
- if constexpr (is_any<std::monostate, Ts...>) return std::get_if<std::monostate>(&x) != nullptr ;
2007
- }
2008
- return false ;
2009
- }
2010
-
2011
2033
template <typename T, typename ... Ts>
2012
2034
auto as ( std::variant<Ts...> && x ) -> decltype(auto ) {
2013
2035
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