flat_foo
constructors taking KeyContainer
lack KeyCompare
parameterSection: 23.6.8 [flat.map], 23.6.9 [flat.multimap], 23.6.11 [flat.set], 23.6.12 [flat.multiset] Status: C++23 Submitter: Arthur O'Dwyer Opened: 2022-10-25 Last modified: 2023-11-22
Priority: 1
View other active issues in [flat.map].
View all other issues in [flat.map].
View all issues with C++23 status.
Discussion:
flat_set
's current constructor overload set has these two overloads:
explicit flat_set(container_type cont); template<class Allocator> flat_set(const container_type& cont, const Allocator& a);
I believe it should have these two in addition:
flat_set(const key_compare& comp, container_type cont); template<class Allocator> flat_set(const key_compare& comp, const container_type& cont, const Allocator& a);
with corresponding deduction guides. Similar wording changes would have to be made to all the
flat_foo
containers.
struct LessWhenDividedBy { int divisor_; bool operator()(int x, int y) const { return x/divisor_ < y/divisor_; } }; std::flat_set<int, LessWhenDividedBy> s(data.begin(), data.end(), LessWhenDividedBy(10)); // BEFORE AND AFTER: okay, but cumbersome std::flat_set<int, LessWhenDividedBy> s(data); // BEFORE AND AFTER: oops, this default-constructs the comparator std::flat_set<int, LessWhenDividedBy> s(LessWhenDividedBy(10), data); // BEFORE: fails to compile // AFTER: compiles successfully
[2022-11-04; Reflector poll]
Set priority to 1 after reflector poll.
[2023-02-09 Tim adds wording]
For each construction that takes containers, this wording allow a comparator to be specified as well.
Differing from the suggestion in the issue, the comparator goes last (but before the allocator),
for consistency with every other constructor of flat_meow
taking a comparator.
(This is inconsistent with priority_queue
, but consistency among the type's own
constructors seems more important.)
[Issaquah 2023-02-09; LWG]
Move to Immediate for C++23
[2023-02-13 Approved at February 2023 meeting in Issaquah. Status changed: Immediate → WP.]
Proposed resolution:
This wording is relative to N4928.
Add a new bullet to 23.6.1 [container.adaptors.general] p6 as indicated:
-6- A deduction guide for a container adaptor shall not participate in overload resolution if any of the following are true:
— (6.?) It has both
KeyContainer
andCompare
template parameters, andis_invocable_v<const Compare&, const typename KeyContainer::value_type&, const typename KeyContainer::value_type&>
is not a valid expression or isfalse
.
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()) { } flat_map(key_container_type key_cont, mapped_container_type mapped_cont, const key_compare& comp = key_compare()); template<class Allocator> flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont, const Allocator& a); template<class Allocator> flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont, const key_compare& comp, const Allocator& a); flat_map(sorted_unique_t, key_container_type key_cont, mapped_container_type mapped_cont, const key_compare& comp = key_compare()); template<class Allocator> flat_map(sorted_unique_t, const key_container_type& key_cont, const mapped_container_type& mapped_cont, const Allocator& a); template<class Allocator> flat_map(sorted_unique_t, const key_container_type& key_cont, const mapped_container_type& mapped_cont, const key_compare& comp, const Allocator& a); […] }; template<class KeyContainer, class MappedContainer, class Compare = less<typename KeyContainer::value_type>> flat_map(KeyContainer, MappedContainer, Compare = Compare()) -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type, Compareless<typename KeyContainer::value_type>, KeyContainer, MappedContainer>; template<class KeyContainer, class MappedContainer, class Allocator> flat_map(KeyContainer, MappedContainer, Allocator) -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type, less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>; template<class KeyContainer, class MappedContainer, class Compare, class Allocator> flat_map(KeyContainer, MappedContainer, Compare, Allocator) -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type, Compare, KeyContainer, MappedContainer>; template<class KeyContainer, class MappedContainer, class Compare = less<typename KeyContainer::value_type>> flat_map(sorted_unique_t, KeyContainer, MappedContainer, Compare = Compare()) -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type, Compareless<typename KeyContainer::value_type>, KeyContainer, MappedContainer>; template<class KeyContainer, class MappedContainer, class Allocator> flat_map(sorted_unique_t, KeyContainer, MappedContainer, Allocator) -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type, less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>; template<class KeyContainer, class MappedContainer, class Compare, class Allocator> flat_map(sorted_unique_t, KeyContainer, MappedContainer, Compare, Allocator) -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type, Compare, KeyContainer, MappedContainer>; […] }
Modify 23.6.8.3 [flat.map.cons] as indicated:
flat_map(key_container_type key_cont, mapped_container_type mapped_cont, const key_compare& comp = key_compare());-1- Effects: Initializes
c.keys
withstd::move(key_cont)
,andc.values
withstd::move(mapped_cont)
, andcompare
withcomp
; value-initializes; sorts the rangecompare
[begin(), end())
with respect tovalue_comp()
; and finally erases the duplicate elements as if by:auto zv = ranges::zip_view(c.keys, c.values); auto it = ranges::unique(zv, key_equiv(compare)).begin(); auto dist = distance(zv.begin(), it); c.keys.erase(c.keys.begin() + dist, c.keys.end()); c.values.erase(c.values.begin() + dist, c.values.end());-2- Complexity: Linear in N if the container arguments are already sorted with respect to
value_comp()
and otherwise N log N, where N is the value ofkey_cont.size()
before this call.template<class Allocator> flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont, const Allocator& a); template<class Allocator> flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont, const key_compare& comp, const Allocator& a);-3- Constraints:
-4- Effects: Equivalent touses_allocator_v<key_container_type, Allocator>
istrue
anduses_allocator_v<mapped_container_type, Allocator>
istrue
.flat_map(key_cont, mapped_cont)
andflat_map(key_cont, mapped_cont, comp)
, respectively, except thatc.keys
andc.values
are constructed with uses-allocator construction (20.2.8.2 [allocator.uses.construction]). -5- Complexity: Same asflat_map(key_cont, mapped_cont)
andflat_map(key_cont, mapped_cont, comp)
, respectively.flat_map(sorted_unique_t, key_container_type key_cont, mapped_container_type mapped_cont, const key_compare& comp = key_compare());-6- Effects: Initializes
-7- Complexity: Constant.c.keys
withstd::move(key_cont)
,andc.values
withstd::move(mapped_cont)
, andcompare
withcomp
; value-initializes.compare
template<class Allocator> flat_map(sorted_unique_t s, const key_container_type& key_cont, const mapped_container_type& mapped_cont, const Allocator& a); template<class Allocator> flat_map(sorted_unique_t s, const key_container_type& key_cont, const mapped_container_type& mapped_cont, const key_compare& comp, const Allocator& a);-8- Constraints:
-9- Effects: Equivalent touses_allocator_v<key_container_type, Allocator>
istrue
anduses_allocator_v<mapped_container_type, Allocator>
istrue
.flat_map(s, key_cont, mapped_cont)
andflat_map(s, key_cont, mapped_cont, comp)
, respectively, except thatc.keys
andc.values
are constructed with uses-allocator construction (20.2.8.2 [allocator.uses.construction]). -10- Complexity: Linear.
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()) { } flat_multimap(key_container_type key_cont, mapped_container_type mapped_cont, const key_compare& comp = key_compare()); template<class Allocator> flat_multimap(const key_container_type& key_cont, const mapped_container_type& mapped_cont, const Allocator& a); template<class Allocator> flat_multimap(const key_container_type& key_cont, const mapped_container_type& mapped_cont, const key_compare& comp, const Allocator& a); flat_multimap(sorted_equivalent_t, key_container_type key_cont, mapped_container_type mapped_cont, const key_compare& comp = key_compare()); template<class Allocator> flat_multimap(sorted_equivalent_t, const key_container_type& key_cont, const mapped_container_type& mapped_cont, const Allocator& a); template<class Allocator> flat_multimap(sorted_equivalent_t, const key_container_type& key_cont, const mapped_container_type& mapped_cont, const key_compare& comp, const Allocator& a); […] }; template<class KeyContainer, class MappedContainer, class Compare = less<typename KeyContainer::value_type>> flat_multimap(KeyContainer, MappedContainer, Compare = Compare()) -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type, Compareless<typename KeyContainer::value_type>, KeyContainer, MappedContainer>; template<class KeyContainer, class MappedContainer, class Allocator> flat_multimap(KeyContainer, MappedContainer, Allocator) -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type, less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>; template<class KeyContainer, class MappedContainer, class Compare, class Allocator> flat_multimap(KeyContainer, MappedContainer, Compare, Allocator) -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type, Compare, KeyContainer, MappedContainer>; template<class KeyContainer, class MappedContainer, class Compare = less<typename KeyContainer::value_type>> flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Compare = Compare()) -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type, Compareless<typename KeyContainer::value_type>, KeyContainer, MappedContainer>; template<class KeyContainer, class MappedContainer, class Allocator> flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Allocator) -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type, less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>; template<class KeyContainer, class MappedContainer, class Compare, class Allocator> flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Compare, Allocator) -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type, Compare, KeyContainer, MappedContainer>; […] }
Modify 23.6.9.3 [flat.multimap.cons] as indicated:
flat_multimap(key_container_type key_cont, mapped_container_type mapped_cont, const key_compare& comp = key_compare());-1- Effects: Initializes
c.keys
withstd::move(key_cont)
,andc.values
withstd::move(mapped_cont)
, andcompare
withcomp
; value-initializes; and sorts the rangecompare
[begin(), end())
with respect tovalue_comp()
.-2- Complexity: Linear in N if the container arguments are already sorted with respect to
value_comp()
and otherwise N log N, where N is the value ofkey_cont.size()
before this call.template<class Allocator> flat_multimap(const key_container_type& key_cont, const mapped_container_type& mapped_cont, const Allocator& a); template<class Allocator> flat_multimap(const key_container_type& key_cont, const mapped_container_type& mapped_cont, const key_compare& comp, const Allocator& a);-3- Constraints:
-4- Effects: Equivalent touses_allocator_v<key_container_type, Allocator>
istrue
anduses_allocator_v<mapped_container_type, Allocator>
istrue
.flat_multimap(key_cont, mapped_cont)
andflat_multimap(key_cont, mapped_cont, comp)
, respectively, except thatc.keys
andc.values
are constructed with uses-allocator construction (20.2.8.2 [allocator.uses.construction]). -5- Complexity: Same asflat_multimap(key_cont, mapped_cont)
andflat_multimap(key_cont, mapped_cont, comp)
, respectively.flat_multimap(sorted_equivalent_t, key_container_type key_cont, mapped_container_type mapped_cont, const key_compare& comp = key_compare());-6- Effects: Initializes
-7- Complexity: Constant.c.keys
withstd::move(key_cont)
,andc.values
withstd::move(mapped_cont)
, andcompare
withcomp
; value-initializes.compare
template<class Allocator> flat_multimap(sorted_equivalent_t s, const key_container_type& key_cont, const mapped_container_type& mapped_cont, const Allocator& a); template<class Allocator> flat_multimap(sorted_equivalent_t s, const key_container_type& key_cont, const mapped_container_type& mapped_cont, const key_compare& comp, const Allocator& a);-8- Constraints:
-9- Effects: Equivalent touses_allocator_v<key_container_type, Allocator>
istrue
anduses_allocator_v<mapped_container_type, Allocator>
istrue
.flat_multimap(s, key_cont, mapped_cont)
andflat_multimap(s, key_cont, mapped_cont, comp)
, respectively, except thatc.keys
andc.values
are constructed with uses-allocator construction (20.2.8.2 [allocator.uses.construction]). -10- Complexity: Linear.
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: […] // [flat.set.cons], constructors flat_set() : flat_set(key_compare()) { } explicit flat_set(container_type cont, const key_compare& comp = key_compare()); template<class Allocator> flat_set(const container_type& cont, const Allocator& a); template<class Allocator> flat_set(const container_type& cont, const key_compare& comp, const Allocator& a); flat_set(sorted_unique_t, container_type cont, const key_compare& comp = key_compare()) : c(std::move(cont)), compare(compkey_compare()) { } template<class Allocator> flat_set(sorted_unique_t, const container_type& cont, const Allocator& a); template<class Allocator> flat_set(sorted_unique_t, const container_type& cont, const key_compare& comp, const Allocator& a); […] }; template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>> flat_set(KeyContainer, Compare = Compare()) -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>; template<class KeyContainer, class Allocator> flat_set(KeyContainer, Allocator) -> flat_set<typename KeyContainer::value_type, less<typename KeyContainer::value_type>, KeyContainer>; template<class KeyContainer, class Compare, class Allocator> flat_set(KeyContainer, Compare, Allocator) -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>; template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>> flat_set(sorted_unique_t, KeyContainer, Compare = Compare()) -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>; template<class KeyContainer, class Allocator> flat_set(sorted_unique_t, KeyContainer, Allocator) -> flat_set<typename KeyContainer::value_type, less<typename KeyContainer::value_type>, KeyContainer>; template<class KeyContainer, class Compare, class Allocator> flat_set(sorted_unique_t, KeyContainer, Compare, Allocator) -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>; […] }
Modify 23.6.11.3 [flat.set.cons] as indicated:
flat_set(container_type cont, const key_compare& comp = key_compare());-1- Effects: Initializes
c
withstd::move(cont)
andcompare
withcomp
, value-initializes, sorts the rangecompare
[begin(), end())
with respect tocompare
, and finally erases all but the first element from each group of consecutive equivalent elements.-2- Complexity: Linear in N if
cont
is already sorted with respect tocompare
and otherwise N log N, where N is the value ofcont.size()
before this call.template<class Allocator> flat_set(const container_type& cont, const Allocator& a); template<class Allocator> flat_set(const container_type& cont, const key_compare& comp, const Allocator& a);-3- Constraints:
-4- Effects: Equivalent touses_allocator_v<container_type, Allocator>
istrue
.flat_set(cont)
andflat_set(cont, comp)
, respectively, except thatc
is constructed with uses-allocator construction (20.2.8.2 [allocator.uses.construction]). -5- Complexity: Same asflat_set(cont)
andflat_set(cont, comp)
, respectively.template<class Allocator> flat_set(sorted_unique_t s, const container_type& cont, const Allocator& a); template<class Allocator> flat_set(sorted_unique_t s, const container_type& cont, const key_compare& comp, const Allocator& a);-6- Constraints:
-7- Effects: Equivalent touses_allocator_v<container_type, Allocator>
istrue
.flat_set(s, cont)
andflat_set(s, cont, comp)
, respectively, except thatc
is constructed with uses-allocator construction (20.2.8.2 [allocator.uses.construction]). -8- Complexity: Linear.
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: […] // [flat.multiset.cons], constructors flat_multiset() : flat_multiset(key_compare()) { } explicit flat_multiset(container_type cont, const key_compare& comp = key_compare()); template<class Allocator> flat_multiset(const container_type& cont, const Allocator& a); template<class Allocator> flat_multiset(const container_type& cont, const key_compare& comp, const Allocator& a); flat_multiset(sorted_equivalent_t, container_type cont, const key_compare& comp = key_compare()) : c(std::move(cont)), compare(compkey_compare()) { } template<class Allocator> flat_multiset(sorted_equivalent_t, const container_type& cont, const Allocator& a); template<class Allocator> flat_multiset(sorted_equivalent_t, const container_type& cont, const key_compare& comp, const Allocator& a); […] }; template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>> flat_multiset(KeyContainer, Compare = Compare()) -> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>; template<class KeyContainer, class Allocator> flat_multiset(KeyContainer, Allocator) -> flat_multiset<typename KeyContainer::value_type, less<typename KeyContainer::value_type>, KeyContainer>; template<class KeyContainer, class Compare, class Allocator> flat_multiset(KeyContainer, Compare, Allocator) -> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>; template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>> flat_multiset(sorted_equivalent_t, KeyContainer, Compare = Compare()) -> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>; template<class KeyContainer, class Allocator> flat_multiset(sorted_equivalent_t, KeyContainer, Allocator) -> flat_multiset<typename KeyContainer::value_type, less<typename KeyContainer::value_type>, KeyContainer>; template<class KeyContainer, class Compare, class Allocator> flat_multiset(sorted_equivalent_t, KeyContainer, Compare, Allocator) -> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>; […] }
Modify 23.6.12.3 [flat.multiset.cons] as indicated:
flat_multiset(container_type cont, const key_compare& comp = key_compare());-1- Effects: Initializes
c
withstd::move(cont)
andcompare
withcomp
, value-initializes, and sorts the rangecompare
[begin(), end())
with respect tocompare
.-2- Complexity: Linear in N if
cont
is already sorted with respect tocompare
and otherwise N log N, where N is the value ofcont.size()
before this call.template<class Allocator> flat_multiset(const container_type& cont, const Allocator& a); template<class Allocator> flat_multiset(const container_type& cont, const key_compare& comp, const Allocator& a);-3- Constraints:
-4- Effects: Equivalent touses_allocator_v<container_type, Allocator>
istrue
.flat_multiset(cont)
andflat_multiset(cont, comp)
, respectively, except thatc
is constructed with uses-allocator construction (20.2.8.2 [allocator.uses.construction]). -5- Complexity: Same asflat_multiset(cont)
andflat_multiset(cont, comp)
, respectively.template<class Allocator> flat_multiset(sorted_equivalent_t s, const container_type& cont, const Allocator& a); template<class Allocator> flat_multiset(sorted_equivalent_t s, const container_type& cont, const key_compare& comp, const Allocator& a);-6- Constraints:
-7- Effects: Equivalent touses_allocator_v<container_type, Allocator>
istrue
.flat_multiset(s, cont)
andflat_multiset(s, cont, comp)
, respectively, except thatc
is constructed with uses-allocator construction (20.2.8.2 [allocator.uses.construction]). -8- Complexity: Linear.