[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