23 Containers library [containers]

23.6 Container adaptors [container.adaptors]

23.6.12 Class template flat_multiset [flat.multiset]

23.6.12.1 Overview [flat.multiset.overview]

A flat_multiset is a container adaptor that provides an associative container interface that supports equivalent keys (i.e., possibly containing multiple copies of the same key value) and provides for fast retrieval of the keys themselves.
flat_multiset supports iterators that model the random_access_iterator concept ([iterator.concept.random.access]).
A flat_multiset meets all of the requirements for a container ([container.reqmts]) and for a reversible container ([container.rev.reqmts]), plus the optional container requirements ([container.opt.reqmts]).
flat_multiset meets the requirements of an associative container ([associative.reqmts]), except that:
  • it does not meet the requirements related to node handles ([container.node.overview]),
  • it does not meet the requirements related to iterator invalidation, and
  • the time complexity of the operations that insert or erase a single element from the set is linear, including the ones that take an insertion position iterator.
[Note 1: 
A flat_multiset does not meet the additional requirements of an allocator-aware container, as described in [container.alloc.reqmts].
— end note]
A flat_multiset also provides most operations described in [associative.reqmts] for equal keys.
This means that a flat_multiset supports the a_eq operations in [associative.reqmts] but not the a_uniq operations.
For a flat_multiset<Key>, both the key_type and value_type are Key.
Descriptions are provided here only for operations on flat_multiset that are not described in one of the general sections or for operations where there is additional semantic information.
A flat_multiset maintains the invariant that the keys are sorted with respect to the comparison object.
If any member function in [flat.multiset.defn] exits via an exception, the invariant is restored.
[Note 2: 
This can result in the flat_multiset's being emptied.
— end note]
Any sequence container ([sequence.reqmts]) supporting Cpp17RandomAccessIterator can be used to instantiate flat_multiset.
In particular, vector ([vector]) and deque ([deque]) can be used.
[Note 3: 
vector<bool> is not a sequence container.
— end note]
The program is ill-formed if Key is not the same type as KeyContainer​::​value_type.
The effect of calling a constructor or member function that takes a sorted_equivalent_t argument with a range that is not sorted with respect to key_comp() is undefined.
The types iterator and const_iterator meet the constexpr iterator requirements ([iterator.requirements.general]).

23.6.12.2 Definition [flat.multiset.defn]

