Created on 2009-12-14.00:00:00 last changed 78 months ago
Proposed resolution:
Add to section [utility] Utility components, Header <utility> synopsis:
// 20.3.X, generic pointer cast functions template<typename U, typename T> unspecified static_pointer_cast(T&&) = delete; template<typename U, typename T> unspecified dynamic_pointer_cast(T&&) = delete; template<typename U, typename T> unspecified const_pointer_cast(T&&) = delete; //Overloads for raw pointers template<typename U, typename T> auto static_pointer_cast(T* t) -> decltype(static_cast<U*>(t)); template<typename U, typename T> auto dynamic_pointer_cast(T* t) -> decltype(dynamic_cast<U*>(t)); template<typename U, typename T> auto const_pointer_cast(T* t) -> decltype(const_cast<U*>(t));
Add to section [utility] Utility components, a new subclause 20.3.X Pointer cast utilities [pointer.cast]:
20.3.X Pointer cast utilities [pointer.cast]
1 The library defines generic pointer casting function templates so that template code can explicitly make these names visible and activate argument-dependent lookup for pointer cast calls.
//Generic declarations template<typename U, typename T> unspecified static_pointer_cast(T&&) = delete; template<typename U, typename T> unspecified dynamic_pointer_cast(T&&) = delete; template<typename U, typename T> unspecified const_pointer_cast(T&&) = delete;2 The library also defines overloads of these functions for raw pointers.
//Overloads for raw pointers template<typename U, typename T> auto static_pointer_cast(T* t) -> decltype(static_cast<U*>(t));Returns: static_cast<U*>(t)
template<typename U, typename T> auto dynamic_pointer_cast(T* t) -> decltype(dynamic_cast<U*>(t));Returns: dynamic_cast<U*>(t)
template<typename U, typename T> auto const_pointer_cast(T* t) -> decltype(const_cast<U*>(t));Returns: const_cast<U*>(t)
[Example:
#include <utility> //static_pointer_cast #include <memory> //pointer_traits class Base{}; class Derived : public Base{}; template<class BasePtr> void generic_pointer_code(BasePtr b) { typedef std::pointer_traits<BasePtr>::template rebind<Derived> DerivedPtr; using std::static_pointer_cast; //ADL applies now that static_pointer_cast is visible DerivedPtr d = static_pointer_cast<Derived>(b); }— end example]
Replace in section [allocator.requirements] Table 40 — Allocator requirements, the following table entries for allocator pointers:
Table 40 — Allocator requirements Expression Return type Assertion/note
pre-/post-conditionDefault static_pointer_cast< X::pointerT>(w)X::pointer static_pointer_cast< X::pointerT>(w) == pstatic_pointer_cast< X::const_pointerconst T>(w)X::const_pointer static_pointer_cast< X::const_pointerconst T>(z) == q
[ LEWG Kona 2017 ]
Recommend NAD: NAD. Should bring a paper as a proposal for 2020.
[ Moved to NAD Future at 2010-11 Batavia ]
This is a new feature rather than a defect. It can be added later: "this is such a hairy area that people will put up with changes"
[ 2010-03-26 Daniel made editorial adjustments to the proposed wording. ]
In section [allocator.requirements], Table 40 — Allocator requirements, the following expression is required for allocator pointers:
Table 40 — Allocator requirements Expression Return type Assertion/note
pre-/post-conditionDefault static_cast<X::pointer>(w) X::pointer static_cast<X::pointer>(w) == p
To achieve this expression, a smart pointer writer must introduce an explicit conversion operator from smart_ptr<void> to smart_ptr<T> so that static_cast<pointer>(void_ptr) is a valid expression. Unfortunately this explicit conversion weakens the safety of a smart pointer since the following expression (invalid for raw pointers) would become valid:
smart_ptr<void> smart_v = ...; smart_ptr<T> smart_t(smart_v);
On the other hand, shared_ptr also defines its own casting functions in [util.smartptr.shared.cast], and although it's unlikely that a programmer will use shared_ptr as allocator::pointer, having two different ways to do the same cast operation does not seem reasonable. A possible solution would be to replace static_cast<X::pointer>(w) expression with a user customizable (via ADL) static_pointer_cast<value_type>(w), and establish the xxx_pointer_cast functions introduced by shared_ptr as the recommended generic casting utilities of the standard.
Unfortunately, we've experienced problems in Boost when trying to establish xxx_pointer_cast as customization points for generic libraries (http://objectmix.com/c/40424-adl-lookup-explicit-template-parameters.html) because these casting functions are called with explicit template parameters and the standard says in [temp.arg.explicit] p.8 "Explicit template argument specification":
8 ...But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply.
So we can do this:
template<class BasePtr> void generic_ptr_swap(BasePtr p) { //ADL customization point swap(p, p); //... }
but not the following:
template<class BasePtr> void generic_ptr_algo(BasePtr p) { typedef std::pointer_traits<BasePtr>::template rebind<Derived> DerivedPtr; DerivedPtr dp = static_pointer_cast<Derived>(p); }
The solution to make static_pointer_cast a customization point is to add a generic declaration (no definition) of static_pointer_cast in a namespace (like std) and apply "using std::static_pointer_cast" declaration to activate ADL:
namespace std{ template<typename U, typename T> unspecified static_pointer_cast(T&&) = delete; } template<class BasePtr> void generic_ptr_algo(BasePtr p) { typedef std::pointer_traits<BasePtr>::template rebind<Derived> DerivedPtr; //ADL applies because static_pointer_cast is made // visible according to [temp.arg.explicit]/8 using std::static_pointer_cast; DerivedPtr dp = static_pointer_cast<Derived>(p); //... }
A complete solution will need also the definition of static_pointer_cast for raw pointers, and this definition has been present in Boost (http://www.boost.org/boost/ pointer_cast.hpp) for years.
History | |||
---|---|---|---|
Date | User | Action | Args |
2018-06-22 06:38:21 | admin | set | messages: + msg9966 |
2018-06-22 06:38:21 | admin | set | status: lewg -> nad |
2014-11-24 15:11:58 | admin | set | status: nad future -> lewg |
2010-11-24 14:28:04 | admin | set | messages: + msg5445 |
2010-11-09 01:42:24 | admin | set | status: new -> nad future |
2010-10-21 18:28:33 | admin | set | messages: + msg1465 |
2010-10-21 18:28:33 | admin | set | messages: + msg1464 |
2009-12-14 00:00:00 | admin | create |