Pushed to trunk now.
On Wed, 10 Apr 2024 at 09:53, Jonathan Wakely <jwak...@redhat.com> wrote: > > Tested x86_64-linux. > > Since this only affects C++26 it seems OK for trunk now. > > -- >8 -- > > This C++26 change was just approved in Tokyo, in P2944R3. It adds > operator== and operator<=> overloads to std::reference_wrapper. > > The operator<=> overloads in the paper cause compilation errors for any > type without <=> so they're implemented here with deduced return types > and constrained by a requires clause. > > libstdc++-v3/ChangeLog: > > * include/bits/refwrap.h (reference_wrapper): Add comparison > operators as proposed by P2944R3. > * include/bits/version.def (reference_wrapper): Define. > * include/bits/version.h: Regenerate. > * include/std/functional: Enable feature test macro. > * testsuite/20_util/reference_wrapper/compare.cc: New test. > --- > libstdc++-v3/include/bits/refwrap.h | 45 +++++++++ > libstdc++-v3/include/bits/version.def | 8 ++ > libstdc++-v3/include/bits/version.h | 10 ++ > libstdc++-v3/include/std/functional | 1 + > .../20_util/reference_wrapper/compare.cc | 95 +++++++++++++++++++ > 5 files changed, 159 insertions(+) > create mode 100644 > libstdc++-v3/testsuite/20_util/reference_wrapper/compare.cc > > diff --git a/libstdc++-v3/include/bits/refwrap.h > b/libstdc++-v3/include/bits/refwrap.h > index 2d4338b718f..fd1cc2b63e6 100644 > --- a/libstdc++-v3/include/bits/refwrap.h > +++ b/libstdc++-v3/include/bits/refwrap.h > @@ -38,6 +38,10 @@ > #include <bits/invoke.h> > #include <bits/stl_function.h> // for unary_function and binary_function > > +#if __glibcxx_reference_wrapper >= 202403L // >= C++26 > +# include <compare> > +#endif > + > namespace std _GLIBCXX_VISIBILITY(default) > { > _GLIBCXX_BEGIN_NAMESPACE_VERSION > @@ -358,6 +362,47 @@ _GLIBCXX_MEM_FN_TRAITS(&& noexcept, false_type, > true_type) > #endif > return std::__invoke(get(), std::forward<_Args>(__args)...); > } > + > +#if __glibcxx_reference_wrapper >= 202403L // >= C++26 > + // [refwrap.comparisons], comparisons > + [[nodiscard]] > + friend constexpr bool > + operator==(reference_wrapper __x, reference_wrapper __y) > + requires requires { { __x.get() == __y.get() } -> > convertible_to<bool>; } > + { return __x.get() == __y.get(); } > + > + [[nodiscard]] > + friend constexpr bool > + operator==(reference_wrapper __x, const _Tp& __y) > + requires requires { { __x.get() == __y } -> convertible_to<bool>; } > + { return __x.get() == __y; } > + > + [[nodiscard]] > + friend constexpr bool > + operator==(reference_wrapper __x, reference_wrapper<const _Tp> __y) > + requires (!is_const_v<_Tp>) > + && requires { { __x.get() == __y.get() } -> convertible_to<bool>; } > + { return __x.get() == __y.get(); } > + > + [[nodiscard]] > + friend constexpr auto > + operator<=>(reference_wrapper __x, reference_wrapper<_Tp> __y) > + requires requires { __detail::__synth3way(__x.get(), __y.get()); } > + { return __detail::__synth3way(__x.get(), __y.get()); } > + > + [[nodiscard]] > + friend constexpr auto > + operator<=>(reference_wrapper __x, const _Tp& __y) > + requires requires { __detail::__synth3way(__x.get(), __y); } > + { return __detail::__synth3way(__x.get(), __y); } > + > + [[nodiscard]] > + friend constexpr auto > + operator<=>(reference_wrapper __x, reference_wrapper<const _Tp> __y) > + requires (!is_const_v<_Tp>) > + && requires { __detail::__synth3way(__x.get(), __y.get()); } > + { return __detail::__synth3way(__x.get(), __y.get()); } > +#endif > }; > > #if __cpp_deduction_guides > diff --git a/libstdc++-v3/include/bits/version.def > b/libstdc++-v3/include/bits/version.def > index 5ad44941bff..5c0477fb61e 100644 > --- a/libstdc++-v3/include/bits/version.def > +++ b/libstdc++-v3/include/bits/version.def > @@ -1760,6 +1760,14 @@ ftms = { > }; > }; > > +ftms = { > + name = reference_wrapper; > + values = { > + v = 202403; > + cxxmin = 26; > + }; > +}; > + > ftms = { > name = saturation_arithmetic; > values = { > diff --git a/libstdc++-v3/include/bits/version.h > b/libstdc++-v3/include/bits/version.h > index 460a3e0116a..65e708c73fb 100644 > --- a/libstdc++-v3/include/bits/version.h > +++ b/libstdc++-v3/include/bits/version.h > @@ -1963,6 +1963,16 @@ > #endif /* !defined(__cpp_lib_ratio) && defined(__glibcxx_want_ratio) */ > #undef __glibcxx_want_ratio > > +#if !defined(__cpp_lib_reference_wrapper) > +# if (__cplusplus > 202302L) > +# define __glibcxx_reference_wrapper 202403L > +# if defined(__glibcxx_want_all) || > defined(__glibcxx_want_reference_wrapper) > +# define __cpp_lib_reference_wrapper 202403L > +# endif > +# endif > +#endif /* !defined(__cpp_lib_reference_wrapper) && > defined(__glibcxx_want_reference_wrapper) */ > +#undef __glibcxx_want_reference_wrapper > + > #if !defined(__cpp_lib_saturation_arithmetic) > # if (__cplusplus > 202302L) > # define __glibcxx_saturation_arithmetic 202311L > diff --git a/libstdc++-v3/include/std/functional > b/libstdc++-v3/include/std/functional > index 766558b3ce0..99364286a72 100644 > --- a/libstdc++-v3/include/std/functional > +++ b/libstdc++-v3/include/std/functional > @@ -83,6 +83,7 @@ > #define __glibcxx_want_move_only_function > #define __glibcxx_want_not_fn > #define __glibcxx_want_ranges > +#define __glibcxx_want_reference_wrapper > #define __glibcxx_want_transparent_operators > #include <bits/version.h> > > diff --git a/libstdc++-v3/testsuite/20_util/reference_wrapper/compare.cc > b/libstdc++-v3/testsuite/20_util/reference_wrapper/compare.cc > new file mode 100644 > index 00000000000..039c9d26496 > --- /dev/null > +++ b/libstdc++-v3/testsuite/20_util/reference_wrapper/compare.cc > @@ -0,0 +1,95 @@ > +// { dg-do compile { target c++26 } } > + > + > +#include <functional> > + > +#ifndef __cpp_lib_reference_wrapper > +# error "Feature-test macro for reference_wrapper missing" > +#elif __cpp_lib_reference_wrapper != 202403 > +# error "Feature-test macro for reference_wrapper has wrong value" > +#endif > + > +// P2944R3 Comparisons for reference_wrapper > + > +auto check(int i, std::reference_wrapper<int> r) -> bool { > + return i == r; > +} > + > +template <class T> using Ref = std::reference_wrapper<T>; > + > +template <class T> > +concept ref_equality_comparable > += requires (T a, T const ca, Ref<T> r, Ref<T const> cr) { > + // the usual T is equality-comparable with itself > + a == a; > + a == ca; > + ca == ca; > + > + // Ref<T> is equality-comparable with itself > + r == r; > + r == cr; > + cr == cr; > + > + // T and Ref<T> are equality-comparable > + a == r; > + a == cr; > + ca == r; > + ca == cr; > +}; > + > +static_assert( ref_equality_comparable<int> ); > + > +struct A { > + auto operator==(A const&) const -> bool { return true; } > +}; > + > +struct B { > + friend auto operator==(B const&, B const&) -> bool { return true; } > +}; > + > +template <class T> > +struct C { > + friend auto operator==(C const&, C const&) -> bool { return true; } > +}; > + > +template <class T> > +struct D { }; > +template <class T> > +auto operator==(D<T> const&, D<T> const&) -> bool { return true; } > + > +static_assert(ref_equality_comparable<int>); > +static_assert(ref_equality_comparable<A>); > +static_assert(ref_equality_comparable<B>); > +static_assert(ref_equality_comparable<C<int>>); > +static_assert(ref_equality_comparable<D<int>>); > +#include <string_view> > +static_assert(ref_equality_comparable<std::string_view>); > + > +template <typename T> > +struct ValArray { > + friend auto operator==(ValArray const&, ValArray const&) -> ValArray<bool> > { > + return {}; > + } > +}; > + > +void f(ValArray<int> v) { > + // this is valid and has type ValArray<bool> > + v == v; > + > + // this is also valid today and has the same type > + std::ref(v) == std::ref(v); > +} > + > +struct ComparesAsInt { > + friend auto operator==(ComparesAsInt, ComparesAsInt) -> int; > +}; > + > +auto f(std::reference_wrapper<ComparesAsInt> a, > + std::reference_wrapper<ComparesAsInt> b) { > + // today: compiles and returns int > + // proposed: compiles and returns bool > + return a == b; > +} > + > +ComparesAsInt& c(); > +static_assert( std::is_same_v<decltype(f(c(), c())), bool> ); > -- > 2.44.0 >