[libc++] P2944R3: Constrained comparisons - update `reference_wrapper` implementation (#139368)
Updates the implementation `std::reference_wrapper` -
[P2944R3](https://wg21.link/P2944R3) as discussed in
https://github.com/llvm/llvm-project/pull/117664#discussion_r1857826166
This PR also refactors the tests in preparation to implements the
constrained comparisons for `optional`, `variant` etc.
- Moves the test helpers (concepts and types) for testing constrained
comparisons to `test_comparisons.h`.
- Updates the `std::reference_wrapper` implementation to use the concept
`__core_convertible_to<bool>` as per comments in #135759.
Closes #138233
# References:
- [refwrap.comparisons](https://wg21.link/refwrap.comparisons)
---------
Co-authored-by: Hristo Hristov <zingam@outlook.com>
Co-authored-by: Nikolas Klauser <nikolasklauser@berlin.de>
GitOrigin-RevId: a0c00ccd5ff180c721def8001c870338d5de319e
diff --git a/docs/Status/Cxx2cPapers.csv b/docs/Status/Cxx2cPapers.csv
index 3809446..8a0417e 100644
--- a/docs/Status/Cxx2cPapers.csv
+++ b/docs/Status/Cxx2cPapers.csv
@@ -59,7 +59,7 @@
"`P2248R8 <https://wg21.link/P2248R8>`__","Enabling list-initialization for algorithms","2024-03 (Tokyo)","","",""
"`P2810R4 <https://wg21.link/P2810R4>`__","``is_debugger_present`` ``is_replaceable``","2024-03 (Tokyo)","","",""
"`P1068R11 <https://wg21.link/P1068R11>`__","Vector API for random number generation","2024-03 (Tokyo)","","",""
-"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","Implemented changes to ``reference_wrapper`` and ``pair``"
+"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","The changes to ``optional``, ``tuple`` and ``variant`` are not yet implemented"
"`P2642R6 <https://wg21.link/P2642R6>`__","Padded ``mdspan`` layouts","2024-03 (Tokyo)","","",""
"`P3029R1 <https://wg21.link/P3029R1>`__","Better ``mdspan``'s CTAD","2024-03 (Tokyo)","|Complete|","19",""
"","","","","",""
diff --git a/include/__functional/reference_wrapper.h b/include/__functional/reference_wrapper.h
index b409ad7..c46203a 100644
--- a/include/__functional/reference_wrapper.h
+++ b/include/__functional/reference_wrapper.h
@@ -11,7 +11,6 @@
#define _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H
#include <__compare/synth_three_way.h>
-#include <__concepts/boolean_testable.h>
#include <__config>
#include <__functional/weak_result_type.h>
#include <__memory/addressof.h>
@@ -19,6 +18,7 @@
#include <__type_traits/enable_if.h>
#include <__type_traits/invoke.h>
#include <__type_traits/is_const.h>
+#include <__type_traits/is_core_convertible.h>
#include <__type_traits/remove_cvref.h>
#include <__type_traits/void_t.h>
#include <__utility/declval.h>
@@ -75,7 +75,7 @@
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, reference_wrapper __y)
requires requires {
- { __x.get() == __y.get() } -> __boolean_testable;
+ { __x.get() == __y.get() } -> __core_convertible_to<bool>;
}
{
return __x.get() == __y.get();
@@ -83,7 +83,7 @@
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, const _Tp& __y)
requires requires {
- { __x.get() == __y } -> __boolean_testable;
+ { __x.get() == __y } -> __core_convertible_to<bool>;
}
{
return __x.get() == __y;
@@ -91,7 +91,7 @@
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, reference_wrapper<const _Tp> __y)
requires(!is_const_v<_Tp>) && requires {
- { __x.get() == __y.get() } -> __boolean_testable;
+ { __x.get() == __y.get() } -> __core_convertible_to<bool>;
}
{
return __x.get() == __y.get();
diff --git a/test/std/containers/sequences/array/compare.three_way.pass.cpp b/test/std/containers/sequences/array/compare.three_way.pass.cpp
index 01be1db..671747f 100644
--- a/test/std/containers/sequences/array/compare.three_way.pass.cpp
+++ b/test/std/containers/sequences/array/compare.three_way.pass.cpp
@@ -26,7 +26,6 @@
static_assert(std::three_way_comparable<std::array<int, N>>);
// Thanks to SFINAE, the following is not a compiler error but returns `false`
-struct NonComparable {};
static_assert(!std::three_way_comparable<std::array<NonComparable, N>>);
// Implementation detail of `test_sequence_container_array_spaceship`
diff --git a/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.const_ref.pass.cpp b/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.const_ref.pass.cpp
index 85106c1..4a2ae96 100644
--- a/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.const_ref.pass.cpp
+++ b/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.const_ref.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+// REQUIRES: std-at-least-c++26
// <functional>
@@ -23,16 +23,13 @@
#include "test_comparisons.h"
#include "test_macros.h"
-#include "helper_concepts.h"
-#include "helper_types.h"
-
// Test SFINAE.
-static_assert(HasSpaceshipOperatorWithInt<std::reference_wrapper<StrongOrder>>);
-static_assert(HasSpaceshipOperatorWithInt<std::reference_wrapper<WeakOrder>>);
-static_assert(HasSpaceshipOperatorWithInt<std::reference_wrapper<PartialOrder>>);
+static_assert(HasOperatorSpaceship<std::reference_wrapper<StrongOrder>, int>);
+static_assert(HasOperatorSpaceship<std::reference_wrapper<WeakOrder>, int>);
+static_assert(HasOperatorSpaceship<std::reference_wrapper<PartialOrder>, int>);
-static_assert(!HasSpaceshipOperatorWithInt<std::reference_wrapper<NonComparable>>);
+static_assert(!HasOperatorSpaceship<std::reference_wrapper<NonComparable>, int>);
// Test comparisons.
diff --git a/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap.pass.cpp b/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap.pass.cpp
index 794fac0..3d72459 100644
--- a/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap.pass.cpp
+++ b/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+// REQUIRES: std-at-least-c++26
// <functional>
@@ -22,17 +22,13 @@
#include "test_comparisons.h"
#include "test_macros.h"
-
-#include "helper_concepts.h"
-#include "helper_types.h"
-
// Test SFINAE.
-static_assert(std::three_way_comparable<std::reference_wrapper<StrongOrder>>);
-static_assert(std::three_way_comparable<std::reference_wrapper<WeakOrder>>);
-static_assert(std::three_way_comparable<std::reference_wrapper<PartialOrder>>);
+static_assert(HasOperatorSpaceship<std::reference_wrapper<StrongOrder>>);
+static_assert(HasOperatorSpaceship<std::reference_wrapper<WeakOrder>>);
+static_assert(HasOperatorSpaceship<std::reference_wrapper<PartialOrder>>);
-static_assert(!std::three_way_comparable<std::reference_wrapper<NonComparable>>);
+static_assert(!HasOperatorSpaceship<std::reference_wrapper<NonComparable>>);
// Test comparisons.
diff --git a/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap_const.pass.cpp b/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap_const.pass.cpp
index 9b1302a..1ae22b4 100644
--- a/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap_const.pass.cpp
+++ b/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap_const.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+// REQUIRES: std-at-least-c++26
// <functional>
@@ -23,18 +23,15 @@
#include "test_comparisons.h"
#include "test_macros.h"
-#include "helper_concepts.h"
-#include "helper_types.h"
-
// Test SFINAE.
-static_assert(std::three_way_comparable_with<std::reference_wrapper<StrongOrder>, const StrongOrder>);
-static_assert(std::three_way_comparable_with<std::reference_wrapper<WeakOrder>, const WeakOrder>);
-static_assert(std::three_way_comparable_with<std::reference_wrapper<PartialOrder>, const PartialOrder>);
+static_assert(HasOperatorSpaceship<std::reference_wrapper<StrongOrder>, std::reference_wrapper<const StrongOrder>>);
+static_assert(HasOperatorSpaceship<std::reference_wrapper<WeakOrder>, std::reference_wrapper<const WeakOrder>>);
+static_assert(HasOperatorSpaceship<std::reference_wrapper<PartialOrder>, std::reference_wrapper<const PartialOrder>>);
-static_assert(!std::three_way_comparable_with<std::reference_wrapper<StrongOrder>, const NonComparable>);
-static_assert(!std::three_way_comparable_with<std::reference_wrapper<WeakOrder>, const NonComparable>);
-static_assert(!std::three_way_comparable_with<std::reference_wrapper<PartialOrder>, const NonComparable>);
+static_assert(!HasOperatorSpaceship<std::reference_wrapper<StrongOrder>, std::reference_wrapper<const NonComparable>>);
+static_assert(!HasOperatorSpaceship<std::reference_wrapper<WeakOrder>, std::reference_wrapper<const NonComparable>>);
+static_assert(!HasOperatorSpaceship<std::reference_wrapper<PartialOrder>, std::reference_wrapper<const NonComparable>>);
// Test comparisons.
diff --git a/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.const_ref.pass.cpp b/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.const_ref.pass.cpp
index 4653268..316ff7c 100644
--- a/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.const_ref.pass.cpp
+++ b/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.const_ref.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+// REQUIRES: std-at-least-c++26
// <functional>
@@ -23,14 +23,13 @@
#include "test_comparisons.h"
#include "test_macros.h"
-#include "helper_concepts.h"
-#include "helper_types.h"
-
// Test SFINAE.
-static_assert(HasEqualityOperatorWithInt<std::reference_wrapper<EqualityComparable>>);
+static_assert(HasOperatorEqual<std::reference_wrapper<EqualityComparable>>);
+static_assert(HasOperatorEqual<std::reference_wrapper<EqualityComparable>, int>);
-static_assert(!HasEqualityOperatorWithInt<std::reference_wrapper<NonComparable>>);
+static_assert(!HasOperatorEqual<std::reference_wrapper<NonComparable>>);
+static_assert(!HasOperatorEqual<std::reference_wrapper<NonComparable>, int>);
// Test equality.
diff --git a/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap.pass.cpp b/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap.pass.cpp
index a50b530..70e79d3 100644
--- a/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap.pass.cpp
+++ b/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+// REQUIRES: std-at-least-c++26
// <functional>
@@ -22,14 +22,11 @@
#include "test_comparisons.h"
#include "test_macros.h"
-#include "helper_concepts.h"
-#include "helper_types.h"
-
// Test SFINAE.
-static_assert(std::equality_comparable<std::reference_wrapper<EqualityComparable>>);
+static_assert(HasOperatorEqual<std::reference_wrapper<EqualityComparable>>);
-static_assert(!std::equality_comparable<std::reference_wrapper<NonComparable>>);
+static_assert(!HasOperatorEqual<std::reference_wrapper<NonComparable>>);
// Test equality.
diff --git a/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap_const.pass.cpp b/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap_const.pass.cpp
index 10f0177..c68ad5c 100644
--- a/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap_const.pass.cpp
+++ b/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap_const.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+// REQUIRES: std-at-least-c++26
// <functional>
@@ -23,16 +23,13 @@
#include "test_comparisons.h"
#include "test_macros.h"
-#include "helper_concepts.h"
-#include "helper_types.h"
-
// Test SFINAE.
-static_assert(std::equality_comparable_with<std::reference_wrapper<EqualityComparable>,
- std::reference_wrapper<const EqualityComparable>>);
+static_assert(
+ HasOperatorEqual<std::reference_wrapper<EqualityComparable>, std::reference_wrapper<const EqualityComparable>>);
-static_assert(!std::equality_comparable_with<std::reference_wrapper<EqualityComparable>,
- std::reference_wrapper<const NonComparable>>);
+static_assert(
+ !HasOperatorEqual<std::reference_wrapper<EqualityComparable>, std::reference_wrapper<const NonComparable>>);
// Test equality.
diff --git a/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_concepts.h b/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_concepts.h
deleted file mode 100644
index 2dbb304..0000000
--- a/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_concepts.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_CONCEPTS_H
-#define TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_CONCEPTS_H
-
-#include <concepts>
-#include <utility>
-
-// Equality
-
-template <typename T>
-concept HasEqualityOperatorWithInt = requires(T t, int i) {
- { t.get() == i } -> std::convertible_to<bool>;
-};
-
-// Spaceship
-
-template <class T>
-concept BooleanTestableImpl = std::convertible_to<T, bool>;
-
-template <class T>
-concept BooleanTestable = BooleanTestableImpl<T> && requires(T&& t) {
- { !std::forward<T>(t) } -> BooleanTestableImpl;
-};
-
-template <typename T>
-concept HasSpaceshipOperatorWithInt = requires(T t, int i) {
- { t < i } -> BooleanTestable;
- { i < t } -> BooleanTestable;
-};
-
-#endif // TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_CONCEPTS_H
diff --git a/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_types.h b/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_types.h
deleted file mode 100644
index cf5e568..0000000
--- a/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_types.h
+++ /dev/null
@@ -1,30 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_TYPES_H
-#define TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_TYPES_H
-
-#include <concepts>
-
-struct EqualityComparable {
- constexpr EqualityComparable(int value) : value_{value} {};
-
- friend constexpr bool operator==(const EqualityComparable&, const EqualityComparable&) noexcept = default;
-
- int value_;
-};
-
-static_assert(std::equality_comparable<EqualityComparable>);
-static_assert(EqualityComparable{94} == EqualityComparable{94});
-static_assert(EqualityComparable{94} != EqualityComparable{82});
-
-struct NonComparable {};
-
-static_assert(!std::three_way_comparable<NonComparable>);
-
-#endif // TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_TYPES_H
diff --git a/test/support/test_comparisons.h b/test/support/test_comparisons.h
index db6977a..d9729e0 100644
--- a/test/support/test_comparisons.h
+++ b/test/support/test_comparisons.h
@@ -268,6 +268,29 @@
}
};
-#endif
+template <typename T1, typename T2 = T1>
+concept HasOperatorEqual = requires(T1 t1, T2 t2) { t1 == t2; };
+
+template <typename T1, typename T2 = T1>
+concept HasOperatorSpaceship = requires(T1 t1, T2 t2) { t1 <=> t2; };
+
+struct NonComparable {};
+static_assert(!std::equality_comparable<NonComparable>);
+static_assert(!HasOperatorEqual<NonComparable>);
+static_assert(!HasOperatorSpaceship<NonComparable>);
+
+class EqualityComparable {
+public:
+ constexpr EqualityComparable(int value) : value_{value} {};
+
+ friend constexpr bool operator==(const EqualityComparable&, const EqualityComparable&) noexcept = default;
+
+private:
+ int value_;
+};
+static_assert(std::equality_comparable<EqualityComparable>);
+static_assert(HasOperatorEqual<EqualityComparable>);
+
+#endif // TEST_STD_VER >= 20
#endif // TEST_COMPARISONS_H
diff --git a/test/support/test_container_comparisons.h b/test/support/test_container_comparisons.h
index f7bf78e..53db5ba 100644
--- a/test/support/test_container_comparisons.h
+++ b/test/support/test_container_comparisons.h
@@ -88,7 +88,6 @@
std::weak_ordering>();
// Thanks to SFINAE, the following is not a compiler error but returns `false`
- struct NonComparable {};
static_assert(!std::three_way_comparable<Container<NonComparable>>);
return true;
@@ -163,7 +162,6 @@
template <template <typename...> typename ContainerAdaptor, template <typename...> typename Container>
constexpr bool test_sequence_container_adaptor_spaceship() {
// Thanks to SFINAE, the following is not a compiler error but returns `false`
- struct NonComparable {};
static_assert(!std::three_way_comparable<ContainerAdaptor<NonComparable>>);
// The container should fulfill `std::three_way_comparable`
@@ -301,7 +299,6 @@
template <template <typename...> typename Container>
constexpr bool test_ordered_map_container_spaceship() {
// Thanks to SFINAE, the following is not a compiler error but returns `false`
- struct NonComparable {};
static_assert(!std::three_way_comparable<Container<int, NonComparable>>);
// The container should fulfill `std::three_way_comparable`
@@ -444,7 +441,6 @@
template <template <typename...> typename Container>
constexpr bool test_ordered_set_container_spaceship() {
// Thanks to SFINAE, the following is not a compiler error but returns `false`
- struct NonComparable {};
static_assert(!std::three_way_comparable<Container<NonComparable>>);
// The container should fulfill `std::three_way_comparable`