Counterintuitive std::pointer_traits rebind

Jonathan Wakely jwakely.gcc@gmail.com
Fri Jul 5 20:33:03 GMT 2024


On Fri, 5 Jul 2024 at 21:09, François Dumont <frs.dumont@gmail.com> wrote:
>
> Hi
>
> I started to add support for allocator fancy pointer types in _Rb_tree
> and I wrote something like that:
>
>    template<typename _BasePtr, typename _BaseCPtr>
>      struct _Rb_tree_pnode_base
>      {
> #if __cplusplus < 201103L
>        typedef _BasePtr        _Base_ptr;
>        typedef _BaseCPtr    _Const_Base_ptr;
> #else
>        using _Base_ptr =
>      __ptr_rebind<_BasePtr, _Rb_tree_pnode_base>;
>        using _Const_Base_ptr =
>      __ptr_rebind<_BaseCPtr, _Rb_tree_pnode_base>;

This is wrong, it should rebind to const _Rb_tree_pnode_base.

> #endif
>
> and then:
>
>    struct _Rb_tree_node_base
>      : _Rb_tree_pnode_base<_Rb_tree_node_base*, const _Rb_tree_node_base*>
>    { };
>
> Surprisingly I had problems with overloads like those:
>
>        static _Base_ptr
>        _S_minimum(_Base_ptr __x) _GLIBCXX_NOEXCEPT
>
>        static _Const_Base_ptr
>        _S_minimum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT
>
> because std::pointer_traits<_Tp*> rebind<_Up> is defined as _Up*,
> regardless of _Tp qualifiers. So _Base_ptr and _Const_Base_ptr are the same.

Only because you defined them to be the same :-)

>
> Is it expected ?

Yes, because you defined them to be the same thing: a pointer to U.
What you want is a pointer to U and a pointer to const U.

> I find it counter-intuitive because if the allocator
> pointer and const_pointer are fancy pointers then I need to do a
> __ptr_rebind on those whereas if they are raw pointers I need to do
> something like:
>
> using _Const_Base_ptr = __ptr_rebind<_BaseCPtr, const _Rb_tree_pnode_base>;
>
> Unless I should do this whatever is _BaseCPtr ?

Yes.

> Attached is a small patch for std::pointer_traits to do what I was
> expecting.

No, this would break pointer_traits and would be completely wrong.

If you say "rebind this pointer to give a pointer to U" then that's
what you should get. It should not depend on whether you start with a
pointer to const T or not.

Otherwise there would be no way to get U* from const T* because the
rebind operation would always give you const U*.


More information about the Libstdc++ mailing list