369 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// <tuple>10 11// template <class... Types> class tuple;12 13// template<class... TTypes, class... UTypes>14// auto15// operator<=>(const tuple<TTypes...>& t, const tuple<UTypes...>& u);16// template<tuple-like UTuple>17// friend constexpr auto operator<=>(const tuple& t, const UTuple& u); // since C++2318 19// UNSUPPORTED: c++03, c++11, c++14, c++1720 21#include "test_macros.h"22 23TEST_CLANG_DIAGNOSTIC_IGNORED("-Wsign-compare")24TEST_GCC_DIAGNOSTIC_IGNORED("-Wsign-compare")25TEST_MSVC_DIAGNOSTIC_IGNORED(4242 4244)26 27#include <array>28#include <cassert>29#include <compare>30#include <complex>31#include <limits>32#include <ranges>33#include <tuple>34#include <type_traits> // std::is_constant_evaluated35#include <utility>36 37// A custom three-way result type38struct CustomEquality {39 friend constexpr bool operator==(const CustomEquality&, int) noexcept { return true; }40 friend constexpr bool operator<(const CustomEquality&, int) noexcept { return false; }41 friend constexpr bool operator<(int, const CustomEquality&) noexcept { return false; }42};43 44constexpr bool test() {45 struct WeakSpaceship {46 constexpr bool operator==(const WeakSpaceship&) const { return true; }47 constexpr std::weak_ordering operator<=>(const WeakSpaceship&) const { return std::weak_ordering::equivalent; }48 };49 50 // Empty tuple51 {52 typedef std::tuple<> T0;53 // No member types yields strong ordering (all are equal).54 ASSERT_SAME_TYPE(decltype(T0() <=> T0()), std::strong_ordering);55 assert((T0() <=> T0()) == std::strong_ordering::equal);56 }57 // Mixed types with integers, which compare strongly ordered58 {59 typedef std::tuple<long> T1;60 typedef std::tuple<short> T2;61 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::strong_ordering);62 assert((T1(1) <=> T2(1)) == std::strong_ordering::equal);63 assert((T1(1) <=> T2(0)) == std::strong_ordering::greater);64 assert((T1(1) <=> T2(2)) == std::strong_ordering::less);65 }66 {67 typedef std::tuple<long, unsigned int> T1;68 typedef std::tuple<short, unsigned long> T2;69 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::strong_ordering);70 assert((T1(1, 2) <=> T2(1, 2)) == std::strong_ordering::equal);71 assert((T1(1, 2) <=> T2(0, 2)) == std::strong_ordering::greater);72 assert((T1(1, 2) <=> T2(2, 2)) == std::strong_ordering::less);73 assert((T1(1, 2) <=> T2(1, 1)) == std::strong_ordering::greater);74 assert((T1(1, 2) <=> T2(1, 3)) == std::strong_ordering::less);75 }76 {77 typedef std::tuple<long, int, unsigned short> T1;78 typedef std::tuple<short, long, unsigned int> T2;79 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::strong_ordering);80 assert((T1(1, 2, 3) <=> T2(1, 2, 3)) == std::strong_ordering::equal);81 assert((T1(1, 2, 3) <=> T2(0, 2, 3)) == std::strong_ordering::greater);82 assert((T1(1, 2, 3) <=> T2(2, 2, 3)) == std::strong_ordering::less);83 assert((T1(1, 2, 3) <=> T2(1, 1, 3)) == std::strong_ordering::greater);84 assert((T1(1, 2, 3) <=> T2(1, 3, 3)) == std::strong_ordering::less);85 assert((T1(1, 2, 3) <=> T2(1, 2, 2)) == std::strong_ordering::greater);86 assert((T1(1, 2, 3) <=> T2(1, 2, 4)) == std::strong_ordering::less);87 }88 // Mixed types with floating point, which compare partially ordered89 {90 typedef std::tuple<long> T1;91 typedef std::tuple<double> T2;92 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering);93 assert((T1(1) <=> T2(1)) == std::partial_ordering::equivalent);94 assert((T1(1) <=> T2(0.9)) == std::partial_ordering::greater);95 assert((T1(1) <=> T2(1.1)) == std::partial_ordering::less);96 }97 {98 typedef std::tuple<long, float> T1;99 typedef std::tuple<double, unsigned int> T2;100 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering);101 assert((T1(1, 2) <=> T2(1, 2)) == std::partial_ordering::equivalent);102 assert((T1(1, 2) <=> T2(0.9, 2)) == std::partial_ordering::greater);103 assert((T1(1, 2) <=> T2(1.1, 2)) == std::partial_ordering::less);104 assert((T1(1, 2) <=> T2(1, 1)) == std::partial_ordering::greater);105 assert((T1(1, 2) <=> T2(1, 3)) == std::partial_ordering::less);106 }107 {108 typedef std::tuple<short, float, double> T1;109 typedef std::tuple<double, long, unsigned int> T2;110 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering);111 assert((T1(1, 2, 3) <=> T2(1, 2, 3)) == std::partial_ordering::equivalent);112 assert((T1(1, 2, 3) <=> T2(0.9, 2, 3)) == std::partial_ordering::greater);113 assert((T1(1, 2, 3) <=> T2(1.1, 2, 3)) == std::partial_ordering::less);114 assert((T1(1, 2, 3) <=> T2(1, 1, 3)) == std::partial_ordering::greater);115 assert((T1(1, 2, 3) <=> T2(1, 3, 3)) == std::partial_ordering::less);116 assert((T1(1, 2, 3) <=> T2(1, 2, 2)) == std::partial_ordering::greater);117 assert((T1(1, 2, 3) <=> T2(1, 2, 4)) == std::partial_ordering::less);118 }119 {120 typedef std::tuple<float> T1;121 typedef std::tuple<double> T2;122 constexpr double nan = std::numeric_limits<double>::quiet_NaN();123 // Comparisons with NaN and non-NaN are non-constexpr in GCC, so both sides must be NaN124 assert((T1(nan) <=> T2(nan)) == std::partial_ordering::unordered);125 }126 {127 typedef std::tuple<double, double> T1;128 typedef std::tuple<float, float> T2;129 constexpr double nan = std::numeric_limits<double>::quiet_NaN();130 assert((T1(nan, 2) <=> T2(nan, 2)) == std::partial_ordering::unordered);131 assert((T1(1, nan) <=> T2(1, nan)) == std::partial_ordering::unordered);132 }133 {134 typedef std::tuple<double, float, float> T1;135 typedef std::tuple<double, double, float> T2;136 constexpr double nan = std::numeric_limits<double>::quiet_NaN();137 assert((T1(nan, 2, 3) <=> T2(nan, 2, 3)) == std::partial_ordering::unordered);138 assert((T1(1, nan, 3) <=> T2(1, nan, 3)) == std::partial_ordering::unordered);139 assert((T1(1, 2, nan) <=> T2(1, 2, nan)) == std::partial_ordering::unordered);140 }141 // Ordering classes and synthesized three way comparison142 {143 typedef std::tuple<long, int, unsigned int> T1;144 typedef std::tuple<int, long, unsigned short> T2;145 // All strongly ordered members yields strong ordering.146 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::strong_ordering);147 }148 {149 typedef std::tuple<int, unsigned int, WeakSpaceship> T1;150 typedef std::tuple<int, unsigned long, WeakSpaceship> T2;151 // Strongly ordered members and a weakly ordered member yields weak ordering.152 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering);153 }154 {155 typedef std::tuple<unsigned int, int, WeakSpaceship> T1;156 typedef std::tuple<double, long, WeakSpaceship> T2;157 // Doubles are partially ordered, so one partial, one strong, and one weak ordering158 // yields partial ordering.159 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering);160 }161 {162 struct NoSpaceship {163 constexpr bool operator==(const NoSpaceship&) const { return true; }164 constexpr bool operator<(const NoSpaceship&) const { return false; }165 };166 typedef std::tuple<int, unsigned int, NoSpaceship> T1;167 typedef std::tuple<int, unsigned long, NoSpaceship> T2;168 // Strongly ordered members and a weakly ordered member (synthesized) yields weak ordering.169 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering);170 }171 {172 struct SpaceshipNoEquals {173 constexpr std::strong_ordering operator<=>(const SpaceshipNoEquals&) const { return std::strong_ordering::equal; }174 constexpr bool operator<(const SpaceshipNoEquals&) const { return false; }175 };176 typedef std::tuple<int, unsigned int, SpaceshipNoEquals> T1;177 typedef std::tuple<int, unsigned long, SpaceshipNoEquals> T2;178 // Spaceship operator with no == operator falls back on the < operator and weak ordering.179 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering);180 }181 {182 struct CustomSpaceship {183 constexpr CustomEquality operator<=>(const CustomSpaceship&) const { return CustomEquality(); }184 };185 typedef std::tuple<int, unsigned int, CustomSpaceship> T1;186 typedef std::tuple<short, unsigned long, CustomSpaceship> T2;187 typedef std::tuple<CustomSpaceship> T3;188 // Custom three way return types cannot be used in synthesized three way comparison,189 // but they can be used for (rewritten) operator< when synthesizing a weak ordering.190 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering);191 ASSERT_SAME_TYPE(decltype(T3() <=> T3()), std::weak_ordering);192 }193 {194 typedef std::tuple<long, int> T1;195 typedef std::tuple<long, unsigned int> T2;196 // Even with the warning suppressed (-Wno-sign-compare) there should still be no <=> operator197 // between signed and unsigned types, so we should end up with a synthesized weak ordering.198 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering);199 }200 201#ifdef TEST_COMPILER_GCC202 // GCC cannot evaluate NaN @ non-NaN constexpr, so test that runtime-only.203 if (!std::is_constant_evaluated())204#endif205 {206 {207 typedef std::tuple<double> T1;208 typedef std::tuple<int> T2;209 constexpr double nan = std::numeric_limits<double>::quiet_NaN();210 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering);211 assert((T1(nan) <=> T2(1)) == std::partial_ordering::unordered);212 }213 {214 typedef std::tuple<double, double> T1;215 typedef std::tuple<int, int> T2;216 constexpr double nan = std::numeric_limits<double>::quiet_NaN();217 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering);218 assert((T1(nan, 2) <=> T2(1, 2)) == std::partial_ordering::unordered);219 assert((T1(1, nan) <=> T2(1, 2)) == std::partial_ordering::unordered);220 }221 {222 typedef std::tuple<double, double, double> T1;223 typedef std::tuple<int, int, int> T2;224 constexpr double nan = std::numeric_limits<double>::quiet_NaN();225 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering);226 assert((T1(nan, 2, 3) <=> T2(1, 2, 3)) == std::partial_ordering::unordered);227 assert((T1(1, nan, 3) <=> T2(1, 2, 3)) == std::partial_ordering::unordered);228 assert((T1(1, 2, nan) <=> T2(1, 2, 3)) == std::partial_ordering::unordered);229 }230 }231 232// Heterogeneous comparisons enabled by P2165R4.233#if TEST_STD_VER >= 23234 {235 using T1 = std::tuple<long, int>;236 using T2 = std::pair<int, long>;237 constexpr T1 t1{1, 2};238 constexpr T2 t2{1, 2};239 ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering);240 assert((t1 <=> t2) == std::strong_ordering::equal);241 }242 {243 using T1 = std::tuple<long, int>;244 using T2 = std::pair<int, long>;245 constexpr T1 t1{1, 2};246 constexpr T2 t2{1, 0};247 ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering);248 assert((t1 <=> t2) == std::strong_ordering::greater);249 }250 {251 using T1 = std::tuple<long, int>;252 using T2 = std::pair<double, long>;253 constexpr T1 t1{1, 2};254 constexpr T2 t2{1.1, 3};255 ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering);256 assert((t1 <=> t2) == std::partial_ordering::less);257 }258 {259 using T1 = std::tuple<long, int>;260 using T2 = std::pair<double, long>;261 constexpr T1 t1{1, 2};262 constexpr T2 t2{1.0, 2};263 ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering);264 assert((t1 <=> t2) == std::partial_ordering::equivalent);265 }266 {267 using T1 = std::tuple<long, int>;268 using T2 = std::pair<double, long>;269 constexpr T1 t1{1, 2};270 constexpr T2 t2{1.1, 3};271 ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering);272 assert((t1 <=> t2) == std::partial_ordering::less);273 }274 {275 using T1 = std::tuple<long, int>;276 using T2 = std::array<double, 2>;277 constexpr T1 t1{1, 2};278 constexpr T2 t2{1.0, 2.0};279 ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering);280 assert((t1 <=> t2) == std::partial_ordering::equivalent);281 }282 {283 using T1 = std::tuple<long, int>;284 using T2 = std::array<double, 2>;285 constexpr T1 t1{1, 2};286 constexpr T2 t2{1.1, 3.0};287 ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering);288 assert((t1 <=> t2) == std::partial_ordering::less);289 }290 {291 using T1 = std::tuple<const int*, const int*>;292 using T2 = std::ranges::subrange<const int*>;293 294 int arr[1]{};295 T1 t1{arr, arr + 1};296 T2 t2{arr};297 ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering);298 assert((t1 <=> t2) == std::strong_ordering::equal);299 }300 {301 using T1 = std::tuple<const int*, const int*>;302 using T2 = std::ranges::subrange<const int*>;303 304 int arr[1]{};305 T1 t1{arr + 1, arr + 1};306 T2 t2{arr};307 ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering);308 assert((t1 <=> t2) == std::strong_ordering::greater);309 }310 {311 constexpr std::tuple<WeakSpaceship, WeakSpaceship> t1{};312 constexpr std::pair<WeakSpaceship, WeakSpaceship> t2{};313 ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::weak_ordering);314 assert((t1 <=> t2) == std::weak_ordering::equivalent);315 }316 {317 constexpr std::tuple<WeakSpaceship, WeakSpaceship> t1{};318 constexpr std::array<WeakSpaceship, 2> t2{};319 ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::weak_ordering);320 assert((t1 <=> t2) == std::weak_ordering::equivalent);321 }322 {323 constexpr std::tuple<> t1{};324 constexpr std::array<int*, 0> t2{};325 ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering);326 assert((t1 <=> t2) == std::strong_ordering::equal);327 }328 {329 constexpr std::tuple<> t1{};330 constexpr std::array<double, 0> t2{};331 ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering);332 assert((t1 <=> t2) == std::strong_ordering::equal);333 }334 {335 constexpr std::tuple<> t1{};336 constexpr std::array<WeakSpaceship, 0> t2{};337 ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::strong_ordering);338 assert((t1 <=> t2) == std::strong_ordering::equal);339 }340#endif341#if TEST_STD_VER >= 26342 {343 using T1 = std::tuple<long, int>;344 using T2 = std::complex<double>;345 constexpr T1 t1{1, 2};346 constexpr T2 t2{1.0, 2.0};347 ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering);348 assert((t1 <=> t2) == std::partial_ordering::equivalent);349 }350 {351 using T1 = std::tuple<long, int>;352 using T2 = std::complex<double>;353 constexpr T1 t1{1, 2};354 constexpr T2 t2{1.1, 3.0};355 ASSERT_SAME_TYPE(decltype(t1 <=> t2), std::partial_ordering);356 assert((t1 <=> t2) == std::partial_ordering::less);357 }358#endif359 360 return true;361}362 363int main(int, char**) {364 test();365 static_assert(test());366 367 return 0;368}369