Title
Missing case for pair construction in scoped and polymorphic allocators
Status
c++20
Section
[mem.poly.allocator.mem][allocator.adaptor.members]
Submitter
Casey Carter

Created on 2017-06-13.00:00:00 last changed 36 months ago

Messages

Date: 2018-03-18.16:03:30

Proposed resolution:

This wording is relative to N4659.

  1. Modify [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 [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 [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.

Date: 2018-03-17.00:00:00

[ 2018-3-17 Adopted in Jacksonville ]

Date: 2017-11-10.03:05:33

[ 2017-11 Albuquerque Wednesday issue processing ]

Move to Ready.

Date: 2017-11-02.00:00:00

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

Date: 2017-11-02.17:34:39

[ 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 [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 [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 [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.

Date: 2017-06-13.00:00:00

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 pairs as intended.

History
Date User Action Args
2021-02-25 10:48:01adminsetstatus: wp -> c++20
2018-03-18 16:03:30adminsetmessages: + msg9731
2018-03-18 16:03:30adminsetstatus: voting -> wp
2018-02-12 01:13:49adminsetstatus: ready -> voting
2017-11-10 03:05:33adminsetmessages: + msg9541
2017-11-10 03:05:33adminsetstatus: new -> ready
2017-11-02 17:34:39adminsetmessages: + msg9501
2017-07-12 01:30:31adminsetmessages: + msg9342
2017-06-13 18:53:49adminsetmessages: + msg9251
2017-06-13 00:00:00admincreate