This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++17 status.
Section: 20.5.3 [allocator.adaptor.cnstr] Status: C++17 Submitter: Jonathan Wakely Opened: 2016-10-14 Last modified: 2017-07-30
Priority: 0
View all issues with C++17 status.
Discussion:
The templated constructors of scoped_allocator_adaptor need to be constrained, otherwise uses-allocator construction gives the wrong answer and causes errors for code that should compile.
Consider two incompatible allocator types:template<class T> struct Alloc1 { ... }; template<class T> struct Alloc2 { ... }; static_assert(!is_convertible_v<Alloc1<int>, Alloc2<int>>);
The unconstrained constructors give this bogus answer:
template<class T> using scoped = scoped_allocator_adaptor<T>; static_assert(is_convertible_v<scoped<Alloc1<int>>, scoped<Alloc2<int>>>);
This causes uses_allocator to give the wrong answer for any specialization involving incompatible scoped_allocator_adaptors, which makes scoped_allocator_adaptor::construct() take an ill-formed branch e.g.
struct X { using allocator_type = scoped<Alloc2<int>>; X(const allocator_type&); X(); }; scoped<Alloc1<int>>{}.construct((X*)0);
This fails to compile, because uses_allocator<X, scoped_allocator_adaptor<Alloc2<int>>> is true, so the allocator is passed to the X constructor, but the conversion fails. The error is outside the immediate context, and so is a hard error.
[2016-11-12, Issaquah]
Sat AM: Priority 0; move to Ready
Billy to open another issue about the confusion with the ctor
Proposed resolution:
This wording is relative to N4606.
Modify 20.5.3 [allocator.adaptor.cnstr] by converting "Requires" elements to "Remarks: shall not participate ..." constraints as shown:
template <class OuterA2> scoped_allocator_adaptor(OuterA2&& outerAlloc, const InnerAllocs&... innerAllocs) noexcept;-3- Effects: Initializes the OuterAlloc base class with std::forward<OuterA2>(outerAlloc) and inner with innerAllocs... (hence recursively initializing each allocator within the adaptor with the corresponding allocator from the argument list). -?- Remarks: This constructor shall not participate in overload resolution unless is_constructible_v<OuterAlloc, OuterA2> is true. […]
-2- Requires: OuterAlloc shall be constructible from OuterA2.template <class OuterA2> scoped_allocator_adaptor(const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& other) noexcept;-7- Effects: Initializes each allocator within the adaptor with the corresponding allocator from other. -?- Remarks: This constructor shall not participate in overload resolution unless is_constructible_v<OuterAlloc, const OuterA2&> is true.
-6- Requires: OuterAlloc shall be constructible from OuterA2.template <class OuterA2> scoped_allocator_adaptor(scoped_allocator_adaptor<OuterA2, InnerAllocs...>&& other) noexcept;-9- Effects: Initializes each allocator within the adaptor with the corresponding allocator rvalue from other. -?- Remarks: This constructor shall not participate in overload resolution unless is_constructible_v<OuterAlloc, OuterA2> is true.
-8- Requires: OuterAlloc shall be constructible from OuterA2.