Title
flat_foo is missing allocator-extended copy/move constructors
Status
wp
Section
[flat.map][flat.multimap] [flat.set][flat.multiset]
Submitter
Arthur O'Dwyer

Created on 2023-02-06.00:00:00 last changed 18 months ago

Messages

Date: 2023-06-19.14:50:03

Proposed resolution:

This wording is relative to N4928.

  1. Modify [flat.map.defn] as indicated:

    namespace std {
      template<class Key, class T, class Compare = less<Key>,
      class KeyContainer = vector<Key>, class MappedContainer = vector<T>>
      class flat_map {
      public:
        […]
        // [flat.map.cons], construct/copy/destroy
        flat_map() : flat_map(key_compare()) { }
    
        template<class Allocator>
          flat_map(const flat_map&, const Allocator& a);
        template<class Allocator>
          flat_map(flat_map&&, const Allocator& a);
    
        […]
      };
      […]
    }
    
  2. Modify [flat.map.cons] as indicated:

    [Drafting note: As a drive-by fix, a missing closing > is inserted in p11.]

    template<class Allocator>
      flat_map(const flat_map&, const Allocator& a);
    template<class Allocator>
      flat_map(flat_map&&, const Allocator& a);
    template<class Allocator>
      flat_map(const key_compare& comp, const Allocator& a);
    template<class Allocator>
      explicit flat_map(const Allocator& a);
    template<class InputIterator, class Allocator>
      flat_map(InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a);
    template<class InputIterator, class Allocator>
      flat_map(InputIterator first, InputIterator last, const Allocator& a);
    […]
    

    -11- Constraints: uses_allocator_v<key_container_type, Allocator> is true and uses_allocator_v<mapped_container_type, Allocator> is true.

    -12- Effects: Equivalent to the corresponding non-allocator constructors except that c.keys and c.values are constructed with uses-allocator construction ([allocator.uses.construction]).

  3. Modify [flat.multimap.defn] as indicated:

    namespace std {
      template<class Key, class T, class Compare = less<Key>,
      class KeyContainer = vector<Key>, class MappedContainer = vector<T>>
      class flat_multimap {
      public:
        […]
        // [flat.multimap.cons], construct/copy/destroy
        flat_multimap() : flat_multimap(key_compare()) { }
    
        template<class Allocator>
          flat_multimap(const flat_multimap&, const Allocator& a);
        template<class Allocator>
          flat_multimap(flat_multimap&&, const Allocator& a);
    
        […]
      };
      […]
    }
    
  4. Modify [flat.multimap.cons] as indicated:

    template<class Allocator>
      flat_multimap(const flat_multimap&, const Allocator& a);
    template<class Allocator>
      flat_multimap(flat_multimap&&, const Allocator& a);
    template<class Allocator>
      flat_multimap(const key_compare& comp, const Allocator& a);
    […]
    

    -11- Constraints: uses_allocator_v<key_container_type, Allocator> is true and uses_allocator_v<mapped_container_type, Allocator> is true.

    -12- Effects: Equivalent to the corresponding non-allocator constructors except that c.keys and c.values are constructed with uses-allocator construction ([allocator.uses.construction]).

  5. Modify [flat.set.defn] as indicated:

    namespace std {
      template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>>
      class flat_set {
      public:
        […]
        // [flat.set.cons], constructors
        flat_set() : flat_set(key_compare()) { }
    
        template<class Allocator>
          flat_set(const flat_set&, const Allocator& a);
        template<class Allocator>
          flat_set(flat_set&&, const Allocator& a);
    
        […]
      };
      […]
    }
    
  6. Modify [flat.set.cons] as indicated:

    template<class Allocator>
      flat_set(const flat_set&, const Allocator& a);
    template<class Allocator>
      flat_set(flat_set&&, const Allocator& a);
    template<class Allocator>
      flat_set(const key_compare& comp, const Allocator& a);
    […]
    

    -9- Constraints: uses_allocator_v<container_type, Allocator> is true.

    -10- Effects: Equivalent to the corresponding non-allocator constructors except that c is constructed with uses-allocator construction ([allocator.uses.construction]).

  7. Modify [flat.multiset.defn] as indicated:

    namespace std {
      template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>>
      class flat_multiset {
      public:
        […]
        // [flat.multiset.cons], constructors
        flat_multiset() : flat_multiset(key_compare()) { }
    
        template<class Allocator>
          flat_multiset(const flat_multiset&, const Allocator& a);
        template<class Allocator>
          flat_multiset(flat_multiset&&, const Allocator& a);
    
        […]
      };
      […]
    }
    
  8. Modify [flat.multiset.cons] as indicated:

    template<class Allocator>
      flat_multiset(const flat_multiset&, const Allocator& a);
    template<class Allocator>
      flat_multiset(flat_multiset&&, const Allocator& a);
    template<class Allocator>
      flat_multiset(const key_compare& comp, const Allocator& a);
    […]
    

    -9- Constraints: uses_allocator_v<container_type, Allocator> is true.

    -10- Effects: Equivalent to the corresponding non-allocator constructors except that c is constructed with uses-allocator construction ([allocator.uses.construction]).

Date: 2023-06-17.00:00:00

[ 2023-06-17 Approved at June 2023 meeting in Varna. Status changed: Voting → WP. ]

Date: 2023-03-15.00:00:00

[ 2023-03-22; Reflector poll ]

Set status to Tentatively Ready after five votes in favour during reflector poll.

Date: 2023-02-06.00:00:00

This issue is part of the "flat_foo" sequence, LWG 3786, 3802, 3803, 3804. flat_set, flat_multiset, flat_map, and flat_multimap all have implicitly defaulted copy and move constructors, but they lack allocator-extended versions of those constructors. This means that the following code is broken:

// https://godbolt.org/z/qezv5rTrW
#include <cassert>
#include <flat_set>
#include <memory_resource>
#include <utility>
#include <vector>

template<class T, class Comp = std::less<T>>
using pmr_flat_set = std::flat_set<T, Comp, std::pmr::vector<T>>;

int main() {
  std::pmr::vector<pmr_flat_set<int>> vs = {
    {1,2,3},
    {4,5,6},
  };
  std::pmr::vector<int> v = std::move(vs[0]).extract();
  assert(v.get_allocator().resource() == std::pmr::get_default_resource());
}

pmr_flat_set<int> advertises that it "uses_allocator" std::pmr::polymorphic_allocator<int>, but in fact it lacks the allocator-extended constructor overload set necessary to interoperate with std::pmr::vector.

History
Date User Action Args
2023-06-19 14:50:03adminsetmessages: + msg13643
2023-06-19 14:50:03adminsetstatus: voting -> wp
2023-06-12 08:52:25adminsetstatus: ready -> voting
2023-03-22 22:31:39adminsetmessages: + msg13466
2023-03-22 22:31:39adminsetstatus: new -> ready
2023-02-19 11:47:07adminsetmessages: + msg13413
2023-02-06 00:00:00admincreate