[PATCH v2 3/3] libstdc++: Implement P2655R3 common_reference of reference_wrapper
Tomasz Kaminski
tkaminsk@redhat.com
Mon Oct 13 08:16:09 GMT 2025
On Mon, Oct 13, 2025 at 9:30 AM Tomasz Kaminski <tkaminsk@redhat.com> wrote:
>
>
> On Mon, Oct 13, 2025 at 6:43 AM Patrick Palka <ppalka@redhat.com> wrote:
>
>> PR libstdc++/120446
>>
>> libstdc++-v3/ChangeLog:
>>
>> * include/bits/refwrap.h (__detail::__is_ref_wrapper):
>> Define as per P2655R3 for C++20.
>> (__detail::__ref_wrap_common_reference_exists_with): Likewise.
>> (basic_common_reference): Define partial specializations using
>> the above as per P2655R3 for C++20.
>> * include/bits/version.def (common_reference_wrapper): New.
>> * include/bits/version.h: Regenerate.
>> * include/std/functional
>> (__glibcxx_want_common_reference_wrapper):
>> Define.
>> * testsuite/20_util/reference_wrapper/p2655r3.cc: New test.
>> ---
>>
> LGTM.
>
>> libstdc++-v3/include/bits/refwrap.h | 34 +++++++++++++++
>> libstdc++-v3/include/bits/version.def | 8 ++++
>> libstdc++-v3/include/bits/version.h | 10 +++++
>> libstdc++-v3/include/std/functional | 1 +
>> .../20_util/reference_wrapper/p2655r3.cc | 43 +++++++++++++++++++
>> 5 files changed, 96 insertions(+)
>> create mode 100644
>> libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc
>>
>> diff --git a/libstdc++-v3/include/bits/refwrap.h
>> b/libstdc++-v3/include/bits/refwrap.h
>> index 612715e9b7bd..5d9f8c8f49f9 100644
>> --- a/libstdc++-v3/include/bits/refwrap.h
>> +++ b/libstdc++-v3/include/bits/refwrap.h
>> @@ -457,6 +457,40 @@ _GLIBCXX_MEM_FN_TRAITS(&& noexcept, false_type,
>> true_type)
>>
>> /// @}
>>
>> +#if __glibcxx_common_reference_wrapper // C++ >= 20
>> + namespace __detail
>> + {
>> + template<typename _Tp>
>> + constexpr bool __is_ref_wrapper = false;
>> +
>> + template<typename _Tp>
>> + constexpr bool __is_ref_wrapper<reference_wrapper<_Tp>> = true;
>> +
>> + template<typename _Rp, typename _Tp, typename _RQual, typename
>> _TQual>
>> + concept __ref_wrap_common_reference_exists_with =
>> __is_ref_wrapper<_Rp>
>> + && requires { typename common_reference_t<typename _Rp::type&,
>> _TQual>; }
>> + && convertible_to<_RQual, common_reference_t<typename _Rp::type&,
>> _TQual>>;
>> + } // namespace __detail
>> +
>> + template<typename _Rp, typename _Tp,
>> + template<typename> class _RQual, template<typename> class
>> _TQual>
>> + requires __detail::__ref_wrap_common_reference_exists_with<_Rp, _Tp,
>> +
>> _RQual<_Rp>, _TQual<_Tp>>
>> + && (!__detail::__ref_wrap_common_reference_exists_with<_Tp, _Rp,
>> + _TQual<_Tp>,
>> _RQual<_Rp>>)
>> + struct basic_common_reference<_Rp, _Tp, _RQual, _TQual>
>> + { using type = common_reference_t<typename _Rp::type&, _TQual<_Tp>>; };
>> +
>> + template<typename _Tp, typename _Rp,
>> + template<typename> class _TQual, template<typename> class
>> _RQual>
>> + requires __detail::__ref_wrap_common_reference_exists_with<_Rp, _Tp,
>> +
>> _RQual<_Rp>, _TQual<_Tp>>
>> + && (!__detail::__ref_wrap_common_reference_exists_with<_Tp, _Rp,
>> + _TQual<_Tp>,
>> _RQual<_Rp>>)
>> + struct basic_common_reference<_Tp, _Rp, _TQual, _RQual>
>> + { using type = common_reference_t<typename _Rp::type&, _TQual<_Tp>>; };
>> +#endif
>> +
>> _GLIBCXX_END_NAMESPACE_VERSION
>> } // namespace std
>>
>> diff --git a/libstdc++-v3/include/bits/version.def
>> b/libstdc++-v3/include/bits/version.def
>> index e2b064e09b1e..9f4e46e37260 100644
>> --- a/libstdc++-v3/include/bits/version.def
>> +++ b/libstdc++-v3/include/bits/version.def
>> @@ -1801,6 +1801,14 @@ ftms = {
>> };
>> };
>>
>> +ftms = {
>> + name = common_reference_wrapper;
>> + values = {
>> + v = 202302;
>> + cxxmin = 20; // We treat P2655R3 as a DR against C++20.
>> + };
>> +};
>> +
>> ftms = {
>> name = formatters;
>> values = {
>> diff --git a/libstdc++-v3/include/bits/version.h
>> b/libstdc++-v3/include/bits/version.h
>> index 4581519d3a7d..e7af12bf629c 100644
>> --- a/libstdc++-v3/include/bits/version.h
>> +++ b/libstdc++-v3/include/bits/version.h
>> @@ -2011,6 +2011,16 @@
>> #endif /* !defined(__cpp_lib_common_reference) &&
>> defined(__glibcxx_want_common_reference) */
>> #undef __glibcxx_want_common_reference
>>
>> +#if !defined(__cpp_lib_common_reference_wrapper)
>> +# if (__cplusplus >= 202002L)
>> +# define __glibcxx_common_reference_wrapper 202302L
>> +# if defined(__glibcxx_want_all) ||
>> defined(__glibcxx_want_common_reference_wrapper)
>> +# define __cpp_lib_common_reference_wrapper 202302L
>> +# endif
>> +# endif
>> +#endif /* !defined(__cpp_lib_common_reference_wrapper) &&
>> defined(__glibcxx_want_common_reference_wrapper) */
>> +#undef __glibcxx_want_common_reference_wrapper
>> +
>> #if !defined(__cpp_lib_formatters)
>> # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED
>> # define __glibcxx_formatters 202302L
>> diff --git a/libstdc++-v3/include/std/functional
>> b/libstdc++-v3/include/std/functional
>> index 8ad73b343bda..6f7f2f627a2a 100644
>> --- a/libstdc++-v3/include/std/functional
>> +++ b/libstdc++-v3/include/std/functional
>> @@ -64,6 +64,7 @@
>> #define __glibcxx_want_not_fn
>> #define __glibcxx_want_ranges
>> #define __glibcxx_want_reference_wrapper
>> +#define __glibcxx_want_common_reference_wrapper
>> #define __glibcxx_want_transparent_operators
>> #include <bits/version.h>
>>
>> diff --git a/libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc
>> b/libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc
>> new file mode 100644
>> index 000000000000..a240971f2e24
>> --- /dev/null
>> +++ b/libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc
>> @@ -0,0 +1,43 @@
>> +// P2655R3 - common_reference_t of reference_wrapper Should Be a
>> Reference Type
>> +// Implemented as a DR against C++20
>> +// { dg-do compile { target c++20 } }
>> +
>> +#include <functional>
>> +
>> +#if __cpp_lib_common_reference_wrapper != 202302L
>> +# error "Feature-test macro __cpp_lib_common_reference_wrapper has wrong
>> value in <functional>"
>> +#endif
>> +
>> +using std::is_same_v;
>> +using std::common_reference_t;
>> +using std::reference_wrapper;
>> +
>> +static_assert( is_same_v<common_reference_t<const
>> reference_wrapper<int>&, int&>, int&> );
>> +static_assert( is_same_v<common_reference_t<int&, const
>> reference_wrapper<int>&>, int&> );
>> +
>> +static_assert( is_same_v<common_reference_t<reference_wrapper<int>,
>> int&>,
>> + common_reference_t<int&, int&>> );
>> +static_assert( is_same_v<common_reference_t<reference_wrapper<int>,
>> const int&>,
>> + common_reference_t<int&, const int&>> );
>> +static_assert( is_same_v<common_reference_t<reference_wrapper<const
>> int>, int&>,
>> + common_reference_t<const int&, int&>> );
>> +
>> +static_assert( is_same_v<common_reference_t<int&,
>> reference_wrapper<int>>,
>> + common_reference_t<int&, int&>> );
>> +static_assert( is_same_v<common_reference_t<const int&,
>> reference_wrapper<int>>,
>> + common_reference_t<int&, const int&>> );
>> +static_assert( is_same_v<common_reference_t<int&,
>> reference_wrapper<const int>>,
>> + common_reference_t<const int&, int&>> );
>> +
>> +static_assert( is_same_v<common_reference_t<reference_wrapper<int>&,
>> reference_wrapper<int>&>,
>> + reference_wrapper<int>&> );
>> +
>> +static_assert( is_same_v<common_reference_t<reference_wrapper<char>,
>> + reference_wrapper<int>>,
>> + int> );
>> +static_assert(
>> is_same_v<common_reference_t<reference_wrapper<reference_wrapper<int>>,
>> + reference_wrapper<int>>,
>> + reference_wrapper<int>> );
>> +static_assert( is_same_v<common_reference_t<reference_wrapper<int>,
>> +
>> reference_wrapper<reference_wrapper<int>>>,
>> + reference_wrapper<int>> );
>> --
>> 2.51.0.491.g4b71b29477
>>
> These are the test I would add in this commit, we can add pair/tuple later:
struct A { };
struct B { operator A&() const; };
template<typename T, typename U>
concept has_common_reference = requires {
typename std::common_reference_t<T, U>;
};
static_assert( is_same_v<common_reference_t<reference_wrapper<A>, const
B&>, A&> );
// reference_wrapper<const B> is not convertible to A&, as it would require
two user
// defined conversions.
static_assert( !has_common_reference<A, reference_wrapper<const B>> );
static_assert( !has_common_reference<reference_wrapper<A>,
reference_wrapper<const B>> );
struct D1 : A {};
struct D2 : A {};
template<template<class> typename Qual1, template<class> typename Qual2>
struct std::basic_common_reference<D1, D2, Qual1, Qual2>
: std::common_reference<Qual1<A>, Qual2<A>>
{ };
template<template<class> typename Qual1, template<class> typename Qual2>
struct std::basic_common_reference<D2, D1, Qual1, Qual2>
: std::common_reference<Qual1<A>, Qual2<A>>
{ };
static_assert( is_same_v<common_reference_t<D1&, D2&>, A&> );
static_assert( is_same_v<common_reference_t<reference_wrapper<D1>, D2&>,
A&> );
static_assert( is_same_v<common_reference_t<D1&, reference_wrapper<D2>>,
A&> );
static_assert( !has_common_reference<reference_wrapper<D1>,
reference_wrapper<D2>> );
> I would add test testing combination of this two changes:
>
struct A { };
> struct B { operator A&() const; };
> // This should be OK
> static_assert( std::is_same_v<std::common_reference_t<refence_wrapper<A>,
> const B&>, A&> );
> // common_reference_t would exists, but the concept
> common_reference_with<A&, reference_wrapper<const B>> would not be modeled,
> // because it would require two user defined conversions
> static_assert( std::is_same_v<std::common_reference_t<A&,
> reference_wrapper<const B>>, A&> );
> // Not sure what happens here.
> static_assert( std::is_same_v<std::common_reference_t<refence_wrapper<A>,
> reference_wrapper<const B>>, reference_wrapper<A>> );
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20251013/85d3051e/attachment-0001.htm>
More information about the Libstdc++
mailing list