This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++20 status.

### 3187. P0591R4 reverted DR 2586 fixes to `scoped_allocator_adaptor::construct()`

Section: 20.2.8.2 [allocator.uses.construction] Status: C++20 Submitter: Jonathan Wakely Opened: 2019-02-14 Last modified: 2021-02-25

Priority: Not Prioritized

View other active issues in [allocator.uses.construction].

View all other issues in [allocator.uses.construction].

View all issues with C++20 status.

Discussion:

2586 fixed the value category in the uses-allocator checks done by `scoped_allocator_adaptor`. When we made that use `uses_allocator_construction_args` we reintroduced the problem, because that function has the same bug.

>     #include <memory>

>     struct X {
>       using allocator_type = std::allocator<X>;
>       X(std::allocator_arg_t, allocator_type&&) { }
>       X(const allocator_type&) { }
>     };

>     int main() {
>       std::allocator<X> a;
>       std::make_obj_using_allocator<X>(a);
>     }

This will fail to compile, because `uses_allocator_construction_args` will check `is_constructible` using an rvalue allocator, but then return `tuple<allocator_arg_t, const allocator<X>&>` containing an lvalue allocator. Those args cannot be used to construct an `X`.

[2019-02; Kona Wednesday night issue processing]

Status to Ready

Proposed resolution:

This wording is relative to N4800.

1. Change 20.2.8.2 [allocator.uses.construction] as indicated:

   > [Drafting Note: Arguably the `uses_allocator` specialization should also use `const Alloc&` but in practice that doesn't matter, except for even more contrived cases than the very contrived example above.]

   >     template <class T, class Alloc, class... Args>
   >       auto uses_allocator_construction_args(const Alloc& alloc, Args&&... args) -> see below;

   > > […]

   > > -5- Returns: A `tuple` value determined as follows:

   > > 1. (5.1) — If `uses_allocator_v<T, Alloc>` is `false` and `is_constructible_v<T, Args...>` is `true`, return `forward_as_tuple(std::forward<Args>(args)...)`.

   > > 2. (5.2) — Otherwise, if `uses_allocator_v<T, Alloc>` is `true` and `is_constructible_v<T, allocator_arg_t, const Alloc&, Args...>` is `true`, return

   > >    >     tuple<allocator_arg_t, const Alloc&, Args&&...>(
   > >    >       allocator_arg, alloc, std::forward<Args>(args)...)

   > > 3. (5.3) — Otherwise, if `uses_allocator_v<T, Alloc>` is `true` and `is_constructible_v<T, Args..., const Alloc&>` is `true`, return `forward_as_tuple(std::forward<Args>(args)..., alloc)`.

   > > 4. (5.4) — Otherwise, the program is ill-formed.

   > > […]