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

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

Section: 23.12.3.2 [mem.poly.allocator.mem], 23.13.4 [allocator.adaptor.members] Status: WP Submitter: Casey Carter Opened: 2017-06-13 Last modified: 2018-03-24

Priority: 3

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

View all issues with WP 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 pairs 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 23.12.3.2 [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 23.10.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 23.13.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 23.12.3.2 [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 23.10.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 23.13.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.