Counterintuitive std::pointer_traits rebind
François Dumont
frs.dumont@gmail.com
Fri Jul 5 20:09:27 GMT 2024
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>;
#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.
Is it expected ? 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 ?
Attached is a small patch for std::pointer_traits to do what I was
expecting.
Note that all that is hypothetical and do not reflect what I have
finally done.
François
-------------- next part --------------
diff --git a/libstdc++-v3/include/bits/ptr_traits.h b/libstdc++-v3/include/bits/ptr_traits.h
index ca67feecca3..a1171102db2 100644
--- a/libstdc++-v3/include/bits/ptr_traits.h
+++ b/libstdc++-v3/include/bits/ptr_traits.h
@@ -177,6 +177,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct pointer_traits : __ptr_traits_impl<_Ptr, __ptr_traits_elem_t<_Ptr>>
{ };
+ template<typename _Tp, typename _Up>
+ using __add_const_if_t = __conditional_t<
+ is_const<_Tp>::value, typename add_const<_Up>::type, _Up>;
+
+ template<typename _Tp, typename _Up>
+ using __add_volatile_if_t = __conditional_t<
+ is_volatile<_Tp>::value, typename add_volatile<_Up>::type, _Up>;
+
+ template<typename _Tp, typename _Up>
+ using __add_cv_if_t =
+ __add_const_if_t<_Tp, __add_volatile_if_t<_Tp, _Up>>;
+
/**
* @brief Partial specialization for built-in pointers.
* @headerfile memory
@@ -193,7 +205,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Type used to represent the difference between two pointers
typedef ptrdiff_t difference_type;
/// A pointer to a different type.
- template<typename _Up> using rebind = _Up*;
+ template<typename _Up> using rebind =
+ __add_cv_if_t<_Tp, __decay_t<_Up>>*;
};
/// Convenience alias for rebinding pointers.
More information about the Libstdc++
mailing list