namespace std { template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>> class flat_multiset { public: // types using key_type = Key; using value_type = Key; using key_compare = Compare; using value_compare = Compare; using reference = value_type&; using const_reference = const value_type&; using size_type = typename KeyContainer::size_type; using difference_type = typename KeyContainer::difference_type; using iterator = implementation-defined; // see [container.requirements] using const_iterator = implementation-defined; // see [container.requirements] using reverse_iterator = std::reverse_iterator<iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>; using container_type = KeyContainer; // [flat.multiset.cons], constructors constexpr flat_multiset() : flat_multiset(key_compare()) { } constexpr explicit flat_multiset(const key_compare& comp) : c(), compare(comp) { } constexpr explicit flat_multiset(container_type cont, const key_compare& comp = key_compare()); constexpr flat_multiset(sorted_equivalent_t, container_type cont, const key_compare& comp = key_compare()) : c(std::move(cont)), compare(comp) { } template<class InputIterator> constexpr flat_multiset(InputIterator first, InputIterator last, const key_compare& comp = key_compare()) : c(), compare(comp) { insert(first, last); } template<class InputIterator> constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, const key_compare& comp = key_compare()) : c(first, last), compare(comp) { } template<container-compatible-range<value_type> R> constexpr flat_multiset(from_range_t, R&& rg) : flat_multiset(from_range, std::forward<R>(rg), key_compare()) { } template<container-compatible-range<value_type> R> constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp) : flat_multiset(comp) { insert_range(std::forward<R>(rg)); } constexpr flat_multiset(initializer_list<value_type> il, const key_compare& comp = key_compare()) : flat_multiset(il.begin(), il.end(), comp) { } constexpr flat_multiset(sorted_equivalent_t s, initializer_list<value_type> il, const key_compare& comp = key_compare()) : flat_multiset(s, il.begin(), il.end(), comp) { } // [flat.multiset.cons.alloc], constructors with allocators template<class Alloc> constexpr explicit flat_multiset(const Alloc& a); template<class Alloc> constexpr flat_multiset(const key_compare& comp, const Alloc& a); template<class Alloc> constexpr flat_multiset(const container_type& cont, const Alloc& a); template<class Alloc> constexpr flat_multiset(const container_type& cont, const key_compare& comp, const Alloc& a); template<class Alloc> constexpr flat_multiset(sorted_equivalent_t, const container_type& cont, const Alloc& a); template<class Alloc> constexpr flat_multiset(sorted_equivalent_t, const container_type& cont, const key_compare& comp, const Alloc& a); template<class Alloc> constexpr flat_multiset(const flat_multiset&, const Alloc& a); template<class Alloc> constexpr flat_multiset(flat_multiset&&, const Alloc& a); template<class InputIterator, class Alloc> constexpr flat_multiset(InputIterator first, InputIterator last, const Alloc& a); template<class InputIterator, class Alloc> constexpr flat_multiset(InputIterator first, InputIterator last, const key_compare& comp, const Alloc& a); template<class InputIterator, class Alloc> constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, const Alloc& a); template<class InputIterator, class Alloc> constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, const key_compare& comp, const Alloc& a); template<container-compatible-range<value_type> R, class Alloc> constexpr flat_multiset(from_range_t, R&& rg, const Alloc& a); template<container-compatible-range<value_type> R, class Alloc> constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); template<class Alloc> constexpr flat_multiset(initializer_list<value_type> il, const Alloc& a); template<class Alloc> constexpr flat_multiset(initializer_list<value_type> il, const key_compare& comp, const Alloc& a); template<class Alloc> constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il, const Alloc& a); template<class Alloc> constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il, const key_compare& comp, const Alloc& a); constexpr flat_multiset& operator=(initializer_list<value_type>); // iterators constexpr iterator begin() noexcept; constexpr const_iterator begin() const noexcept; constexpr iterator end() noexcept; constexpr const_iterator end() const noexcept; constexpr reverse_iterator rbegin() noexcept; constexpr const_reverse_iterator rbegin() const noexcept; constexpr reverse_iterator rend() noexcept; constexpr const_reverse_iterator rend() const noexcept; constexpr const_iterator cbegin() const noexcept; constexpr const_iterator cend() const noexcept; constexpr const_reverse_iterator crbegin() const noexcept; constexpr const_reverse_iterator crend() const noexcept; // capacity constexpr bool empty() const noexcept; constexpr size_type size() const noexcept; constexpr size_type max_size() const noexcept; // [flat.multiset.modifiers], modifiers template<class... Args> constexpr iterator emplace(Args&&... args); template<class... Args> constexpr iterator emplace_hint(const_iterator position, Args&&... args); constexpr iterator insert(const value_type& x) { return emplace(x); } constexpr iterator insert(value_type&& x) { return emplace(std::move(x)); } constexpr iterator insert(const_iterator position, const value_type& x) { return emplace_hint(position, x); } constexpr iterator insert(const_iterator position, value_type&& x) { return emplace_hint(position, std::move(x)); } template<class InputIterator> constexpr void insert(InputIterator first, InputIterator last); template<class InputIterator> constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last); template<container-compatible-range<value_type> R> constexpr void insert_range(R&& rg); constexpr void insert(initializer_list<value_type> il) { insert(il.begin(), il.end()); } constexpr void insert(sorted_equivalent_t s, initializer_list<value_type> il) { insert(s, il.begin(), il.end()); } constexpr container_type extract() &&; constexpr void replace(container_type&&); constexpr iterator erase(iterator position); constexpr iterator erase(const_iterator position); constexpr size_type erase(const key_type& x); template<class K> constexpr size_type erase(K&& x); constexpr iterator erase(const_iterator first, const_iterator last); constexpr void swap(flat_multiset& y) noexcept; constexpr void clear() noexcept; // observers constexpr key_compare key_comp() const; constexpr value_compare value_comp() const; // set operations constexpr iterator find(const key_type& x); constexpr const_iterator find(const key_type& x) const; template<class K> constexpr iterator find(const K& x); template<class K> constexpr const_iterator find(const K& x) const; constexpr size_type count(const key_type& x) const; template<class K> constexpr size_type count(const K& x) const; constexpr bool contains(const key_type& x) const; template<class K> constexpr bool contains(const K& x) const; constexpr iterator lower_bound(const key_type& x); constexpr const_iterator lower_bound(const key_type& x) const; template<class K> constexpr iterator lower_bound(const K& x); template<class K> constexpr const_iterator lower_bound(const K& x) const; constexpr iterator upper_bound(const key_type& x); constexpr const_iterator upper_bound(const key_type& x) const; template<class K> constexpr iterator upper_bound(const K& x); template<class K> constexpr const_iterator upper_bound(const K& x) const; constexpr pair<iterator, iterator> equal_range(const key_type& x); constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const; template<class K> constexpr pair<iterator, iterator> equal_range(const K& x); template<class K> constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const; constexpr friend bool operator==(const flat_multiset& x, const flat_multiset& y); friend synth-three-way-result<value_type> constexpr operator<=>(const flat_multiset& x, const flat_multiset& y); constexpr friend void swap(flat_multiset& x, flat_multiset& y) noexcept { x.swap(y); } private: container_type c; // exposition only key_compare compare; // exposition only }; 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>; template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>> flat_multiset(InputIterator, InputIterator, Compare = Compare()) -> flat_multiset<iter-value-type<InputIterator>, Compare>; template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>> flat_multiset(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare()) -> flat_multiset<iter-value-type<InputIterator>, Compare>; template<ranges::input_range R, class Compare = less<ranges::range_value_t<R>>, class Allocator = allocator<ranges::range_value_t<R>>> flat_multiset(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) -> flat_multiset<ranges::range_value_t<R>, Compare, vector<ranges::range_value_t<R>, alloc-rebind<Allocator, ranges::range_value_t<R>>>>; template<ranges::input_range R, class Allocator> flat_multiset(from_range_t, R&&, Allocator) -> flat_multiset<ranges::range_value_t<R>, less<ranges::range_value_t<R>>, vector<ranges::range_value_t<R>, alloc-rebind<Allocator, ranges::range_value_t<R>>>>; template<class Key, class Compare = less<Key>> flat_multiset(initializer_list<Key>, Compare = Compare()) -> flat_multiset<Key, Compare>; template<class Key, class Compare = less<Key>> flat_multiset(sorted_equivalent_t, initializer_list<Key>, Compare = Compare()) -> flat_multiset<Key, Compare>; template<class Key, class Compare, class KeyContainer, class Allocator> struct uses_allocator<flat_multiset<Key, Compare, KeyContainer>, Allocator> : bool_constant<uses_allocator_v<KeyContainer, Allocator>> { }; }

23.6.12.3 Constructors [flat.multiset.cons]

constexpr explicit flat_multiset(container_type cont, const key_compare& comp = key_compare());
Effects: Initializes c with std​::​move(cont) and compare with comp, and sorts the range [begin(), end()) with respect to compare.
Complexity: Linear in N if cont is already sorted with respect to compare and otherwise , where N is the value of cont.size() before this call.

23.6.12.4 Constructors with allocators [flat.multiset.cons.alloc]

The constructors in this subclause shall not participate in overload resolution unless uses_allocator_v<container_type, Alloc> is true.
template<class Alloc> constexpr flat_multiset(const container_type& cont, const Alloc& a); template<class Alloc> constexpr flat_multiset(const container_type& cont, const key_compare& comp, const Alloc& a);
Effects: Equivalent to flat_multiset(cont) and flat_multiset(cont, comp), respectively, except that c is constructed with uses-allocator construction ([allocator.uses.construction]).
Complexity: Same as flat_multiset(cont) and flat_multiset(cont, comp), respectively.
template<class Alloc> constexpr flat_multiset(sorted_equivalent_t s, const container_type& cont, const Alloc& a); template<class Alloc> constexpr flat_multiset(sorted_equivalent_t s, const container_type& cont, const key_compare& comp, const Alloc& a);
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]).
Complexity: Linear.
template<class Alloc> constexpr explicit flat_multiset(const Alloc& a); template<class Alloc> constexpr flat_multiset(const key_compare& comp, const Alloc& a); template<class Alloc> constexpr flat_multiset(const flat_multiset&, const Alloc& a); template<class Alloc> constexpr flat_multiset(flat_multiset&&, const Alloc& a); template<class InputIterator, class Alloc> constexpr flat_multiset(InputIterator first, InputIterator last, const Alloc& a); template<class InputIterator, class Alloc> constexpr flat_multiset(InputIterator first, InputIterator last, const key_compare& comp, const Alloc& a); template<class InputIterator, class Alloc> constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, const Alloc& a); template<class InputIterator, class Alloc> constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, const key_compare& comp, const Alloc& a); template<container-compatible-range<value_type> R, class Alloc> constexpr flat_multiset(from_range_t, R&& rg, const Alloc& a); template<container-compatible-range<value_type> R, class Alloc> constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); template<class Alloc> constexpr flat_multiset(initializer_list<value_type> il, const Alloc& a); template<class Alloc> constexpr flat_multiset(initializer_list<value_type> il, const key_compare& comp, const Alloc& a); template<class Alloc> constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il, const Alloc& a); template<class Alloc> constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il, const key_compare& comp, const Alloc& a);
Effects: Equivalent to the corresponding non-allocator constructors except that c is constructed with uses-allocator construction ([allocator.uses.construction]).

