1. Changelog
- 
     R2: Move proposed wording into a single section, and remove Bikeshed "notes" that were never intended to propose new "Note" elements in the wording. 
- 
     R1: Incorporate LWG wording feedback. Mention [LWG3506] and [P1425R3]. 
2. Stop overconstraining allocators that do not participate in deduction
2.1. The problem
Consider this code:
std :: pmr :: monotonic_buffer_resource mr ; std :: pmr :: polymorphic_allocator < int > a = & mr ; std :: pmr :: vector < int > pv ( a ); auto s1 = std :: stack < int , std :: pmr :: vector < int >> ( pv ); auto s2 = std :: stack < int , std :: pmr :: vector < int >> ( pv , a ); auto s3 = std :: stack < int , std :: pmr :: vector < int >> ( pv , & mr ); auto ds1 = std :: stack ( pv ); auto ds2 = std :: stack ( pv , a ); auto ds3 = std :: stack ( pv , & mr ); 
The initializers of 
However, the natural and useful 
2.2. The explanation
template < class Container , class Allocator > stack ( Container , Allocator ) -> stack < typename Container :: value_type , Container > ; 
This deduction guide satisfies the following constraints.
[container.adaptors.general] says:
A deduction guide for a container adaptor shall not participate in overload resolution if any of the following are true: ...
It has an
template parameter and a type that does not qualify as an allocator is deduced for that parameter.Allocator 
It has both
andContainer template parameters, andAllocator isuses_allocator_v < Container , Allocator > false.
To qualify as an allocator, a type true.
Because the type of 
3. Stop deducing from allocators that should not participate in deduction
3.1. The problem
Consider the following code:
The initializers ofstd :: pmr :: monotonic_buffer_resource mr ; std :: pmr :: polymorphic_allocator < int > a = & mr ; std :: pmr :: vector < int > pv ( a ); auto v1 = std :: vector < int , std :: pmr :: polymorphic_allocator < int >> ( pv ); auto v2 = std :: vector < int , std :: pmr :: polymorphic_allocator < int >> ( pv , a ); auto v3 = std :: vector < int , std :: pmr :: polymorphic_allocator < int >> ( pv , & mr ); auto dv1 = std :: vector ( pv ); auto dv2 = std :: vector ( pv , a ); auto dv3 = std :: vector ( pv , & mr ); 
v1 v2 v3 dv1 dv2 But the initializer of 
Again, we know from the 
The problem we see with 
3.2. The explanation
template < class T , class Allocator > class vector { vector ( const vector < T , Allocator >& , const Allocator & ); }; 
From the first parameter, we deduce 
In this case, the second argument unnecessarily participates in deduction, and again unexpectedly prevents natural and useful code from working as desired.
Observe that even in the absence of CTAD, the signature above
permits construction only from the same specialization of 
std :: vector < T , A1 > v1 ; std :: vector < T , A2 > v2 ( v1 , A2 ()); // ill-formed 
4. Proposed wording
Modify [container.adaptors.general] as follows:
A deduction guide for a container adaptor shall not participate in overload resolution if any of the following are true:
It has an
template parameter and a type that does not qualify as an input iterator is deduced for that parameter.InputIterator 
It has a
template parameter and a type that qualifies as an allocator is deduced for that parameter.Compare 
It has a
template parameter and a type that qualifies as an allocator is deduced for that parameter.Container 
It has no
template parameter, and it has anContainer template parameter, and a type that does not qualify as an allocator is deduced for that parameter.Allocator 
It has both
andContainer template parameters, andAllocator isuses_allocator_v < Container , Allocator > false.
Modify [deque.overview] as follows:
deque ( deque && ); deque ( const deque & , const Allocator & ); deque ( const deque & , const type_identity_t < Allocator >& ); deque ( deque && , const Allocator & ); deque ( deque && , const type_identity_t < Allocator >& ); deque ( initializer_list < T > , const Allocator & = Allocator ()); 
Modify [forwardlist.overview] as follows:
forward_list ( forward_list && ); forward_list ( const forward_list & , const Allocator & ); forward_list ( const forward_list & , const type_identity_t < Allocator >& ); forward_list ( forward_list && , const Allocator & ); forward_list ( forward_list && , const type_identity_t < Allocator >& ); forward_list ( initializer_list < T > , const Allocator & = Allocator ()); 
Modify [list.overview] as follows:
list ( list && ); list ( const list & , const Allocator & ); list ( const list & , const type_identity_t < Allocator >& ); list ( list && , const Allocator & ); list ( list && , const type_identity_t < Allocator >& ); list ( initializer_list < T > , const Allocator & = Allocator ()); 
Modify [vector.overview] as follows:
constexpr vector ( vector && ) noexcept ; constexpr vector ( const vector & , const Allocator & ); constexpr vector ( const vector & , const type_identity_t < Allocator >& ); constexpr vector ( vector && , const Allocator & ); constexpr vector ( vector && , const type_identity_t < Allocator >& ); constexpr vector ( initializer_list < T > , const Allocator & = Allocator ()); 
Modify [vector.bool] as follows:
constexpr vector ( vector && x ); constexpr vector ( const vector & , const Allocator & ); constexpr vector ( const vector & , const type_identity_t < Allocator >& ); constexpr vector ( vector && , const Allocator & ); constexpr vector ( vector && , const type_identity_t < Allocator >& ); constexpr vector ( initializer_list < bool > , const Allocator & = Allocator ()); 
Modify [map.overview] as follows:
explicit map ( const Allocator & ); map ( const map & , const Allocator & ); map ( const map & , const type_identity_t < Allocator >& ); map ( map && , const Allocator & ); map ( map && , const type_identity_t < Allocator >& ); map ( initializer_list < value_type > , const Compare & = Compare , const Allocator & = Allocator ()); 
Modify [multimap.overview] as follows:
explicit multimap ( const Allocator & ); multimap ( const multimap & , const Allocator & ); multimap ( const multimap & , const type_identity_t < Allocator >& ); multimap ( multimap && , const Allocator & ); multimap ( multimap && , const type_identity_t < Allocator >& ); multimap ( initializer_list < value_type > , const Compare & = Compare , const Allocator & = Allocator ()); 
Modify [set.overview] as follows:
explicit set ( const Allocator & ); set ( const set & , const Allocator & ); set ( const set & , const type_identity_t < Allocator >& ); set ( set && , const Allocator & ); set ( set && , const type_identity_t < Allocator >& ); set ( initializer_list < value_type > , const Compare & = Compare (), const Allocator & = Allocator ()); 
Modify [multiset.overview] as follows:
explicit multiset ( const Allocator & ); multiset ( const multiset & , const Allocator & ); multiset ( const multiset & , const type_identity_t < Allocator >& ); multiset ( multiset && , const Allocator & ); multiset ( multiset && , const type_identity_t < Allocator >& ); multiset ( initializer_list < value_type > , const Compare & = Compare (), const Allocator & = Allocator ()); 
Modify [unord.map.overview] as follows:
explicit unordered_map ( const Allocator & ); unordered_map ( const unordered_map & , const Allocator & ); unordered_map ( const unordered_map & , const type_identity_t < Allocator >& ); unordered_map ( unordered_map && , const Allocator & ); unordered_map ( unordered_map && , const type_identity_t < Allocator >& ); unordered_map ( initializer_list < value_type > il , size_type n = see below , const hasher & hf = hasher (), const key_equal & eql = key_equal (), const allocator_type & a = allocator_type ()); 
Modify [unord.multimap.overview] as follows:
explicit unordered_multimap ( const Allocator & ); unordered_multimap ( const unordered_multimap & , const Allocator & ); unordered_multimap ( const unordered_multimap & , const type_identity_t < Allocator >& ); unordered_multimap ( unordered_multimap && , const Allocator & ); unordered_multimap ( unordered_multimap && , const type_identity_t < Allocator >& ); unordered_multimap ( initializer_list < value_type > il , size_type n = see below , const hasher & hf = hasher (), const key_equal & eql = key_equal (), const allocator_type & a = allocator_type ()); 
Modify [unord.set.overview] as follows:
explicit unordered_set ( const Allocator & ); unordered_set ( const unordered_set & , const Allocator & ); unordered_set ( const unordered_set & , const type_identity_t < Allocator >& ); unordered_set ( unordered_set && , const Allocator & ); unordered_set ( unordered_set && , const type_identity_t < Allocator >& ); unordered_set ( initializer_list < value_type > il , size_type n = see below , const hasher & hf = hasher (), const key_equal & eql = key_equal (), const allocator_type & a = allocator_type ()); 
Modify [unord.multiset.overview] as follows:
explicit unordered_multiset ( const Allocator & ); unordered_multiset ( const unordered_multiset & , const Allocator & ); unordered_multiset ( const unordered_multiset & , const type_identity_t < Allocator >& ); unordered_multiset ( unordered_multiset && , const Allocator & ); unordered_multiset ( unordered_multiset && , const type_identity_t < Allocator >& ); unordered_multiset ( initializer_list < value_type > il , size_type n = see below , const hasher & hf = hasher (), const key_equal & eql = key_equal (), const allocator_type & a = allocator_type ()); 
5. Implementation note
Some of the changes proposed in this paper have already been implemented "accidentally" by one or more library implementations, as shown in the following table and this Godbolt:| Construct | Well-formed | SFINAE-friendly ill-formed | Hard error | 
|---|---|---|---|
| std::deque(pd, &mr) | MSVC, libstdc++, libc++ | ||
| std::forward_list(pfl, &mr) | MSVC, libstdc++, libc++ | ||
| std::list(pl, &mr) | MSVC, libstdc++, libc++ | ||
| std::vector(pv, &mr) | MSVC, libstdc++, libc++ | ||
| std::map(pm, &mr) | MSVC, libc++ | libstdc++ | |
| std::multimap(pmm, &mr) | MSVC, libc++ | libstdc++ | |
| std::multiset(pms, &mr) | MSVC, libc++ | libstdc++ | |
| std::set(ps, &mr) | MSVC, libc++ | libstdc++ | |
| std::unordered_map(pum, &mr) | MSVC, libstdc++, libc++ | ||
| std::unordered_multimap(pumm, &mr) | MSVC, libstdc++, libc++ | ||
| std::unordered_multiset(pums, &mr) | MSVC, libstdc++, libc++ | ||
| std::unordered_set(pus, &mr) | MSVC, libstdc++, libc++ | ||
| std::priority_queue(ppq, &mr) | MSVC, libstdc++, libc++ | ||
| std::queue(pq, &mr) | MSVC, libstdc++, libc++ | ||
| std::stack(ps, &mr) | MSVC, libstdc++, libc++ | ||
| std::priority_queue(comp, pv, &mr) | MSVC, libstdc++, libc++ | ||
| std::queue(pd, &mr) | MSVC, libstdc++, libc++ | ||
| std::stack(pv, &mr) | MSVC, libstdc++, libc++ |