This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of NAD status.
Section: 22.2 [utility] Status: NAD Submitter: Ion Gaztañaga Opened: 2009-12-14 Last modified: 2019-02-26
Priority: Not Prioritized
View all other issues in [utility].
View all issues with NAD status.
Discussion:
In section 16.4.4.6 [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 20.3.2.2.10 [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 13.10.2 [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.
[ 2010-03-26 Daniel made editorial adjustments to the proposed wording. ]
[ 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"
[LEWG Kona 2017]
Recommend NAD: NAD. Should bring a paper as a proposal for 2020.
Proposed resolution:
Add to section 22.2 [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 22.2 [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 16.4.4.6 [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