23.6.12.5 Modifiers [flat.multiset.modifiers]

template<class... Args> constexpr iterator emplace(Args&&... args);
Constraints: is_constructible_v<value_type, Args...> is true.
Effects: First, initializes an object t of type value_type with std​::​forward<Args>(args)..., then inserts t as if by: auto it = ranges::upper_bound(c, t, compare); c.insert(it, std::move(t));
Returns: An iterator that points to the inserted element.
template<class InputIterator> constexpr void insert(InputIterator first, InputIterator last);
Effects: Adds elements to c as if by: c.insert(c.end(), first, last);
Then, sorts the range of newly inserted elements with respect to compare, and merges the resulting sorted range and the sorted range of pre-existing elements into a single sorted range.
Complexity: N + , where N is size() before the operation and M is distance(first, last).
Remarks: Since this operation performs an in-place merge, it may allocate memory.
template<class InputIterator> constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last);
Effects: Equivalent to insert(first, last).
Complexity: Linear.
constexpr void swap(flat_multiset& y) noexcept;
Effects: Equivalent to: ranges::swap(compare, y.compare); ranges::swap(c, y.c);
constexpr container_type extract() &&;
Postconditions: *this is emptied, even if the function exits via an exception.
Returns: std​::​move(c).
constexpr void replace(container_type&& cont);
Preconditions: The elements of cont are sorted with respect to compare.
Effects: Equivalent to: c = std​::​move(cont);

23.6.12.6 Erasure [flat.multiset.erasure]

template<class Key, class Compare, class KeyContainer, class Predicate> constexpr typename flat_multiset<Key, Compare, KeyContainer>::size_type erase_if(flat_multiset<Key, Compare, KeyContainer>& c, Predicate pred);
Preconditions: Key meets the Cpp17MoveAssignable requirements.
Effects: Let E be bool(pred(as_const(e))).
Erases all elements e in c for which E holds.
Returns: The number of elements erased.
Complexity: Exactly c.size() applications of the predicate.
Remarks: Stable ([algorithm.stable]).
If an invocation of erase_if exits via an exception, c is in a valid but unspecified state ([defns.valid]).
[Note 1: 
c still meets its invariants, but can be empty.
— end note]