flat_foo is missing allocator-extended copy/move constructorsSection: 23.6.8 [flat.map], 23.6.9 [flat.multimap], 23.6.11 [flat.set], 23.6.12 [flat.multiset] Status: WP Submitter: Arthur O'Dwyer Opened: 2023-02-06 Last modified: 2023-11-22
Priority: Not Prioritized
View other active issues in [flat.map].
View all other issues in [flat.map].
View all issues with WP status.
Discussion:
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.
[2023-03-22; Reflector poll]
Set status to Tentatively Ready after five votes in favour during reflector poll.
[2023-06-17 Approved at June 2023 meeting in Varna. Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4928.
Modify 23.6.8.2 [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:
[…]
// 23.6.8.3 [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);
[…]
};
[…]
}
Modify 23.6.8.3 [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:
-12- Effects: Equivalent to the corresponding non-allocator constructors except thatuses_allocator_v<key_container_type, Allocator>istrueanduses_allocator_v<mapped_container_type, Allocator>istrue.c.keysandc.valuesare constructed with uses-allocator construction (20.2.8.2 [allocator.uses.construction]).
Modify 23.6.9.2 [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:
[…]
// 23.6.9.3 [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);
[…]
};
[…]
}
Modify 23.6.9.3 [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:
-12- Effects: Equivalent to the corresponding non-allocator constructors except thatuses_allocator_v<key_container_type, Allocator>istrueanduses_allocator_v<mapped_container_type, Allocator>istrue.c.keysandc.valuesare constructed with uses-allocator construction (20.2.8.2 [allocator.uses.construction]).
Modify 23.6.11.2 [flat.set.defn] as indicated:
namespace std {
template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>>
class flat_set {
public:
[…]
// 23.6.11.3 [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);
[…]
};
[…]
}
Modify 23.6.11.3 [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:
-10- Effects: Equivalent to the corresponding non-allocator constructors except thatuses_allocator_v<container_type, Allocator>istrue.cis constructed with uses-allocator construction (20.2.8.2 [allocator.uses.construction]).
Modify 23.6.12.2 [flat.multiset.defn] as indicated:
namespace std {
template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>>
class flat_multiset {
public:
[…]
// 23.6.12.3 [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);
[…]
};
[…]
}
Modify 23.6.12.3 [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:
-10- Effects: Equivalent to the corresponding non-allocator constructors except thatuses_allocator_v<container_type, Allocator>istrue.cis constructed with uses-allocator construction (20.2.8.2 [allocator.uses.construction]).