326 lines · cpp
1//===----------------------------------------------------------------------===//2//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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++1410 11// <variant>12 13// template <class ...Types>14// constexpr bool15// operator==(variant<Types...> const&, variant<Types...> const&) noexcept;16//17// template <class ...Types>18// constexpr bool19// operator!=(variant<Types...> const&, variant<Types...> const&) noexcept;20//21// template <class ...Types>22// constexpr bool23// operator<(variant<Types...> const&, variant<Types...> const&) noexcept;24//25// template <class ...Types>26// constexpr bool27// operator>(variant<Types...> const&, variant<Types...> const&) noexcept;28//29// template <class ...Types>30// constexpr bool31// operator<=(variant<Types...> const&, variant<Types...> const&) noexcept;32//33// template <class ...Types>34// constexpr bool35// operator>=(variant<Types...> const&, variant<Types...> const&) noexcept;36 37#include <cassert>38#include <type_traits>39#include <utility>40#include <variant>41 42#include "test_comparisons.h"43#include "test_macros.h"44 45#if TEST_STD_VER >= 2646 47// Test SFINAE.48 49// ==50static_assert(HasOperatorEqual<std::variant<EqualityComparable>>);51static_assert(HasOperatorEqual<std::variant<EqualityComparable, int, long>>);52 53static_assert(!HasOperatorEqual<std::variant<NonComparable>>);54static_assert(!HasOperatorEqual<std::variant<NonComparable, EqualityComparable>>);55 56// >57static_assert(HasOperatorGreaterThan<std::variant<ThreeWayComparable>>);58static_assert(HasOperatorGreaterThan<std::variant<ThreeWayComparable, int, long>>);59 60static_assert(!HasOperatorGreaterThan<std::variant<NonComparable>>);61static_assert(!HasOperatorGreaterThan<std::variant<NonComparable, ThreeWayComparable>>);62 63// >=64static_assert(HasOperatorGreaterThanEqual<std::variant<ThreeWayComparable>>);65static_assert(HasOperatorGreaterThanEqual<std::variant<ThreeWayComparable, int, long>>);66 67static_assert(!HasOperatorGreaterThanEqual<std::variant<NonComparable>>);68static_assert(!HasOperatorGreaterThanEqual<std::variant<NonComparable, ThreeWayComparable>>);69 70// <71static_assert(HasOperatorLessThan<std::variant<ThreeWayComparable>>);72static_assert(HasOperatorLessThan<std::variant<ThreeWayComparable, int, long>>);73 74static_assert(!HasOperatorLessThan<std::variant<NonComparable>>);75static_assert(!HasOperatorLessThan<std::variant<NonComparable, ThreeWayComparable>>);76 77// <=78static_assert(HasOperatorLessThanEqual<std::variant<ThreeWayComparable>>);79static_assert(HasOperatorLessThanEqual<std::variant<ThreeWayComparable, int, long>>);80 81static_assert(!HasOperatorLessThanEqual<std::variant<NonComparable>>);82static_assert(!HasOperatorLessThanEqual<std::variant<NonComparable, ThreeWayComparable>>);83 84// !=85static_assert(HasOperatorNotEqual<std::variant<EqualityComparable>>);86static_assert(HasOperatorNotEqual<std::variant<EqualityComparable, int, long>>);87 88static_assert(!HasOperatorNotEqual<std::variant<NonComparable>>);89static_assert(!HasOperatorNotEqual<std::variant<NonComparable, EqualityComparable>>);90 91#endif92 93#ifndef TEST_HAS_NO_EXCEPTIONS94struct MakeEmptyT {95 MakeEmptyT() = default;96 MakeEmptyT(MakeEmptyT &&) { throw 42; }97 MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }98};99inline bool operator==(const MakeEmptyT &, const MakeEmptyT &) {100 assert(false);101 return false;102}103inline bool operator!=(const MakeEmptyT &, const MakeEmptyT &) {104 assert(false);105 return false;106}107inline bool operator<(const MakeEmptyT &, const MakeEmptyT &) {108 assert(false);109 return false;110}111inline bool operator<=(const MakeEmptyT &, const MakeEmptyT &) {112 assert(false);113 return false;114}115inline bool operator>(const MakeEmptyT &, const MakeEmptyT &) {116 assert(false);117 return false;118}119inline bool operator>=(const MakeEmptyT &, const MakeEmptyT &) {120 assert(false);121 return false;122}123 124template <class Variant> void makeEmpty(Variant &v) {125 Variant v2(std::in_place_type<MakeEmptyT>);126 try {127 v = std::move(v2);128 assert(false);129 } catch (...) {130 assert(v.valueless_by_exception());131 }132}133#endif // TEST_HAS_NO_EXCEPTIONS134 135struct MyBool {136 bool value;137 constexpr explicit MyBool(bool v) : value(v) {}138 constexpr operator bool() const noexcept { return value; }139};140 141struct ComparesToMyBool {142 int value = 0;143};144inline constexpr MyBool operator==(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {145 return MyBool(LHS.value == RHS.value);146}147inline constexpr MyBool operator!=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {148 return MyBool(LHS.value != RHS.value);149}150inline constexpr MyBool operator<(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {151 return MyBool(LHS.value < RHS.value);152}153inline constexpr MyBool operator<=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {154 return MyBool(LHS.value <= RHS.value);155}156inline constexpr MyBool operator>(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {157 return MyBool(LHS.value > RHS.value);158}159inline constexpr MyBool operator>=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {160 return MyBool(LHS.value >= RHS.value);161}162 163template <class T1, class T2>164void test_equality_basic() {165 {166 using V = std::variant<T1, T2>;167 constexpr V v1(std::in_place_index<0>, T1{42});168 constexpr V v2(std::in_place_index<0>, T1{42});169 static_assert(v1 == v2, "");170 static_assert(v2 == v1, "");171 static_assert(!(v1 != v2), "");172 static_assert(!(v2 != v1), "");173 }174 {175 using V = std::variant<T1, T2>;176 constexpr V v1(std::in_place_index<0>, T1{42});177 constexpr V v2(std::in_place_index<0>, T1{43});178 static_assert(!(v1 == v2), "");179 static_assert(!(v2 == v1), "");180 static_assert(v1 != v2, "");181 static_assert(v2 != v1, "");182 }183 {184 using V = std::variant<T1, T2>;185 constexpr V v1(std::in_place_index<0>, T1{42});186 constexpr V v2(std::in_place_index<1>, T2{42});187 static_assert(!(v1 == v2), "");188 static_assert(!(v2 == v1), "");189 static_assert(v1 != v2, "");190 static_assert(v2 != v1, "");191 }192 {193 using V = std::variant<T1, T2>;194 constexpr V v1(std::in_place_index<1>, T2{42});195 constexpr V v2(std::in_place_index<1>, T2{42});196 static_assert(v1 == v2, "");197 static_assert(v2 == v1, "");198 static_assert(!(v1 != v2), "");199 static_assert(!(v2 != v1), "");200 }201}202 203void test_equality() {204 test_equality_basic<int, long>();205 test_equality_basic<ComparesToMyBool, int>();206 test_equality_basic<int, ComparesToMyBool>();207 test_equality_basic<ComparesToMyBool, ComparesToMyBool>();208#ifndef TEST_HAS_NO_EXCEPTIONS209 {210 using V = std::variant<int, MakeEmptyT>;211 V v1;212 V v2;213 makeEmpty(v2);214 assert(!(v1 == v2));215 assert(!(v2 == v1));216 assert(v1 != v2);217 assert(v2 != v1);218 }219 {220 using V = std::variant<int, MakeEmptyT>;221 V v1;222 makeEmpty(v1);223 V v2;224 assert(!(v1 == v2));225 assert(!(v2 == v1));226 assert(v1 != v2);227 assert(v2 != v1);228 }229 {230 using V = std::variant<int, MakeEmptyT>;231 V v1;232 makeEmpty(v1);233 V v2;234 makeEmpty(v2);235 assert(v1 == v2);236 assert(v2 == v1);237 assert(!(v1 != v2));238 assert(!(v2 != v1));239 }240#endif241}242 243template <class Var>244constexpr bool test_less(const Var &l, const Var &r, bool expect_less,245 bool expect_greater) {246 static_assert(std::is_same_v<decltype(l < r), bool>, "");247 static_assert(std::is_same_v<decltype(l <= r), bool>, "");248 static_assert(std::is_same_v<decltype(l > r), bool>, "");249 static_assert(std::is_same_v<decltype(l >= r), bool>, "");250 251 return ((l < r) == expect_less) && (!(l >= r) == expect_less) &&252 ((l > r) == expect_greater) && (!(l <= r) == expect_greater);253}254 255template <class T1, class T2>256void test_relational_basic() {257 { // same index, same value258 using V = std::variant<T1, T2>;259 constexpr V v1(std::in_place_index<0>, T1{1});260 constexpr V v2(std::in_place_index<0>, T1{1});261 static_assert(test_less(v1, v2, false, false), "");262 }263 { // same index, value < other_value264 using V = std::variant<T1, T2>;265 constexpr V v1(std::in_place_index<0>, T1{0});266 constexpr V v2(std::in_place_index<0>, T1{1});267 static_assert(test_less(v1, v2, true, false), "");268 }269 { // same index, value > other_value270 using V = std::variant<T1, T2>;271 constexpr V v1(std::in_place_index<0>, T1{1});272 constexpr V v2(std::in_place_index<0>, T1{0});273 static_assert(test_less(v1, v2, false, true), "");274 }275 { // LHS.index() < RHS.index()276 using V = std::variant<T1, T2>;277 constexpr V v1(std::in_place_index<0>, T1{0});278 constexpr V v2(std::in_place_index<1>, T2{0});279 static_assert(test_less(v1, v2, true, false), "");280 }281 { // LHS.index() > RHS.index()282 using V = std::variant<T1, T2>;283 constexpr V v1(std::in_place_index<1>, T2{0});284 constexpr V v2(std::in_place_index<0>, T1{0});285 static_assert(test_less(v1, v2, false, true), "");286 }287}288 289void test_relational() {290 test_relational_basic<int, long>();291 test_relational_basic<ComparesToMyBool, int>();292 test_relational_basic<int, ComparesToMyBool>();293 test_relational_basic<ComparesToMyBool, ComparesToMyBool>();294#ifndef TEST_HAS_NO_EXCEPTIONS295 { // LHS.index() < RHS.index(), RHS is empty296 using V = std::variant<int, MakeEmptyT>;297 V v1;298 V v2;299 makeEmpty(v2);300 assert(test_less(v1, v2, false, true));301 }302 { // LHS.index() > RHS.index(), LHS is empty303 using V = std::variant<int, MakeEmptyT>;304 V v1;305 makeEmpty(v1);306 V v2;307 assert(test_less(v1, v2, true, false));308 }309 { // LHS.index() == RHS.index(), LHS and RHS are empty310 using V = std::variant<int, MakeEmptyT>;311 V v1;312 makeEmpty(v1);313 V v2;314 makeEmpty(v2);315 assert(test_less(v1, v2, false, false));316 }317#endif318}319 320int main(int, char**) {321 test_equality();322 test_relational();323 324 return 0;325}326