diff --git a/stl/inc/variant b/stl/inc/variant index bccf5add82..7389fbee20 100644 --- a/stl/inc/variant +++ b/stl/inc/variant @@ -1365,13 +1365,14 @@ _NODISCARD constexpr add_pointer_t get_if( } // RELATIONAL OPERATORS [variant.relops] -template -struct _Variant_relop_visitor { // evaluate _Op with the contained value of two variants that hold the same alternative +template +struct _Variant_relop_visitor2 { // evaluate _Op with the contained value of two variants that hold the same alternative const _Variant_storage<_Types...>& _Left; template - _NODISCARD constexpr bool operator()(_Tagged _Right) const noexcept( - disjunction_v, is_nothrow_invocable_r>) { + _NODISCARD constexpr _Result operator()(_Tagged _Right) const + noexcept(disjunction_v, + is_nothrow_invocable_r<_Result, _Op, const _Ty&, const _Ty&>>) { // determine the relationship between the stored values of _Left and _Right // pre: _Left.index() == _Idx && _Right.index() == _Idx if constexpr (_Idx != variant_npos) { @@ -1387,7 +1388,7 @@ template _NODISCARD constexpr bool operator==(const variant<_Types...>& _Left, const variant<_Types...>& _Right) noexcept( conjunction_v, const _Types&, const _Types&>...>) /* strengthened */ { // determine if the arguments are both valueless or contain equal values - using _Visitor = _Variant_relop_visitor, _Types...>; + using _Visitor = _Variant_relop_visitor2, bool, _Types...>; const size_t _Right_index = _Right.index(); return _Left.index() == _Right_index && _Variant_raw_visit(_Right_index, _Right._Storage(), _Visitor{_Left._Storage()}); @@ -1397,7 +1398,7 @@ template _NODISCARD constexpr bool operator!=(const variant<_Types...>& _Left, const variant<_Types...>& _Right) noexcept( conjunction_v, const _Types&, const _Types&>...>) /* strengthened */ { // determine if the arguments have different active alternatives or contain unequal values - using _Visitor = _Variant_relop_visitor, _Types...>; + using _Visitor = _Variant_relop_visitor2, bool, _Types...>; const size_t _Right_index = _Right.index(); return _Left.index() != _Right_index || _Variant_raw_visit(_Right_index, _Right._Storage(), _Visitor{_Left._Storage()}); @@ -1408,7 +1409,7 @@ _NODISCARD constexpr bool operator<(const variant<_Types...>& _Left, const varia conjunction_v, const _Types&, const _Types&>...>) /* strengthened */ { // determine if _Left has a lesser index(), or equal index() and lesser // contained value than _Right - using _Visitor = _Variant_relop_visitor, _Types...>; + using _Visitor = _Variant_relop_visitor2, bool, _Types...>; const size_t _Left_offset = _Left.index() + 1; const size_t _Right_offset = _Right.index() + 1; return _Left_offset < _Right_offset @@ -1421,7 +1422,7 @@ _NODISCARD constexpr bool operator>(const variant<_Types...>& _Left, const varia conjunction_v, const _Types&, const _Types&>...>) /* strengthened */ { // determine if _Left has a greater index(), or equal index() and // greater contained value than _Right - using _Visitor = _Variant_relop_visitor, _Types...>; + using _Visitor = _Variant_relop_visitor2, bool, _Types...>; const size_t _Left_offset = _Left.index() + 1; const size_t _Right_offset = _Right.index() + 1; return _Left_offset > _Right_offset @@ -1434,7 +1435,7 @@ _NODISCARD constexpr bool operator<=(const variant<_Types...>& _Left, const vari conjunction_v, const _Types&, const _Types&>...>) /* strengthened */ { // determine if _Left's index() is less than _Right's, or equal and // _Left contains a value less than or equal to _Right - using _Visitor = _Variant_relop_visitor, _Types...>; + using _Visitor = _Variant_relop_visitor2, bool, _Types...>; const size_t _Left_offset = _Left.index() + 1; const size_t _Right_offset = _Right.index() + 1; return _Left_offset < _Right_offset @@ -1447,7 +1448,7 @@ _NODISCARD constexpr bool operator>=(const variant<_Types...>& _Left, const vari conjunction_v, const _Types&, const _Types&>...>) /* strengthened */ { // determine if _Left's index() is greater than _Right's, or equal and // _Left contains a value greater than or equal to _Right - using _Visitor = _Variant_relop_visitor, _Types...>; + using _Visitor = _Variant_relop_visitor2, bool, _Types...>; const size_t _Left_offset = _Left.index() + 1; const size_t _Right_offset = _Right.index() + 1; return _Left_offset > _Right_offset @@ -1455,6 +1456,27 @@ _NODISCARD constexpr bool operator>=(const variant<_Types...>& _Left, const vari && _Variant_raw_visit(_Right_offset - 1, _Right._Storage(), _Visitor{_Left._Storage()})); } +#ifdef __cpp_lib_concepts +// clang-format off +template + requires (three_way_comparable<_Types> && ...) +_NODISCARD constexpr common_comparison_category_t...> + operator<=>(const variant<_Types...>& _Left, const variant<_Types...>& _Right) noexcept( + conjunction_v...>, + compare_three_way, const _Types&, const _Types&>...>) /* strengthened */ { + // clang-format on + // determine the three-way comparison of _Left's and _Right's index, if equal + // return the three-way comparison of the contained values of _Left and _Right + using _Visitor = _Variant_relop_visitor2...>, _Types...>; + const size_t _Left_offset = _Left.index() + 1; + const size_t _Right_offset = _Right.index() + 1; + const auto _Offset_order = _Left_offset <=> _Right_offset; + return _Offset_order != 0 ? _Offset_order + : _Variant_raw_visit(_Right_offset - 1, _Right._Storage(), _Visitor{_Left._Storage()}); +} +#endif // __cpp_lib_concepts + // VISITATION [variant.visit] template inline constexpr size_t _Variant_total_states = @@ -1698,6 +1720,12 @@ struct monostate {}; _NODISCARD constexpr bool operator==(monostate, monostate) noexcept { return true; } + +#if _HAS_CXX20 +_NODISCARD constexpr strong_ordering operator<=>(monostate, monostate) noexcept { + return strong_ordering::equal; +} +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv _NODISCARD constexpr bool operator!=(monostate, monostate) noexcept { return false; } @@ -1713,6 +1741,7 @@ _NODISCARD constexpr bool operator<=(monostate, monostate) noexcept { _NODISCARD constexpr bool operator>=(monostate, monostate) noexcept { return true; } +#endif // !_HAS_CXX20 // SPECIALIZED ALGORITHMS [variant.specalg] template #include #include +#include #include template @@ -133,7 +134,7 @@ struct dummy_diagnostic : std::error_category { }; template -void spaceship_test(const SmallType& smaller, const EqualType& smaller_equal, const LargeType& larger) { +constexpr bool spaceship_test(const SmallType& smaller, const EqualType& smaller_equal, const LargeType& larger) { assert(smaller == smaller_equal); assert(smaller_equal == smaller); assert(smaller != larger); @@ -151,6 +152,8 @@ void spaceship_test(const SmallType& smaller, const EqualType& smaller_equal, co assert((smaller <=> smaller_equal) == 0); static_assert(std::is_same_v larger), ReturnType>); + + return true; } template @@ -603,6 +606,42 @@ void ordering_test_cases() { spaceship_test(c_mem[0], c_mem[0], c_mem[1]); } + { // variant + using V = std::variant; + constexpr V v0_0(std::in_place_index<0>, 0); + constexpr V v0_1(std::in_place_index<0>, 1); + constexpr V v1_0(std::in_place_index<1>, 0); + constexpr V v1_1(std::in_place_index<1>, 1); + + spaceship_test(v0_0, v0_0, v0_1); + spaceship_test(v0_1, v0_1, v1_0); + spaceship_test(v1_0, v1_0, v1_1); + + static_assert(spaceship_test(v0_0, v0_0, v0_1)); + static_assert(spaceship_test(v0_1, v0_1, v1_0)); + static_assert(spaceship_test(v1_0, v1_0, v1_1)); + + struct ThrowException { + operator int() { + throw "woof"; + } + }; + V valueless(std::in_place_index<1>, 1729L); + try { + valueless.emplace<0>(ThrowException{}); + } catch (...) { + // ignore exception + } + assert(valueless.valueless_by_exception()); + spaceship_test(valueless, valueless, v0_0); + spaceship_test(valueless, valueless, v1_1); + + using M = std::monostate; + constexpr M m1{}; + constexpr M m2{}; + assert((m1 <=> m2) == 0); + static_assert((m1 <=> m2) == 0); + } { // slice std::slice a1(2, 3, 4); std::slice a2(2, 3, 4);