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.
scoped_allocator_adaptor
constructors must be constrainedSection: 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.
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
-2- Requires:OuterAlloc
shall be constructible fromOuterA2
.OuterAlloc
base class withstd::forward<OuterA2>(outerAlloc)
and inner withinnerAllocs...
(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 unlessis_constructible_v<OuterAlloc, OuterA2>
istrue
. […]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
-6- Requires:OuterAlloc
shall be constructible fromOuterA2
.other
. -?- Remarks: This constructor shall not participate in overload resolution unlessis_constructible_v<OuterAlloc, const OuterA2&>
istrue
.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
-8- Requires:OuterAlloc
shall be constructible fromOuterA2
.other
. -?- Remarks: This constructor shall not participate in overload resolution unlessis_constructible_v<OuterAlloc, OuterA2>
istrue
.