@@ -649,6 +649,11 @@ concept specialization_of_template_type_and_nttp = requires (X x) {
649649 { specialization_of_template_helper<C>(std::forward<X>(x)) } -> std::same_as<std::true_type>;
650650};
651651
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+
652657template <typename X>
653658concept dereferencable = requires (X x) { *x; };
654659
@@ -732,6 +737,67 @@ auto pointer_eq(T const* a, T const* b) {
732737 return std::compare_three_way{}(a, b) == std::strong_ordering::equal;
733738}
734739
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...> const &, 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+
735801
736802// -----------------------------------------------------------------------
737803//
@@ -1652,6 +1718,62 @@ auto is( X const& x ) -> bool {
16521718 return Dynamic_cast<C const *>(&x) != nullptr ;
16531719 }
16541720 }
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 false // 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+ }
16551777 else if constexpr (
16561778 requires { *x; X (); }
16571779 && std::is_same_v<C, empty>
@@ -1908,106 +2030,6 @@ constexpr auto operator_as( std::variant<Ts...> const& x ) -> decltype(auto) {
19082030}
19092031
19102032
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-
20112033template <typename T, typename ... Ts>
20122034auto as ( std::variant<Ts...> && x ) -> decltype(auto ) {
20132035 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