Message ID | 20240410085039.267589-2-jwakely@redhat.com |
---|---|
State | New |
Headers | show |
Series | [1/4] libstdc++: Heterogeneous std::pair comparisons [PR113386] | expand |
Pushed to trunk now. On Wed, 10 Apr 2024 at 09:53, Jonathan Wakely <jwakely@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 >
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> );