//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 // // template class variant; // template requires (three_way_comparable && ...) // constexpr std::common_comparison_category_t< // std::compare_three_way_result_t...> // operator<=>(const variant& t, const variant& u); #include #include #include #include #include #include "test_macros.h" #include "test_comparisons.h" #ifndef TEST_HAS_NO_EXCEPTIONS // MakeEmptyT throws in operator=(&&), so we can move to it to create valueless-by-exception variants. struct MakeEmptyT { MakeEmptyT() = default; MakeEmptyT(MakeEmptyT&&) { throw 42; } MakeEmptyT& operator=(MakeEmptyT&&) { throw 42; } }; inline bool operator==(const MakeEmptyT&, const MakeEmptyT&) { assert(false); return false; } inline std::weak_ordering operator<=>(const MakeEmptyT&, const MakeEmptyT&) { assert(false); return std::weak_ordering::equivalent; } template void makeEmpty(Variant& v) { Variant v2(std::in_place_type); try { v = std::move(v2); assert(false); } catch (...) { assert(v.valueless_by_exception()); } } void test_empty() { { using V = std::variant; V v1; V v2; makeEmpty(v2); assert(testOrder(v1, v2, std::weak_ordering::greater)); } { using V = std::variant; V v1; makeEmpty(v1); V v2; assert(testOrder(v1, v2, std::weak_ordering::less)); } { using V = std::variant; V v1; makeEmpty(v1); V v2; makeEmpty(v2); assert(testOrder(v1, v2, std::weak_ordering::equivalent)); } } #endif // TEST_HAS_NO_EXCEPTIONS template constexpr bool test_with_types() { using V = std::variant; AssertOrderReturn(); { // same index, same value constexpr V v1(std::in_place_index<0>, T1{1}); constexpr V v2(std::in_place_index<0>, T1{1}); assert(testOrder(v1, v2, Order::equivalent)); } { // same index, value < other_value constexpr V v1(std::in_place_index<0>, T1{0}); constexpr V v2(std::in_place_index<0>, T1{1}); assert(testOrder(v1, v2, Order::less)); } { // same index, value > other_value constexpr V v1(std::in_place_index<0>, T1{1}); constexpr V v2(std::in_place_index<0>, T1{0}); assert(testOrder(v1, v2, Order::greater)); } { // LHS.index() < RHS.index() constexpr V v1(std::in_place_index<0>, T1{0}); constexpr V v2(std::in_place_index<1>, T2{0}); assert(testOrder(v1, v2, Order::less)); } { // LHS.index() > RHS.index() constexpr V v1(std::in_place_index<1>, T2{0}); constexpr V v2(std::in_place_index<0>, T1{0}); assert(testOrder(v1, v2, Order::greater)); } return true; } constexpr bool test_three_way() { assert((test_with_types())); assert((test_with_types())); { using V = std::variant; constexpr double nan = std::numeric_limits::quiet_NaN(); { constexpr V v1(std::in_place_type, 1); constexpr V v2(std::in_place_type, nan); assert(testOrder(v1, v2, std::partial_ordering::less)); } { constexpr V v1(std::in_place_type, nan); constexpr V v2(std::in_place_type, 2); assert(testOrder(v1, v2, std::partial_ordering::greater)); } { constexpr V v1(std::in_place_type, nan); constexpr V v2(std::in_place_type, nan); assert(testOrder(v1, v2, std::partial_ordering::unordered)); } } return true; } // SFINAE tests template concept has_three_way_op = requires (T& t, U& u) { t <=> u; }; // std::three_way_comparable is a more stringent requirement that demands // operator== and a few other things. using std::three_way_comparable; struct HasSimpleOrdering { constexpr bool operator==(const HasSimpleOrdering&) const; constexpr bool operator<(const HasSimpleOrdering&) const; }; struct HasOnlySpaceship { constexpr bool operator==(const HasOnlySpaceship&) const = delete; constexpr std::weak_ordering operator<=>(const HasOnlySpaceship&) const; }; struct HasFullOrdering { constexpr bool operator==(const HasFullOrdering&) const; constexpr std::weak_ordering operator<=>(const HasFullOrdering&) const; }; // operator<=> must resolve the return types of all its union types' // operator<=>s to determine its own return type, so it is detectable by SFINAE static_assert(!has_three_way_op); static_assert(!has_three_way_op>); static_assert(!three_way_comparable); static_assert(!three_way_comparable>); static_assert(has_three_way_op); static_assert(!has_three_way_op>); static_assert(!three_way_comparable); static_assert(!three_way_comparable>); static_assert( has_three_way_op); static_assert( has_three_way_op>); static_assert( three_way_comparable); static_assert( three_way_comparable>); int main(int, char**) { test_three_way(); static_assert(test_three_way()); #ifndef TEST_HAS_NO_EXCEPTIONS test_empty(); #endif // TEST_HAS_NO_EXCEPTIONS return 0; }