From: Jonathan Wakely Date: Wed, 13 Nov 2019 16:26:18 +0000 (+0000) Subject: libsupc++: Implement comparison algorithms for C++20 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0ff15d21c8602ad78129c0a6baab821c4090de71;p=gcc.git libsupc++: Implement comparison algorithms for C++20 This is incomplete because std::strong_order doesn't support floating-point types. The partial_order and weak_order tests use VERIFY instead of static_assert because of PR 92431. * libsupc++/compare (strong_order, weak_order, partial_order) (compare_strong_order_fallback, compare_weak_order_fallback) (compare_partial_order_fallback): Define customization point objects for C++20. * testsuite/18_support/comparisons/algorithms/partial_order.cc: New test. * testsuite/18_support/comparisons/algorithms/strong_order.cc: New test. * testsuite/18_support/comparisons/algorithms/weak_order.cc: New test. From-SVN: r278149 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index f48c291f406..b073c688187 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,15 @@ +2019-11-13 Jonathan Wakely + + * libsupc++/compare (strong_order, weak_order, partial_order) + (compare_strong_order_fallback, compare_weak_order_fallback) + (compare_partial_order_fallback): Define customization point objects + for C++20. + * testsuite/18_support/comparisons/algorithms/partial_order.cc: New + test. + * testsuite/18_support/comparisons/algorithms/strong_order.cc: New + test. + * testsuite/18_support/comparisons/algorithms/weak_order.cc: New test. + 2019-11-11 Gerald Pfeifer * doc/xml/gnu/gpl-3.0.xml: Adjust link to "Why not LGPL". diff --git a/libstdc++-v3/libsupc++/compare b/libstdc++-v3/libsupc++/compare index 94728e29de8..289145dea56 100644 --- a/libstdc++-v3/libsupc++/compare +++ b/libstdc++-v3/libsupc++/compare @@ -576,20 +576,346 @@ namespace std using is_transparent = void; }; + namespace __cmp_cust + { + template + constexpr weak_ordering + __fp_weak_ordering(_Tp __e, _Tp __f) + { + // Returns an integer with the same sign as the argument, and magnitude + // indicating the classification: zero=1 subnorm=2 norm=3 inf=4 nan=5 + auto __cat = [](_Tp __fp) -> int { + const int __sign = __builtin_signbit(__fp) ? -1 : 1; + if (__builtin_isnormal(__fp)) + return (__fp == 0 ? 1 : 3) * __sign; + if (__builtin_isnan(__fp)) + return 5 * __sign; + if (int __inf = __builtin_isinf_sign(__fp)) + return 4 * __inf; + return 2 * __sign; + }; + + auto __po = __e <=> __f; + if (is_lt(__po)) + return weak_ordering::less; + else if (is_gt(__po)) + return weak_ordering::greater; + else if (__po == partial_ordering::equivalent) + return weak_ordering::equivalent; + else // unordered, at least one argument is NaN + { + // return -1 for negative nan, +1 for positive nan, 0 otherwise. + auto __isnan_sign = [](_Tp __fp) -> int { + return __builtin_isnan(__fp) + ? __builtin_signbit(__fp) ? -1 : 1 + : 0; + }; + auto __ord = __isnan_sign(__e) <=> __isnan_sign(__f); + if (is_eq(__ord)) + return weak_ordering::equivalent; + else if (is_lt(__ord)) + return weak_ordering::less; + else + return weak_ordering::greater; + } + } + + template + concept __adl_strong = requires(_Tp&& __t, _Up&& __u) + { + strong_ordering(strong_order(static_cast<_Tp&&>(__t), + static_cast<_Up&&>(__u))); + }; + + template + concept __adl_weak = requires(_Tp&& __t, _Up&& __u) + { + weak_ordering(weak_order(static_cast<_Tp&&>(__t), + static_cast<_Up&&>(__u))); + }; + + template + concept __adl_partial = requires(_Tp&& __t, _Up&& __u) + { + partial_ordering(partial_order(static_cast<_Tp&&>(__t), + static_cast<_Up&&>(__u))); + }; + + template + concept __op_cmp = requires(_Tp&& __t, _Up&& __u) + { + _Ord(static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u)); + }; + + template + concept __strongly_ordered + = __adl_strong<_Tp, _Up> + // FIXME: || floating_point> + || __op_cmp; + + class _Strong_order + { + template + static constexpr bool + _S_noexcept() + { + if constexpr (floating_point>) + return true; + else if constexpr (__adl_strong<_Tp, _Up>) + return noexcept(strong_ordering(strong_order(std::declval<_Tp>(), + std::declval<_Up>()))); + else if constexpr (__op_cmp) + return noexcept(std::declval<_Tp>() <=> std::declval<_Up>()); + } + + friend class _Weak_order; + friend class _Strong_fallback; + + public: + template + requires __strongly_ordered<_Tp, _Up> + constexpr strong_ordering + operator()(_Tp&& __e, _Up&& __f) const + noexcept(_S_noexcept<_Tp, _Up>()) + { + static_assert(same_as, decay_t<_Up>>); + + /* FIXME: + if constexpr (floating_point>) + return __cmp_cust::__fp_strong_order(__e, __f); + else */ if constexpr (__adl_strong<_Tp, _Up>) + return strong_ordering(strong_order(static_cast<_Tp&&>(__e), + static_cast<_Up&&>(__f))); + else if constexpr (__op_cmp) + return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f); + } + }; + + template + concept __weakly_ordered + = floating_point> + || __adl_weak<_Tp, _Up> + || __op_cmp + || __strongly_ordered<_Tp, _Up>; + + class _Weak_order + { + template + static constexpr bool + _S_noexcept() + { + if constexpr (floating_point>) + return true; + else if constexpr (__adl_weak<_Tp, _Up>) + return noexcept(weak_ordering(weak_order(std::declval<_Tp>(), + std::declval<_Up>()))); + else if constexpr (__op_cmp) + return noexcept(std::declval<_Tp>() <=> std::declval<_Up>()); + else if constexpr (__strongly_ordered<_Tp, _Up>) + return _Strong_order::_S_noexcept<_Tp, _Up>(); + } + + friend class _Partial_order; + friend class _Weak_fallback; + + public: + template + requires __weakly_ordered<_Tp, _Up> + constexpr weak_ordering + operator()(_Tp&& __e, _Up&& __f) const + noexcept(_S_noexcept<_Tp, _Up>()) + { + static_assert(same_as, decay_t<_Up>>); + + if constexpr (floating_point>) + return __cmp_cust::__fp_weak_ordering(__e, __f); + else if constexpr (__adl_weak<_Tp, _Up>) + return weak_ordering(weak_order(static_cast<_Tp&&>(__e), + static_cast<_Up&&>(__f))); + else if constexpr (__op_cmp) + return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f); + else if constexpr (__strongly_ordered<_Tp, _Up>) + return _Strong_order{}(static_cast<_Tp&&>(__e), + static_cast<_Up&&>(__f)); + } + }; + + template + concept __partially_ordered + = __adl_partial<_Tp, _Up> + || __op_cmp + || __weakly_ordered<_Tp, _Up>; + + class _Partial_order + { + template + static constexpr bool + _S_noexcept() + { + if constexpr (__adl_partial<_Tp, _Up>) + return noexcept(partial_ordering(partial_order(std::declval<_Tp>(), + std::declval<_Up>()))); + else if constexpr (__op_cmp) + return noexcept(std::declval<_Tp>() <=> std::declval<_Up>()); + else if constexpr (__weakly_ordered<_Tp, _Up>) + return _Weak_order::_S_noexcept<_Tp, _Up>(); + } + + friend class _Partial_fallback; + + public: + template + requires __partially_ordered<_Tp, _Up> + constexpr partial_ordering + operator()(_Tp&& __e, _Up&& __f) const + noexcept(_S_noexcept<_Tp, _Up>()) + { + static_assert(same_as, decay_t<_Up>>); + + if constexpr (__adl_partial<_Tp, _Up>) + return partial_ordering(partial_order(static_cast<_Tp&&>(__e), + static_cast<_Up&&>(__f))); + else if constexpr (__op_cmp) + return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f); + else if constexpr (__weakly_ordered<_Tp, _Up>) + return _Weak_order{}(static_cast<_Tp&&>(__e), + static_cast<_Up&&>(__f)); + } + }; + + template + concept __op_eq_lt = requires(_Tp&& __t, _Up&& __u) + { + { static_cast<_Tp&&>(__t) == static_cast<_Up&&>(__u) } + -> convertible_to; + { static_cast<_Tp&&>(__t) < static_cast<_Up&&>(__u) } + -> convertible_to; + }; + + class _Strong_fallback + { + template + static constexpr bool + _S_noexcept() + { + if constexpr (__strongly_ordered<_Tp, _Up>) + return _Strong_order::_S_noexcept<_Tp, _Up>(); + else + return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) + && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); + } + + public: + template + requires __strongly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up> + constexpr decltype(auto) + operator()(_Tp&& __e, _Up&& __f) const + noexcept(_S_noexcept<_Tp, _Up>()) + { + static_assert(same_as, decay_t<_Up>>); + + if constexpr (__strongly_ordered<_Tp, _Up>) + return _Strong_order{}(static_cast<_Tp&&>(__e), + static_cast<_Up&&>(__f)); + else if constexpr (__op_eq_lt<_Tp, _Up>) + return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) + ? strong_ordering::equal + : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) + ? strong_ordering::less + : strong_ordering::greater; + } + }; + + class _Weak_fallback + { + template + static constexpr bool + _S_noexcept() + { + if constexpr (__weakly_ordered<_Tp, _Up>) + return _Weak_order::_S_noexcept<_Tp, _Up>(); + else + return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) + && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); + } + + public: + template + requires __weakly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up> + constexpr decltype(auto) + operator()(_Tp&& __e, _Up&& __f) const + noexcept(_S_noexcept<_Tp, _Up>()) + { + static_assert(same_as, decay_t<_Up>>); + + if constexpr (__weakly_ordered<_Tp, _Up>) + return _Weak_order{}(static_cast<_Tp&&>(__e), + static_cast<_Up&&>(__f)); + else if constexpr (__op_eq_lt<_Tp, _Up>) + return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) + ? weak_ordering::equivalent + : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) + ? weak_ordering::less + : weak_ordering::greater; + } + }; + + class _Partial_fallback + { + template + static constexpr bool + _S_noexcept() + { + if constexpr (__partially_ordered<_Tp, _Up>) + return _Partial_order::_S_noexcept<_Tp, _Up>(); + else + return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) + && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); + } + + public: + template + requires __partially_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up> + constexpr decltype(auto) + operator()(_Tp&& __e, _Up&& __f) const + noexcept(_S_noexcept<_Tp, _Up>()) + { + static_assert(same_as, decay_t<_Up>>); + + if constexpr (__partially_ordered<_Tp, _Up>) + return _Partial_order{}(static_cast<_Tp&&>(__e), + static_cast<_Up&&>(__f)); + else if constexpr (__op_eq_lt<_Tp, _Up>) + return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) + ? partial_ordering::equivalent + : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) + ? partial_ordering::less + : static_cast<_Up&&>(__f) < static_cast<_Tp&&>(__e) + ? partial_ordering::greater + : partial_ordering::unordered; + } + }; + } // namespace __cmp_cust + // [cmp.alg], comparison algorithms inline namespace __cmp_alg { - // TODO -#if 0 - inline constexpr unspecified strong_order = unspecified; - inline constexpr unspecified weak_order = unspecified; - inline constexpr unspecified partial_order = unspecified; - inline constexpr unspecified compare_strong_order_fallback = unspecified; - inline constexpr unspecified compare_weak_order_fallback = unspecified; - inline constexpr unspecified compare_partial_order_fallback = unspecified; -#endif + inline constexpr __cmp_cust::_Strong_order strong_order{}; + + inline constexpr __cmp_cust::_Weak_order weak_order{}; + + inline constexpr __cmp_cust::_Partial_order partial_order{}; + + inline constexpr __cmp_cust::_Strong_fallback + compare_strong_order_fallback{}; + + inline constexpr __cmp_cust::_Weak_fallback + compare_weak_order_fallback{}; + + inline constexpr __cmp_cust::_Partial_fallback + compare_partial_order_fallback{}; } -#endif +#endif // concepts } // namespace std #pragma GCC visibility pop diff --git a/libstdc++-v3/testsuite/18_support/comparisons/algorithms/partial_order.cc b/libstdc++-v3/testsuite/18_support/comparisons/algorithms/partial_order.cc new file mode 100644 index 00000000000..ec85996e16d --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/comparisons/algorithms/partial_order.cc @@ -0,0 +1,118 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +using std::partial_order; +using std::partial_ordering; + +void +test01() +{ + int one = 1, two = 2; + + VERIFY( partial_order(one, two) == partial_ordering::less ); + VERIFY( partial_order(one, one) == partial_ordering::equivalent ); + VERIFY( partial_order(two, one) == partial_ordering::greater ); + static_assert( noexcept(partial_order(1, 1)) ); +} + +constexpr partial_ordering different_cv_quals(int i, const int j) +{ + return partial_order(i, j); +} + +void +test02() +{ + int fortytwo = 42, nines = 999, lots = 1000; + VERIFY( different_cv_quals(fortytwo, nines) == partial_ordering::less ); + VERIFY( different_cv_quals(-nines, -nines) == partial_ordering::equivalent ); + VERIFY( different_cv_quals(-nines, -lots) == partial_ordering::greater ); +} + +void +test03() +{ + double zero = 0.0; + VERIFY( partial_order(zero, zero) == partial_ordering::equivalent ); + VERIFY( partial_order(-zero, -zero) == partial_ordering::equivalent ); + VERIFY( partial_order(-zero, zero) == partial_ordering::equivalent ); + VERIFY( partial_order(zero, -zero) == partial_ordering::equivalent ); + static_assert( noexcept(partial_order(zero, 1.0)) ); + static_assert( partial_order(0.0, 1.0) == std::partial_ordering::less ); + + double min = std::numeric_limits::lowest(); + double max = std::numeric_limits::max(); + double nan = std::numeric_limits::quiet_NaN(); + double inf = std::numeric_limits::infinity(); + double denorm = std::numeric_limits::denorm_min(); + double smallest = std::numeric_limits::min(); + double epsilon = std::numeric_limits::epsilon(); + VERIFY( partial_order(denorm, smallest) == partial_ordering::less ); + VERIFY( partial_order(denorm, 0.0) == partial_ordering::greater ); + VERIFY( partial_order(0.0, nan) == partial_ordering::unordered ); + VERIFY( partial_order(nan, nan) == partial_ordering::unordered ); + VERIFY( partial_order(nan, 0.0) == partial_ordering::unordered ); + VERIFY( partial_order(-nan, 0.0) == partial_ordering::unordered ); + VERIFY( partial_order(-nan, min) == partial_ordering::unordered ); + VERIFY( partial_order(-inf, min) == partial_ordering::less ); + VERIFY( partial_order(-nan, -inf) == partial_ordering::unordered ); + VERIFY( partial_order(-inf, -nan) == partial_ordering::unordered ); + VERIFY( partial_order(max, inf) == partial_ordering::less ); + VERIFY( partial_order(inf, max) == partial_ordering::greater ); + VERIFY( partial_order(inf, nan) == partial_ordering::unordered ); + VERIFY( partial_order(1.0, 1.0+epsilon) == partial_ordering::less ); +} + +namespace N +{ + struct X { int i; }; + + constexpr partial_ordering operator<=>(X l, X r) + { + if (l.i < 0 && r.i < 0) + return partial_ordering::equivalent; + return r.i <=> l.i; + } +} + +void +test04() +{ + using N::X; + X one{1}; + X negone{-1}; + + VERIFY( partial_order(one, X{1}) == partial_ordering::equivalent ); + VERIFY( partial_order(negone, X{-2}) == partial_ordering::equivalent ); + VERIFY( partial_order(one, X{2}) == partial_ordering::greater ); + static_assert( !noexcept(partial_order(X{1}, X{2})) ); +} + +int main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/18_support/comparisons/algorithms/strong_order.cc b/libstdc++-v3/testsuite/18_support/comparisons/algorithms/strong_order.cc new file mode 100644 index 00000000000..2c813494ce7 --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/comparisons/algorithms/strong_order.cc @@ -0,0 +1,56 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include +#include + +using std::strong_order; +using std::strong_ordering; + +static_assert( strong_order(1, 2) == strong_ordering::less ); +static_assert( strong_order(1, 1) == strong_ordering::equal ); +static_assert( strong_order(2, 1) == strong_ordering::greater ); +static_assert( noexcept(strong_order(1, 1)) ); + +constexpr strong_ordering different_cv_quals(int i, const int j) +{ + return strong_order(i, j); +} +static_assert( different_cv_quals(42, 999) == strong_ordering::less ); +static_assert( different_cv_quals(-999, -999) == strong_ordering::equal ); +static_assert( different_cv_quals(-99, -111) == strong_ordering::greater ); + +namespace N +{ + struct X { int i; }; + + constexpr strong_ordering operator<=>(X l, X r) + { + if (l.i < 0 && r.i < 0) + return strong_ordering::equivalent; + return r.i <=> l.i; + } +} +using N::X; + +static_assert( strong_order(X{1}, X{1}) == strong_ordering::equal ); +static_assert( strong_order(X{-1}, X{-2}) == strong_ordering::equivalent ); +static_assert( strong_order(X{1}, X{2}) == strong_ordering::greater ); +static_assert( !noexcept(strong_order(X{1}, X{2})) ); diff --git a/libstdc++-v3/testsuite/18_support/comparisons/algorithms/weak_order.cc b/libstdc++-v3/testsuite/18_support/comparisons/algorithms/weak_order.cc new file mode 100644 index 00000000000..03a162b86d5 --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/comparisons/algorithms/weak_order.cc @@ -0,0 +1,119 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +using std::weak_order; +using std::weak_ordering; + +void +test01() +{ + int one = 1, two = 2; + + VERIFY( weak_order(one, two) == weak_ordering::less ); + VERIFY( weak_order(one, one) == weak_ordering::equivalent ); + VERIFY( weak_order(two, one) == weak_ordering::greater ); + static_assert( noexcept(weak_order(1, 1)) ); +} + +constexpr weak_ordering different_cv_quals(int i, const int j) +{ + return weak_order(i, j); +} + +void +test02() +{ + int fortytwo = 42, nines = 999, lots = 1000; + + VERIFY( different_cv_quals(fortytwo, nines) == weak_ordering::less ); + VERIFY( different_cv_quals(-nines, -nines) == weak_ordering::equivalent ); + VERIFY( different_cv_quals(-nines, -lots) == weak_ordering::greater ); +} + +void +test03() +{ + double zero = 0.0; + VERIFY( weak_order(zero, zero) == weak_ordering::equivalent ); + VERIFY( weak_order(-zero, -zero) == weak_ordering::equivalent ); + VERIFY( weak_order(-zero, zero) == weak_ordering::equivalent ); + VERIFY( weak_order(zero, -zero) == weak_ordering::equivalent ); + + double min = std::numeric_limits::lowest(); + double max = std::numeric_limits::max(); + double nan = std::numeric_limits::quiet_NaN(); + double inf = std::numeric_limits::infinity(); + double denorm = std::numeric_limits::denorm_min(); + double smallest = std::numeric_limits::min(); + double epsilon = std::numeric_limits::epsilon(); + VERIFY( weak_order(denorm, smallest) == weak_ordering::less ); + VERIFY( weak_order(denorm, 0.0) == weak_ordering::greater ); + VERIFY( weak_order(0.0, nan) == weak_ordering::less ); + VERIFY( weak_order(nan, nan) == weak_ordering::equivalent ); + VERIFY( weak_order(nan, -nan) == weak_ordering::greater ); + VERIFY( weak_order(-nan, nan) == weak_ordering::less ); + VERIFY( weak_order(nan, 0.0) == weak_ordering::greater ); + VERIFY( weak_order(-nan, 0.0) == weak_ordering::less ); + VERIFY( weak_order(-nan, min) == weak_ordering::less ); + VERIFY( weak_order(-inf, min) == weak_ordering::less ); + VERIFY( weak_order(-nan, -inf) == weak_ordering::less ); + VERIFY( weak_order(-inf, -nan) == weak_ordering::greater ); + VERIFY( weak_order(max, inf) == weak_ordering::less ); + VERIFY( weak_order(inf, max) == weak_ordering::greater ); + VERIFY( weak_order(inf, nan) == weak_ordering::less ); + VERIFY( weak_order(1.0, 1.0+epsilon) == weak_ordering::less ); +} + +namespace N +{ + struct X { int i; }; + + constexpr weak_ordering operator<=>(X l, X r) + { + if (l.i < 0 && r.i < 0) + return weak_ordering::equivalent; + return r.i <=> l.i; + } +} + +void +test04() +{ + using N::X; + X one{1}; + X negone{-1}; + + VERIFY( weak_order(one, X{1}) == weak_ordering::equivalent ); + VERIFY( weak_order(negone, X{-2}) == weak_ordering::equivalent ); + VERIFY( weak_order(one, X{2}) == weak_ordering::greater ); + static_assert( !noexcept(weak_order(X{1}, X{2})) ); +} + +int main() +{ + test01(); + test02(); + test03(); + test04(); +}