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.

### 2975. Missing case for `pair` construction in scoped and polymorphic allocators

Section: 20.4.3.3 [mem.poly.allocator.mem], 20.5.4 [allocator.adaptor.members] Status: C++20 Submitter: Casey Carter Opened: 2017-06-13 Last modified: 2021-02-25

Priority: 3

View all other issues in [mem.poly.allocator.mem].

View all issues with C++20 status.

Discussion:

`scoped_allocator_adaptor` ([allocator.adaptor.syn]) and `polymorphic_allocator` ([mem.poly.allocator.class]) have identical families of members named `construct`:

>     template <class T, class... Args>
>       void construct(T* p, Args&&... args);

>     template <class T1, class T2, class... Args1, class... Args2>
>       void construct(pair<T1,T2>* p, piecewise_construct_t,
>                      tuple<Args1...> x, tuple<Args2...> y);
>     template <class T1, class T2>
>       void construct(pair<T1,T2>* p);
>     template <class T1, class T2, class U, class V>
>       void construct(pair<T1,T2>* p, U&& x, V&& y);
>     template <class T1, class T2, class U, class V>
>       void construct(pair<T1,T2>* p, const pair<U, V>& pr);
>     template <class T1, class T2, class U, class V>
>       void construct(pair<T1,T2>* p, pair<U, V>&& pr);

Both allocators perform `uses_allocator` construction, and therefore need special handling for `pair` constructions since `pair` doesn't specialize `uses_allocator` (`tuple` gets all of that magic and `pair` is left out in the cold). Presumably, the intent is that the `construct` overloads whose first argument is a pointer to `pair` capture all `pair` constructions. This is not the case: invoking `construct` with a `pair` pointer and a non-constant lvalue `pair` resolves to the first overload when it is viable: it's a better match than the `pair`-pointer-and-`const`-lvalue-`pair` overload. The first overload notably does not properly perform piecewise `uses_allocator` construction for `pair`s as intended.

[2017-07 Toronto Monday issue prioritization]

Priority 2; Marshall to work with Casey to reduce the negations in the wording.

Previous resolution [SUPERSEDED]:

> 1. Modify 20.4.3.3 [mem.poly.allocator.mem] as indicated:

>    >     template <class T, class... Args>
>    >       void construct(T* p, Args&&... args);

>    > > -5- Requires: Uses-allocator construction of `T` with allocator `resource()` (see 20.2.8.2 [allocator.uses.construction]) and constructor arguments `std::forward<Args>(args)...` is well-formed. [Note: Uses-allocator construction is always well formed for types that do not use allocators. — end note]

>    > > -6- Effects: Construct a `T` object in the storage whose address is represented by `p` by uses-allocator construction with allocator `resource()` and constructor arguments `std::forward<Args>(args)...`.

>    > > -7- Throws: Nothing unless the constructor for `T` throws.

>    > > -?- Remarks: This function shall not participate in overload resolution unless `T` is not a specialization of `pair`.

> 2. Modify 20.5.4 [allocator.adaptor.members] as indicated:

>    >     template <class T, class... Args>
>    >       void construct(T* p, Args&&... args);

>    > > -9- Effects: […]

>    > > -?- Remarks: This function shall not participate in overload resolution unless `T` is not a specialization of `pair`.

[2017-11-02 Marshall and Casey provide updated wording]

[2017-11 Albuquerque Wednesday issue processing]

Move to Ready.

[2018-3-17 Adopted in Jacksonville]

Proposed resolution:

This wording is relative to N4659.

1. Modify 20.4.3.3 [mem.poly.allocator.mem] as indicated:

   >     template <class T, class... Args>
   >       void construct(T* p, Args&&... args);

   > > -5- Requires: Uses-allocator construction of `T` with allocator `resource()` (see 20.2.8.2 [allocator.uses.construction]) and constructor arguments `std::forward<Args>(args)...` is well-formed. [Note: Uses-allocator construction is always well formed for types that do not use allocators. — end note]

   > > -6- Effects: Construct a `T` object in the storage whose address is represented by `p` by uses-allocator construction with allocator `resource()` and constructor arguments `std::forward<Args>(args)...`.

   > > -7- Throws: Nothing unless the constructor for `T` throws.

   > > -?- Remarks: This function shall not participate in overload resolution if `T` is a specialization of `pair`.

2. Modify 20.5.4 [allocator.adaptor.members] as indicated:

   >     template <class T, class... Args>
   >       void construct(T* p, Args&&... args);

   > > -9- Effects: […]

   > > -?- Remarks: This function shall not participate in overload resolution if `T` is a specialization of `pair`.