This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Resolved status.
Section: 20.5.4 [allocator.adaptor.members] Status: Resolved Submitter: Howard Hinnant Opened: 2010-02-16 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [allocator.adaptor.members].
View all issues with Resolved status.
Discussion:
20.5.4 [allocator.adaptor.members] p8-9 says:
template <class T, class... Args> void construct(T* p, Args&&... args);8 Effects: let OUTERMOST(x) be x if x does not have an outer_allocator() function and OUTERMOST(x.outer_allocator()) otherwise.
- If uses_allocator<T, inner_allocator_type>::value is false and is_constructible<T, Args...>::value is true, calls OUTERMOST(*this).construct(p, std::forward<Args>(args)...).
- Otherwise, if uses_allocator<T, inner_allocator_type>::value is true and is_constructible<T, allocator_arg_t, inner_allocator_type, Args...>::value is true, calls OUTERMOST(*this).construct(p, allocator_arg, inner_allocator(),std::forward<Args>(args)...).
- Otherwise, if uses_allocator<T, inner_allocator_type>::value is true and is_constructible<T, Args..., inner_allocator_type>::value is true, calls OUTERMOST(*this).construct(p, std::forward<Args>(args)..., inner_allocator()).
- Otherwise, the program is ill-formed. [Note: an error will result if uses_allocator evaluates to true but the specific constructor does not take an allocator. This definition prevents a silent failure to pass an inner allocator to a contained element. — end note]
template <class T> void destroy(T* p);9 Effects: calls outer_allocator().destroy(p).
In all other calls where applicable scoped_allocator_adaptor does not call members of an allocator directly, but rather does so indirectly via allocator_traits. For example:
size_type max_size() const;7 Returns: allocator_traits<OuterAlloc>::max_size(outer_allocator()).
Indeed, without the indirection through allocator_traits the definitions for construct and destroy are likely to fail at compile time since the outer_allocator() may not have the members construct and destroy.
[ The proposed wording is a product of Pablo, Daniel and Howard. ]
[ 2010 Pittsburgh: Moved to NAD Editorial. Rationale added below. ]
Rationale:
Solved by N3059.
Proposed resolution:
In 20.5.4 [allocator.adaptor.members] move and change p8 as indicated, and change p9 as indicated:
Let OUTERMOST(x) be x if x does not have an outer_allocator() member function and OUTERMOST(x.outer_allocator()) otherwise. Let OUTERMOST_ALLOC_TRAITS(x) be allocator_traits<decltype(OUTERMOST(x))>. [Note: OUTERMOST(x) and OUTERMOST_ALLOC_TRAITS(x) are recursive operations. It is incumbent upon the definition of outer_allocator() to ensure that the recursion terminates. It will terminate for all instantiations of scoped_allocator_adaptor. — end note]
template <class T, class... Args> void construct(T* p, Args&&... args);8 Effects:
let OUTERMOST(x) be x if x does not have an outer_allocator() function and OUTERMOST(x.outer_allocator()) otherwise.
- If uses_allocator<T, inner_allocator_type>::value is false and is_constructible<T, Args...>::value is true, calls
OUTERMOST(*this).OUTERMOST_ALLOC_TRAITS(outer_allocator())::construct( OUTERMOST(outer_allocator()), p, std::forward<Args>(args)... ).- Otherwise, if uses_allocator<T, inner_allocator_type>::value is true and is_constructible<T, allocator_arg_t, inner_allocator_type, Args...>::value is true, calls
OUTERMOST(*this).OUTERMOST_ALLOC_TRAITS(outer_allocator())::construct( OUTERMOST(outer_allocator()), p, allocator_arg, inner_allocator(), std::forward<Args>(args)... ).- Otherwise, if uses_allocator<T, inner_allocator_type>::value is true and is_constructible<T, Args..., inner_allocator_type>::value is true, calls
OUTERMOST(*this).OUTERMOST_ALLOC_TRAITS(outer_allocator())::construct( OUTERMOST(outer_allocator()), p, std::forward<Args>(args)..., inner_allocator() ).- Otherwise, the program is ill-formed. [Note: an error will result if uses_allocator evaluates to true but the specific constructor does not take an allocator. This definition prevents a silent failure to pass an inner allocator to a contained element. — end note]
template <class T> void destroy(T* p);9 Effects: calls
outer_allocator().OUTERMOST_ALLOC_TRAITS(outer_allocator())::destroy( OUTERMOST(outer_allocator()), p).