1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
13 // template <class... Types> class variant;
15 // template <class... Types> requires (three_way_comparable<Types> && ...)
16 // constexpr std::common_comparison_category_t<
17 // std::compare_three_way_result_t<Types>...>
18 // operator<=>(const variant<Types...>& t, const variant<Types...>& u);
22 #include <type_traits>
26 #include "test_macros.h"
27 #include "test_comparisons.h"
29 #ifndef TEST_HAS_NO_EXCEPTIONS
30 // MakeEmptyT throws in operator=(&&), so we can move to it to create valueless-by-exception variants.
32 MakeEmptyT() = default;
33 MakeEmptyT(MakeEmptyT
&&) { throw 42; }
34 MakeEmptyT
& operator=(MakeEmptyT
&&) { throw 42; }
36 inline bool operator==(const MakeEmptyT
&, const MakeEmptyT
&) {
40 inline std::weak_ordering
operator<=>(const MakeEmptyT
&, const MakeEmptyT
&) {
42 return std::weak_ordering::equivalent
;
45 template <class Variant
>
46 void makeEmpty(Variant
& v
) {
47 Variant
v2(std::in_place_type
<MakeEmptyT
>);
52 assert(v
.valueless_by_exception());
58 using V
= std::variant
<int, MakeEmptyT
>;
62 assert(testOrder(v1
, v2
, std::weak_ordering::greater
));
65 using V
= std::variant
<int, MakeEmptyT
>;
69 assert(testOrder(v1
, v2
, std::weak_ordering::less
));
72 using V
= std::variant
<int, MakeEmptyT
>;
77 assert(testOrder(v1
, v2
, std::weak_ordering::equivalent
));
80 #endif // TEST_HAS_NO_EXCEPTIONS
82 template <class T1
, class T2
, class Order
>
83 constexpr bool test_with_types() {
84 using V
= std::variant
<T1
, T2
>;
85 AssertOrderReturn
<Order
, V
>();
86 { // same index, same value
87 constexpr V
v1(std::in_place_index
<0>, T1
{1});
88 constexpr V
v2(std::in_place_index
<0>, T1
{1});
89 assert(testOrder(v1
, v2
, Order::equivalent
));
91 { // same index, value < other_value
92 constexpr V
v1(std::in_place_index
<0>, T1
{0});
93 constexpr V
v2(std::in_place_index
<0>, T1
{1});
94 assert(testOrder(v1
, v2
, Order::less
));
96 { // same index, value > other_value
97 constexpr V
v1(std::in_place_index
<0>, T1
{1});
98 constexpr V
v2(std::in_place_index
<0>, T1
{0});
99 assert(testOrder(v1
, v2
, Order::greater
));
101 { // LHS.index() < RHS.index()
102 constexpr V
v1(std::in_place_index
<0>, T1
{0});
103 constexpr V
v2(std::in_place_index
<1>, T2
{0});
104 assert(testOrder(v1
, v2
, Order::less
));
106 { // LHS.index() > RHS.index()
107 constexpr V
v1(std::in_place_index
<1>, T2
{0});
108 constexpr V
v2(std::in_place_index
<0>, T1
{0});
109 assert(testOrder(v1
, v2
, Order::greater
));
115 constexpr bool test_three_way() {
116 assert((test_with_types
<int, double, std::partial_ordering
>()));
117 assert((test_with_types
<int, long, std::strong_ordering
>()));
120 using V
= std::variant
<int, double>;
121 constexpr double nan
= std::numeric_limits
<double>::quiet_NaN();
123 constexpr V
v1(std::in_place_type
<int>, 1);
124 constexpr V
v2(std::in_place_type
<double>, nan
);
125 assert(testOrder(v1
, v2
, std::partial_ordering::less
));
128 constexpr V
v1(std::in_place_type
<double>, nan
);
129 constexpr V
v2(std::in_place_type
<int>, 2);
130 assert(testOrder(v1
, v2
, std::partial_ordering::greater
));
133 constexpr V
v1(std::in_place_type
<double>, nan
);
134 constexpr V
v2(std::in_place_type
<double>, nan
);
135 assert(testOrder(v1
, v2
, std::partial_ordering::unordered
));
143 template <class T
, class U
= T
>
144 concept has_three_way_op
= requires (T
& t
, U
& u
) { t
<=> u
; };
146 // std::three_way_comparable is a more stringent requirement that demands
147 // operator== and a few other things.
148 using std::three_way_comparable
;
150 struct HasSimpleOrdering
{
151 constexpr bool operator==(const HasSimpleOrdering
&) const;
152 constexpr bool operator<(const HasSimpleOrdering
&) const;
155 struct HasOnlySpaceship
{
156 constexpr bool operator==(const HasOnlySpaceship
&) const = delete;
157 constexpr std::weak_ordering
operator<=>(const HasOnlySpaceship
&) const;
160 struct HasFullOrdering
{
161 constexpr bool operator==(const HasFullOrdering
&) const;
162 constexpr std::weak_ordering
operator<=>(const HasFullOrdering
&) const;
165 // operator<=> must resolve the return types of all its union types'
166 // operator<=>s to determine its own return type, so it is detectable by SFINAE
167 static_assert(!has_three_way_op
<HasSimpleOrdering
>);
168 static_assert(!has_three_way_op
<std::variant
<int, HasSimpleOrdering
>>);
170 static_assert(!three_way_comparable
<HasSimpleOrdering
>);
171 static_assert(!three_way_comparable
<std::variant
<int, HasSimpleOrdering
>>);
173 static_assert(has_three_way_op
<HasOnlySpaceship
>);
174 static_assert(!has_three_way_op
<std::variant
<int, HasOnlySpaceship
>>);
176 static_assert(!three_way_comparable
<HasOnlySpaceship
>);
177 static_assert(!three_way_comparable
<std::variant
<int, HasOnlySpaceship
>>);
179 static_assert( has_three_way_op
<HasFullOrdering
>);
180 static_assert( has_three_way_op
<std::variant
<int, HasFullOrdering
>>);
182 static_assert( three_way_comparable
<HasFullOrdering
>);
183 static_assert( three_way_comparable
<std::variant
<int, HasFullOrdering
>>);
185 int main(int, char**) {
187 static_assert(test_three_way());
189 #ifndef TEST_HAS_NO_EXCEPTIONS
191 #endif // TEST_HAS_NO_EXCEPTIONS