[libcxx-commits] [libcxx] [libc++] Extend __default_three_way_comparator to any types that only implements operator<=> (PR #157602)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Sep 9 00:32:21 PDT 2025
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/157602
>From e9346d6c53273f17a1425a58f009301503db4858 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Tue, 9 Sep 2025 05:38:12 +0200
Subject: [PATCH] [libc++] Extend __default_three_way_comparator to any types
that only implement operator<=>
---
.../__utility/default_three_way_comparator.h | 26 ++++++++++++--
libcxx/include/string | 2 ++
.../has_default_three_way.compile.pass.cpp | 36 +++++++++++++++++++
3 files changed, 61 insertions(+), 3 deletions(-)
create mode 100644 libcxx/test/libcxx/utilities/utility/has_default_three_way.compile.pass.cpp
diff --git a/libcxx/include/__utility/default_three_way_comparator.h b/libcxx/include/__utility/default_three_way_comparator.h
index ce423c6ce98e4..70eb1a27af11f 100644
--- a/libcxx/include/__utility/default_three_way_comparator.h
+++ b/libcxx/include/__utility/default_three_way_comparator.h
@@ -27,9 +27,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _LHS, class _RHS, class = void>
struct __default_three_way_comparator;
-template <class _Tp>
-struct __default_three_way_comparator<_Tp, _Tp, __enable_if_t<is_arithmetic<_Tp>::value> > {
- _LIBCPP_HIDE_FROM_ABI static int operator()(_Tp __lhs, _Tp __rhs) {
+template <class _LHS, class _RHS>
+struct __default_three_way_comparator<_LHS,
+ _RHS,
+ __enable_if_t<is_arithmetic<_LHS>::value && is_arithmetic<_RHS>::value> > {
+ _LIBCPP_HIDE_FROM_ABI static int operator()(_LHS __lhs, _RHS __rhs) {
if (__lhs < __rhs)
return -1;
if (__lhs > __rhs)
@@ -38,6 +40,24 @@ struct __default_three_way_comparator<_Tp, _Tp, __enable_if_t<is_arithmetic<_Tp>
}
};
+#if _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_lt_synthesises_from_spaceship)
+template <class _LHS, class _RHS>
+struct __default_three_way_comparator<
+ _LHS,
+ _RHS,
+ __enable_if_t<(!is_arithmetic<_LHS>::value || !is_arithmetic<_RHS>::value) &&
+ __builtin_lt_synthesises_from_spaceship(const _LHS&, const _RHS&)>> {
+ _LIBCPP_HIDE_FROM_ABI static int operator()(const _LHS& __lhs, const _RHS& __rhs) {
+ auto __res = __lhs <=> __rhs;
+ if (__res < 0)
+ return -1;
+ if (__res > 0)
+ return 1;
+ return 0;
+ }
+};
+#endif
+
template <class _LHS, class _RHS, bool = true>
inline const bool __has_default_three_way_comparator_v = false;
diff --git a/libcxx/include/string b/libcxx/include/string
index 0abdfebcb863f..f13a7640760f7 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -2521,6 +2521,7 @@ _LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_DECLARE, wchar_t)
# endif
# undef _LIBCPP_DECLARE
+# if _LIBCPP_STD_VER <= 17 || !__has_builtin(__builtin_lt_synthesises_from_spaceship)
template <class _CharT, class _Traits, class _Alloc>
struct __default_three_way_comparator<basic_string<_CharT, _Traits, _Alloc>, basic_string<_CharT, _Traits, _Alloc> > {
using __string_t _LIBCPP_NODEBUG = basic_string<_CharT, _Traits, _Alloc>;
@@ -2533,6 +2534,7 @@ struct __default_three_way_comparator<basic_string<_CharT, _Traits, _Alloc>, bas
return __ret;
}
};
+# endif
# if _LIBCPP_STD_VER >= 17
template <class _InputIterator,
diff --git a/libcxx/test/libcxx/utilities/utility/has_default_three_way.compile.pass.cpp b/libcxx/test/libcxx/utilities/utility/has_default_three_way.compile.pass.cpp
new file mode 100644
index 0000000000000..b412e5a86f036
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/utility/has_default_three_way.compile.pass.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+#include <__utility/default_three_way_comparator.h>
+#include <string>
+#include <vector>
+
+static_assert(std::__has_default_three_way_comparator_v<int, int>);
+static_assert(std::__has_default_three_way_comparator_v<int, long>);
+static_assert(std::__has_default_three_way_comparator_v<long, int>);
+static_assert(std::__has_default_three_way_comparator_v<long, long>);
+static_assert(std::__has_default_three_way_comparator_v<std::string, std::string>);
+
+#if __has_builtin(__builtin_lt_synthesises_from_spaceship)
+static_assert(std::__has_default_three_way_comparator_v<const std::string&, const std::string&>);
+static_assert(std::__has_default_three_way_comparator_v<const std::string&, const std::string_view&>);
+static_assert(std::__has_default_three_way_comparator_v<const std::string&, const char*>);
+static_assert(!std::__has_default_three_way_comparator_v<const std::string&, const wchar_t*>);
+
+static_assert(std::__has_default_three_way_comparator_v<const std::vector<int>&, const std::vector<int>&>);
+
+struct MyStruct {
+ int i;
+
+ friend auto operator<=>(MyStruct, MyStruct) = default;
+};
+
+static_assert(std::__has_default_three_way_comparator_v<const MyStruct&, const MyStruct&>);
+#endif
More information about the libcxx-commits
mailing list