Created on 2022-10-25.00:00:00 last changed 12 months ago
Proposed resolution:
This wording is relative to n4928.
Add a new bullet to [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 and Compare template parameters, and is_invocable_v<const Compare&, const typename KeyContainer::value_type&, const typename KeyContainer::value_type&> is not a valid expression or is false.
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()) { } 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 [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 with std::move(key_cont),
andc.values with std::move(mapped_cont), and compare with comp; value-initializes compare; sorts the range [begin(), end()) with respect to value_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 of key_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: uses_allocator_v<key_container_type, Allocator> is true and uses_allocator_v<mapped_container_type, Allocator> is true.
-4- Effects: Equivalent to flat_map(key_cont, mapped_cont) and flat_map(key_cont, mapped_cont, comp), respectively, except that c.keys and c.values are constructed with uses-allocator construction ([allocator.uses.construction]). -5- Complexity: Same as flat_map(key_cont, mapped_cont) and flat_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 c.keys with std::move(key_cont),
-7- Complexity: Constant.andc.values with std::move(mapped_cont), and compare with comp; 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: uses_allocator_v<key_container_type, Allocator> is true and uses_allocator_v<mapped_container_type, Allocator> is true.
-9- Effects: Equivalent to flat_map(s, key_cont, mapped_cont) and flat_map(s, key_cont, mapped_cont, comp), respectively, except that c.keys and c.values are constructed with uses-allocator construction ([allocator.uses.construction]). -10- Complexity: Linear.
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()) { } 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 [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 with std::move(key_cont),
andc.values with std::move(mapped_cont), and compare with comp; value-initializes compare; and sorts the range [begin(), end()) with respect to value_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 of key_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: uses_allocator_v<key_container_type, Allocator> is true and uses_allocator_v<mapped_container_type, Allocator> is true.
-4- Effects: Equivalent to flat_multimap(key_cont, mapped_cont) and flat_multimap(key_cont, mapped_cont, comp), respectively, except that c.keys and c.values are constructed with uses-allocator construction ([allocator.uses.construction]). -5- Complexity: Same as flat_multimap(key_cont, mapped_cont) and flat_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 c.keys with std::move(key_cont),
-7- Complexity: Constant.andc.values with std::move(mapped_cont), and compare with comp; 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: uses_allocator_v<key_container_type, Allocator> is true and uses_allocator_v<mapped_container_type, Allocator> is true.
-9- Effects: Equivalent to flat_multimap(s, key_cont, mapped_cont) and flat_multimap(s, key_cont, mapped_cont, comp), respectively, except that c.keys and c.values are constructed with uses-allocator construction ([allocator.uses.construction]). -10- Complexity: Linear.
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()) { } 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 [flat.set.cons] as indicated:
flat_set(container_type cont, const key_compare& comp = key_compare());-1- Effects: Initializes c with std::move(cont) and compare with comp
, value-initializes compare, sorts the range [begin(), end()) with respect to compare, 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 to compare and otherwise N log N, where N is the value of cont.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: uses_allocator_v<container_type, Allocator> is true.
-4- Effects: Equivalent to flat_set(cont) and flat_set(cont, comp), respectively, except that c is constructed with uses-allocator construction ([allocator.uses.construction]). -5- Complexity: Same as flat_set(cont) and flat_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: uses_allocator_v<container_type, Allocator> is true.
-7- Effects: Equivalent to flat_set(s, cont) and flat_set(s, cont, comp), respectively, except that c is constructed with uses-allocator construction ([allocator.uses.construction]). -8- Complexity: Linear.
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()) { } 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 [flat.multiset.cons] as indicated:
flat_multiset(container_type cont, const key_compare& comp = key_compare());-1- Effects: Initializes c with std::move(cont) and compare with comp
, value-initializes compare, and sorts the range [begin(), end()) with respect to compare.-2- Complexity: Linear in N if cont is already sorted with respect to compare and otherwise N log N, where N is the value of cont.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: uses_allocator_v<container_type, Allocator> is true.
-4- Effects: Equivalent to flat_multiset(cont) and flat_multiset(cont, comp), respectively, except that c is constructed with uses-allocator construction ([allocator.uses.construction]). -5- Complexity: Same as flat_multiset(cont) and flat_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: uses_allocator_v<container_type, Allocator> is true.
-7- Effects: Equivalent to flat_multiset(s, cont) and flat_multiset(s, cont, comp), respectively, except that c is constructed with uses-allocator construction ([allocator.uses.construction]). -8- Complexity: Linear.
[ 2023-02-13 Approved at February 2023 meeting in Issaquah. Status changed: Immediate → WP. ]
[ Issaquah 2023-02-09; LWG ]
Move to Immediate for C++23
[ 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.)
[ 2022-11-04; Reflector poll ]
Set priority to 1 after reflector poll.
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.
Tony Table: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
History | |||
---|---|---|---|
Date | User | Action | Args |
2023-11-22 15:47:43 | admin | set | status: wp -> c++23 |
2023-02-13 11:31:32 | admin | set | messages: + msg13386 |
2023-02-13 11:31:32 | admin | set | status: immediate -> wp |
2023-02-10 01:38:08 | admin | set | messages: + msg13329 |
2023-02-10 01:38:08 | admin | set | status: new -> immediate |
2023-02-09 15:54:42 | admin | set | messages: + msg13310 |
2023-02-09 15:54:42 | admin | set | messages: + msg13309 |
2022-11-04 20:59:04 | admin | set | messages: + msg12922 |
2022-10-25 00:00:00 | admin | create |