23 Containers library [containers]

23.4 Associative containers [associative]

23.4.1 General [associative.general]

The header <map> defines the class templates map and multimap; the header <set> defines the class templates set and multiset.
The following exposition-only alias templates may appear in deduction guides for associative containers: template<class InputIterator> using iter-value-type = typename iterator_traits<InputIterator>::value_type; // exposition only template<class InputIterator> using iter-key-type = remove_const_t< tuple_element_t<0, iter-value-type<InputIterator>>>; // exposition only template<class InputIterator> using iter-mapped-type = tuple_element_t<1, iter-value-type<InputIterator>>; // exposition only template<class InputIterator> using iter-to-alloc-type = pair< add_const_t<tuple_element_t<0, iter-value-type<InputIterator>>>, tuple_element_t<1, iter-value-type<InputIterator>>>; // exposition only template<ranges::input_range Range> using range-key-type = remove_const_t<typename ranges::range_value_t<Range>::first_type>; // exposition only template<ranges::input_range Range> using range-mapped-type = typename ranges::range_value_t<Range>::second_type; // exposition only template<ranges::input_range Range> using range-to-alloc-type = pair<add_const_t<typename ranges::range_value_t<Range>::first_type>, typename ranges::range_value_t<Range>::second_type>; // exposition only

23.4.2 Header <map> synopsis [associative.map.syn]

#include <compare> // see [compare.syn] #include <initializer_list> // see [initializer.list.syn] namespace std { // [map], class template map template<class Key, class T, class Compare = less<Key>, class Allocator = allocator<pair<const Key, T>>> class map; template<class Key, class T, class Compare, class Allocator> bool operator==(const map<Key, T, Compare, Allocator>& x, const map<Key, T, Compare, Allocator>& y); template<class Key, class T, class Compare, class Allocator> synth-three-way-result<pair<const Key, T>> operator<=>(const map<Key, T, Compare, Allocator>& x, const map<Key, T, Compare, Allocator>& y); template<class Key, class T, class Compare, class Allocator> void swap(map<Key, T, Compare, Allocator>& x, map<Key, T, Compare, Allocator>& y) noexcept(noexcept(x.swap(y))); // [map.erasure], erasure for map template<class Key, class T, class Compare, class Allocator, class Predicate> typename map<Key, T, Compare, Allocator>::size_type erase_if(map<Key, T, Compare, Allocator>& c, Predicate pred); // [multimap], class template multimap template<class Key, class T, class Compare = less<Key>, class Allocator = allocator<pair<const Key, T>>> class multimap; template<class Key, class T, class Compare, class Allocator> bool operator==(const multimap<Key, T, Compare, Allocator>& x, const multimap<Key, T, Compare, Allocator>& y); template<class Key, class T, class Compare, class Allocator> synth-three-way-result<pair<const Key, T>> operator<=>(const multimap<Key, T, Compare, Allocator>& x, const multimap<Key, T, Compare, Allocator>& y); template<class Key, class T, class Compare, class Allocator> void swap(multimap<Key, T, Compare, Allocator>& x, multimap<Key, T, Compare, Allocator>& y) noexcept(noexcept(x.swap(y))); // [multimap.erasure], erasure for multimap template<class Key, class T, class Compare, class Allocator, class Predicate> typename multimap<Key, T, Compare, Allocator>::size_type erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred); namespace pmr { template<class Key, class T, class Compare = less<Key>> using map = std::map<Key, T, Compare, polymorphic_allocator<pair<const Key, T>>>; template<class Key, class T, class Compare = less<Key>> using multimap = std::multimap<Key, T, Compare, polymorphic_allocator<pair<const Key, T>>>; } }

23.4.3 Class template map [map]

23.4.3.1 Overview [map.overview]

A map is an associative container that supports unique keys (i.e., contains at most one of each key value) and provides for fast retrieval of values of another type T based on the keys.
The map class supports bidirectional iterators.
A map meets all of the requirements of a container ([container.reqmts]), of a reversible container ([container.rev.reqmts]), of an allocator-aware container ([container.alloc.reqmts]).
and of an associative container ([associative.reqmts]).
A map also provides most operations described in [associative.reqmts] for unique keys.
This means that a map supports the a_uniq operations in [associative.reqmts] but not the a_eq operations.
For a map<Key,T> the key_type is Key and the value_type is pair<const Key,T>.
Descriptions are provided here only for operations on map that are not described in one of those tables or for operations where there is additional semantic information.
namespace std { template<class Key, class T, class Compare = less<Key>, class Allocator = allocator<pair<const Key, T>>> class map { public: // types using key_type = Key; using mapped_type = T; using value_type = pair<const Key, T>; using key_compare = Compare; using allocator_type = Allocator; using pointer = typename allocator_traits<Allocator>::pointer; using const_pointer = typename allocator_traits<Allocator>::const_pointer; using reference = value_type&; using const_reference = const value_type&; using size_type = implementation-defined; // see [container.requirements] using difference_type = implementation-defined; // see [container.requirements] 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 node_type = unspecified; using insert_return_type = insert-return-type<iterator, node_type>; class value_compare { protected: Compare comp; value_compare(Compare c) : comp(c) {} public: bool operator()(const value_type& x, const value_type& y) const { return comp(x.first, y.first); } }; // [map.cons], construct/copy/destroy map() : map(Compare()) { } explicit map(const Compare& comp, const Allocator& = Allocator()); template<class InputIterator> map(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator()); template<container-compatible-range<value_type> R> map(from_range_t, R&& rg, const Compare& comp = Compare(), const Allocator& = Allocator()); map(const map& x); map(map&& x); explicit map(const Allocator&); map(const map&, const type_identity_t<Allocator>&); map(map&&, const type_identity_t<Allocator>&); map(initializer_list<value_type>, const Compare& = Compare(), const Allocator& = Allocator()); template<class InputIterator> map(InputIterator first, InputIterator last, const Allocator& a) : map(first, last, Compare(), a) { } template<container-compatible-range<value_type> R> map(from_range_t, R&& rg, const Allocator& a)) : map(from_range, std::forward<R>(rg), Compare(), a) { } map(initializer_list<value_type> il, const Allocator& a) : map(il, Compare(), a) { } ~map(); map& operator=(const map& x); map& operator=(map&& x) noexcept(allocator_traits<Allocator>::is_always_equal::value && is_nothrow_move_assignable_v<Compare>); map& operator=(initializer_list<value_type>); allocator_type get_allocator() const noexcept; // iterators iterator begin() noexcept; const_iterator begin() const noexcept; iterator end() noexcept; const_iterator end() const noexcept; reverse_iterator rbegin() noexcept; const_reverse_iterator rbegin() const noexcept; reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; const_iterator cbegin() const noexcept; const_iterator cend() const noexcept; const_reverse_iterator crbegin() const noexcept; const_reverse_iterator crend() const noexcept; // capacity bool empty() const noexcept; size_type size() const noexcept; size_type max_size() const noexcept; // [map.access], element access mapped_type& operator[](const key_type& x); mapped_type& operator[](key_type&& x); template<class K> mapped_type& operator[](K&& x); mapped_type& at(const key_type& x); const mapped_type& at(const key_type& x) const; template<class K> mapped_type& at(const K& x); template<class K> const mapped_type& at(const K& x) const; // [map.modifiers], modifiers template<class... Args> pair<iterator, bool> emplace(Args&&... args); template<class... Args> iterator emplace_hint(const_iterator position, Args&&... args); pair<iterator, bool> insert(const value_type& x); pair<iterator, bool> insert(value_type&& x); template<class P> pair<iterator, bool> insert(P&& x); iterator insert(const_iterator position, const value_type& x); iterator insert(const_iterator position, value_type&& x); template<class P> iterator insert(const_iterator position, P&&); template<class InputIterator> void insert(InputIterator first, InputIterator last); template<container-compatible-range<value_type> R> void insert_range(R&& rg); void insert(initializer_list<value_type>); node_type extract(const_iterator position); node_type extract(const key_type& x); template<class K> node_type extract(K&& x); insert_return_type insert(node_type&& nh); iterator insert(const_iterator hint, node_type&& nh); template<class... Args> pair<iterator, bool> try_emplace(const key_type& k, Args&&... args); template<class... Args> pair<iterator, bool> try_emplace(key_type&& k, Args&&... args); template<class K, class... Args> pair<iterator, bool> try_emplace(K&& k, Args&&... args); template<class... Args> iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); template<class... Args> iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); template<class K, class... Args> iterator try_emplace(const_iterator hint, K&& k, Args&&... args); template<class M> pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj); template<class M> pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj); template<class K, class M> pair<iterator, bool> insert_or_assign(K&& k, M&& obj); template<class M> iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); template<class M> iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); template<class K, class M> iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); iterator erase(iterator position); iterator erase(const_iterator position); size_type erase(const key_type& x); template<class K> size_type erase(K&& x); iterator erase(const_iterator first, const_iterator last); void swap(map&) noexcept(allocator_traits<Allocator>::is_always_equal::value && is_nothrow_swappable_v<Compare>); void clear() noexcept; template<class C2> void merge(map<Key, T, C2, Allocator>& source); template<class C2> void merge(map<Key, T, C2, Allocator>&& source); template<class C2> void merge(multimap<Key, T, C2, Allocator>& source); template<class C2> void merge(multimap<Key, T, C2, Allocator>&& source); // observers key_compare key_comp() const; value_compare value_comp() const; // map operations iterator find(const key_type& x); const_iterator find(const key_type& x) const; template<class K> iterator find(const K& x); template<class K> const_iterator find(const K& x) const; size_type count(const key_type& x) const; template<class K> size_type count(const K& x) const; bool contains(const key_type& x) const; template<class K> bool contains(const K& x) const; iterator lower_bound(const key_type& x); const_iterator lower_bound(const key_type& x) const; template<class K> iterator lower_bound(const K& x); template<class K> const_iterator lower_bound(const K& x) const; iterator upper_bound(const key_type& x); const_iterator upper_bound(const key_type& x) const; template<class K> iterator upper_bound(const K& x); template<class K> const_iterator upper_bound(const K& x) const; pair<iterator, iterator> equal_range(const key_type& x); pair<const_iterator, const_iterator> equal_range(const key_type& x) const; template<class K> pair<iterator, iterator> equal_range(const K& x); template<class K> pair<const_iterator, const_iterator> equal_range(const K& x) const; }; template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>, class Allocator = allocator<iter-to-alloc-type<InputIterator>>> map(InputIterator, InputIterator, Compare = Compare(), Allocator = Allocator()) -> map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Compare, Allocator>; template<ranges::input_range R, class Compare = less<range-key-type<R>, class Allocator = allocator<range-to-alloc-type<R>>> map(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) -> map<range-key-type<R>, range-mapped-type<R>, Compare, Allocator>; template<class Key, class T, class Compare = less<Key>, class Allocator = allocator<pair<const Key, T>>> map(initializer_list<pair<Key, T>>, Compare = Compare(), Allocator = Allocator()) -> map<Key, T, Compare, Allocator>; template<class InputIterator, class Allocator> map(InputIterator, InputIterator, Allocator) -> map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, less<iter-key-type<InputIterator>>, Allocator>; template<ranges::input_range R, class Allocator> map(from_range_t, R&&, Allocator) -> map<range-key-type<R>, range-mapped-type<R>, less<range-key-type<R>>, Allocator>; template<class Key, class T, class Allocator> map(initializer_list<pair<Key, T>>, Allocator) -> map<Key, T, less<Key>, Allocator>; }

23.4.3.2 Constructors, copy, and assignment [map.cons]

explicit map(const Compare& comp, const Allocator& = Allocator());
Effects: Constructs an empty map using the specified comparison object and allocator.
Complexity: Constant.
template<class InputIterator> map(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator());
Effects: Constructs an empty map using the specified comparison object and allocator, and inserts elements from the range [first, last).
Complexity: Linear in N if the range [first, last) is already sorted with respect to comp and otherwise , where N is last - first.
template<container-compatible-range<value_type> R> map(from_range_t, R&& rg, const Compare& comp = Compare(), const Allocator& = Allocator());
Effects: Constructs an empty map using the specified comparison object and allocator, and inserts elements from the range rg.
Complexity: Linear in N if rg is already sorted with respect to comp and otherwise , where N is ranges​::​distance(rg).

23.4.3.3 Element access [map.access]

mapped_type& operator[](const key_type& x);
Effects: Equivalent to: return try_emplace(x).first->second;
mapped_type& operator[](key_type&& x);
Effects: Equivalent to: return try_emplace(std​::​move(x)).first->second;
template<class K> mapped_type& operator[](K&& x);
Constraints: The qualified-id Compare​::​is_transparent is valid and denotes a type.
Effects: Equivalent to: return try_emplace(std​::​forward<K>(x)).first->second;
mapped_type& at(const key_type& x); const mapped_type& at(const key_type& x) const;
Returns: A reference to the mapped_type corresponding to x in *this.
Throws: An exception object of type out_of_range if no such element is present.
Complexity: Logarithmic.
template<class K> mapped_type& at(const K& x); template<class K> const mapped_type& at(const K& x) const;
Constraints: The qualified-id Compare​::​is_transparent is valid and denotes a type.
Preconditions: The expression find(x) is well-formed and has well-defined behavior.
Returns: A reference to find(x)->second.
Throws: An exception object of type out_of_range if find(x) == end() is true.
Complexity: Logarithmic.

23.4.3.4 Modifiers [map.modifiers]

template<class P> pair<iterator, bool> insert(P&& x); template<class P> iterator insert(const_iterator position, P&& x);
Constraints: is_constructible_v<value_type, P&&> is true.
Effects: The first form is equivalent to return emplace(std​::​forward<P>(x)).
The second form is equivalent to return emplace_hint(position, std​::​forward<P>(x)).
template<class... Args> pair<iterator, bool> try_emplace(const key_type& k, Args&&... args); template<class... Args> iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);
Preconditions: value_type is Cpp17EmplaceConstructible into map from piecewise_construct, forward_as_tuple(k), forward_as_tuple(std​::​forward<Args>(args)...).
Effects: If the map already contains an element whose key is equivalent to k, there is no effect.
Otherwise inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(k), forward_as_tuple(std​::​forward<Args>(args)...).
Returns: In the first overload, the bool component of the returned pair is true if and only if the insertion took place.
The returned iterator points to the map element whose key is equivalent to k.
Complexity: The same as emplace and emplace_hint, respectively.
template<class... Args> pair<iterator, bool> try_emplace(key_type&& k, Args&&... args); template<class... Args> iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);
Preconditions: value_type is Cpp17EmplaceConstructible into map from piecewise_construct, forward_as_tuple(std​::​move(k)), forward_as_tuple(std​::​forward<Args>(args)...).
Effects: If the map already contains an element whose key is equivalent to k, there is no effect.
Otherwise inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(std​::​move(k)), forward_as_tuple(std​::​forward<Args>(args)...).
Returns: In the first overload, the bool component of the returned pair is true if and only if the insertion took place.
The returned iterator points to the map element whose key is equivalent to k.
Complexity: The same as emplace and emplace_hint, respectively.
template<class K, class... Args> pair<iterator, bool> try_emplace(K&& k, Args&&... args); template<class K, class... Args> iterator try_emplace(const_iterator hint, K&& k, Args&&... args);
Constraints: The qualified-id Compare​::​is_transparent is valid and denotes a type.
For the first overload, is_convertible_v<K&&, const_iterator> and is_convertible_v<K&&, iterator> are both false.
Preconditions: value_type is Cpp17EmplaceConstructible into map from piecewise_construct, forward_as_tuple(std​::​forward<K>(k)), forward_as_tuple(std​::​forward<Args>(args)...).
Effects: If the map already contains an element whose key is equivalent to k, there is no effect.
Otherwise, let r be equal_range(k).
Constructs an object u of type value_type with piecewise_construct, forward_as_tuple(std​::​forward<K>(k)), forward_as_tuple(std​::​forward<Args>(args)...).
If equal_range(u.first) == r is false, the behavior is undefined.
Inserts u into *this.
Returns: For the first overload, the bool component of the returned pair is true if and only if the insertion took place.
The returned iterator points to the map element whose key is equivalent to k.
Complexity: The same as emplace and emplace_hint, respectively.
template<class M> pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj); template<class M> iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);
Mandates: is_assignable_v<mapped_type&, M&&> is true.
Preconditions: value_type is Cpp17EmplaceConstructible into map from k, std​::​forward<M>(obj).
Effects: If the map already contains an element e whose key is equivalent to k, assigns std​::​forward<M>(obj) to e.second.
Otherwise inserts an object of type value_type constructed with k, std​::​forward<M>(obj).
Returns: In the first overload, the bool component of the returned pair is true if and only if the insertion took place.
The returned iterator points to the map element whose key is equivalent to k.
Complexity: The same as emplace and emplace_hint, respectively.
template<class M> pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj); template<class M> iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);
Mandates: is_assignable_v<mapped_type&, M&&> is true.
Preconditions: value_type is Cpp17EmplaceConstructible into map from std​::​move(k), std​::​forward<M>(obj).
Effects: If the map already contains an element e whose key is equivalent to k, assigns std​::​forward<M>(obj) to e.second.
Otherwise inserts an object of type value_type constructed with std​::​​move(k), std​::​forward<M>(obj).
Returns: In the first overload, the bool component of the returned pair is true if and only if the insertion took place.
The returned iterator points to the map element whose key is equivalent to k.
Complexity: The same as emplace and emplace_hint, respectively.
template<class K, class M> pair<iterator, bool> insert_or_assign(K&& k, M&& obj); template<class K, class M> iterator insert_or_assign(const_iterator hint, K&& k, M&& obj);
Constraints: The qualified-id Compare​::​is_transparent is valid and denotes a type.
Mandates: is_assignable_v<mapped_type&, M&&> is true.
Preconditions: value_type is Cpp17EmplaceConstructible into map from std​::​forward<K>(k), std​::​
forward<M>(obj)
.
Effects: If the map already contains an element e whose key is equivalent to k, assigns std​::​forward<M>
(obj)
to e.second.
Otherwise, let r be equal_range(k).
Constructs an object u of type value_type with std​::​forward<K>(k), std​::​forward<M>(obj).
If equal_range(u.first) == r is false, the behavior is undefined.
Inserts u into *this.
Returns: For the first overload, the bool component of the returned pair is true if and only if the insertion took place.
The returned iterator points to the map element whose key is equivalent to k.
Complexity: The same as emplace and emplace_hint, respectively.

23.4.3.5 Erasure [map.erasure]

template<class Key, class T, class Compare, class Allocator, class Predicate> typename map<Key, T, Compare, Allocator>::size_type erase_if(map<Key, T, Compare, Allocator>& c, Predicate pred);
Effects: Equivalent to: auto original_size = c.size(); for (auto i = c.begin(), last = c.end(); i != last; ) { if (pred(*i)) { i = c.erase(i); } else { ++i; } } return original_size - c.size();

23.4.4 Class template multimap [multimap]

23.4.4.1 Overview [multimap.overview]

A multimap is an associative container that supports equivalent keys (i.e., possibly containing multiple copies of the same key value) and provides for fast retrieval of values of another type T based on the keys.
The multimap class supports bidirectional iterators.
A multimap meets all of the requirements of a container ([container.reqmts]), of a reversible container ([container.rev.reqmts]), of an allocator-aware container ([container.alloc.reqmts]), and of an associative container ([associative.reqmts]).
A multimap also provides most operations described in [associative.reqmts] for equal keys.
This means that a multimap supports the a_eq operations in [associative.reqmts] but not the a_uniq operations.
For a multimap<Key,T> the key_type is Key and the value_type is pair<const Key,T>.
Descriptions are provided here only for operations on multimap that are not described in one of those tables or for operations where there is additional semantic information.
namespace std { template<class Key, class T, class Compare = less<Key>, class Allocator = allocator<pair<const Key, T>>> class multimap { public: // types using key_type = Key; using mapped_type = T; using value_type = pair<const Key, T>; using key_compare = Compare; using allocator_type = Allocator; using pointer = typename allocator_traits<Allocator>::pointer; using const_pointer = typename allocator_traits<Allocator>::const_pointer; using reference = value_type&; using const_reference = const value_type&; using size_type = implementation-defined; // see [container.requirements] using difference_type = implementation-defined; // see [container.requirements] 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 node_type = unspecified; class value_compare { protected: Compare comp; value_compare(Compare c) : comp(c) { } public: bool operator()(const value_type& x, const value_type& y) const { return comp(x.first, y.first); } }; // [multimap.cons], construct/copy/destroy multimap() : multimap(Compare()) { } explicit multimap(const Compare& comp, const Allocator& = Allocator()); template<class InputIterator> multimap(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator()); template<container-compatible-range<value_type> R> multimap(from_range_t, R&& rg, const Compare& comp = Compare(), const Allocator& = Allocator()); multimap(const multimap& x); multimap(multimap&& x); explicit multimap(const Allocator&); multimap(const multimap&, const type_identity_t<Allocator>&); multimap(multimap&&, const type_identity_t<Allocator>&); multimap(initializer_list<value_type>, const Compare& = Compare(), const Allocator& = Allocator()); template<class InputIterator> multimap(InputIterator first, InputIterator last, const Allocator& a) : multimap(first, last, Compare(), a) { } template<container-compatible-range<value_type> R> multimap(from_range_t, R&& rg, const Allocator& a)) : multimap(from_range, std::forward<R>(rg), Compare(), a) { } multimap(initializer_list<value_type> il, const Allocator& a) : multimap(il, Compare(), a) { } ~multimap(); multimap& operator=(const multimap& x); multimap& operator=(multimap&& x) noexcept(allocator_traits<Allocator>::is_always_equal::value && is_nothrow_move_assignable_v<Compare>); multimap& operator=(initializer_list<value_type>); allocator_type get_allocator() const noexcept; // iterators iterator begin() noexcept; const_iterator begin() const noexcept; iterator end() noexcept; const_iterator end() const noexcept; reverse_iterator rbegin() noexcept; const_reverse_iterator rbegin() const noexcept; reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; const_iterator cbegin() const noexcept; const_iterator cend() const noexcept; const_reverse_iterator crbegin() const noexcept; const_reverse_iterator crend() const noexcept; // capacity bool empty() const noexcept; size_type size() const noexcept; size_type max_size() const noexcept; // [multimap.modifiers], modifiers template<class... Args> iterator emplace(Args&&... args); template<class... Args> iterator emplace_hint(const_iterator position, Args&&... args); iterator insert(const value_type& x); iterator insert(value_type&& x); template<class P> iterator insert(P&& x); iterator insert(const_iterator position, const value_type& x); iterator insert(const_iterator position, value_type&& x); template<class P> iterator insert(const_iterator position, P&& x); template<class InputIterator> void insert(InputIterator first, InputIterator last); template<container-compatible-range<value_type> R> void insert_range(R&& rg); void insert(initializer_list<value_type>); node_type extract(const_iterator position); node_type extract(const key_type& x); template<class K> node_type extract(K&& x); iterator insert(node_type&& nh); iterator insert(const_iterator hint, node_type&& nh); iterator erase(iterator position); iterator erase(const_iterator position); size_type erase(const key_type& x); template<class K> size_type erase(K&& x); iterator erase(const_iterator first, const_iterator last); void swap(multimap&) noexcept(allocator_traits<Allocator>::is_always_equal::value && is_nothrow_swappable_v<Compare>); void clear() noexcept; template<class C2> void merge(multimap<Key, T, C2, Allocator>& source); template<class C2> void merge(multimap<Key, T, C2, Allocator>&& source); template<class C2> void merge(map<Key, T, C2, Allocator>& source); template<class C2> void merge(map<Key, T, C2, Allocator>&& source); // observers key_compare key_comp() const; value_compare value_comp() const; // map operations iterator find(const key_type& x); const_iterator find(const key_type& x) const; template<class K> iterator find(const K& x); template<class K> const_iterator find(const K& x) const; size_type count(const key_type& x) const; template<class K> size_type count(const K& x) const; bool contains(const key_type& x) const; template<class K> bool contains(const K& x) const; iterator lower_bound(const key_type& x); const_iterator lower_bound(const key_type& x) const; template<class K> iterator lower_bound(const K& x); template<class K> const_iterator lower_bound(const K& x) const; iterator upper_bound(const key_type& x); const_iterator upper_bound(const key_type& x) const; template<class K> iterator upper_bound(const K& x); template<class K> const_iterator upper_bound(const K& x) const; pair<iterator, iterator> equal_range(const key_type& x); pair<const_iterator, const_iterator> equal_range(const key_type& x) const; template<class K> pair<iterator, iterator> equal_range(const K& x); template<class K> pair<const_iterator, const_iterator> equal_range(const K& x) const; }; template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>, class Allocator = allocator<iter-to-alloc-type<InputIterator>>> multimap(InputIterator, InputIterator, Compare = Compare(), Allocator = Allocator()) -> multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Compare, Allocator>; template<ranges::input_range R, class Compare = less<range-key-type<R>>, class Allocator = allocator<range-to-alloc-type<R>>> multimap(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) -> multimap<range-key-type<R>, range-mapped-type<R>, Compare, Allocator>; template<class Key, class T, class Compare = less<Key>, class Allocator = allocator<pair<const Key, T>>> multimap(initializer_list<pair<Key, T>>, Compare = Compare(), Allocator = Allocator()) -> multimap<Key, T, Compare, Allocator>; template<class InputIterator, class Allocator> multimap(InputIterator, InputIterator, Allocator) -> multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, less<iter-key-type<InputIterator>>, Allocator>; template<ranges::input_range R, class Allocator> multimap(from_range_t, R&&, Allocator) -> multimap<range-key-type<R>, range-mapped-type<R>, less<range-key-type<R>>, Allocator>; template<class Key, class T, class Allocator> multimap(initializer_list<pair<Key, T>>, Allocator) -> multimap<Key, T, less<Key>, Allocator>; }

23.4.4.2 Constructors [multimap.cons]

explicit multimap(const Compare& comp, const Allocator& = Allocator());
Effects: Constructs an empty multimap using the specified comparison object and allocator.
Complexity: Constant.
template<class InputIterator> multimap(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator());
Effects: Constructs an empty multimap using the specified comparison object and allocator, and inserts elements from the range [first, last).
Complexity: Linear in N if the range [first, last) is already sorted with respect to comp and otherwise , where N is last - first.
template<container-compatible-range<value_type> R> multimap(from_range_t, R&& rg, const Compare& comp = Compare(), const Allocator& = Allocator());
Effects: Constructs an empty multimap using the specified comparison object and allocator, and inserts elements from the range rg.
Complexity: Linear in N if rg is already sorted with respect to comp and otherwise , where N is ranges​::​distance(rg).

23.4.4.3 Modifiers [multimap.modifiers]

template<class P> iterator insert(P&& x); template<class P> iterator insert(const_iterator position, P&& x);
Constraints: is_constructible_v<value_type, P&&> is true.
Effects: The first form is equivalent to return emplace(std​::​forward<P>(x)).
The second form is equivalent to return emplace_hint(position, std​::​forward<P>(x)).

23.4.4.4 Erasure [multimap.erasure]

template<class Key, class T, class Compare, class Allocator, class Predicate> typename multimap<Key, T, Compare, Allocator>::size_type erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred);
Effects: Equivalent to: auto original_size = c.size(); for (auto i = c.begin(), last = c.end(); i != last; ) { if (pred(*i)) { i = c.erase(i); } else { ++i; } } return original_size - c.size();

23.4.5 Header <set> synopsis [associative.set.syn]

#include <compare> // see [compare.syn] #include <initializer_list> // see [initializer.list.syn] namespace std { // [set], class template set template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>> class set; template<class Key, class Compare, class Allocator> bool operator==(const set<Key, Compare, Allocator>& x, const set<Key, Compare, Allocator>& y); template<class Key, class Compare, class Allocator> synth-three-way-result<Key> operator<=>(const set<Key, Compare, Allocator>& x, const set<Key, Compare, Allocator>& y); template<class Key, class Compare, class Allocator> void swap(set<Key, Compare, Allocator>& x, set<Key, Compare, Allocator>& y) noexcept(noexcept(x.swap(y))); // [set.erasure], erasure for set template<class Key, class Compare, class Allocator, class Predicate> typename set<Key, Compare, Allocator>::size_type erase_if(set<Key, Compare, Allocator>& c, Predicate pred); // [multiset], class template multiset template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>> class multiset; template<class Key, class Compare, class Allocator> bool operator==(const multiset<Key, Compare, Allocator>& x, const multiset<Key, Compare, Allocator>& y); template<class Key, class Compare, class Allocator> synth-three-way-result<Key> operator<=>(const multiset<Key, Compare, Allocator>& x, const multiset<Key, Compare, Allocator>& y); template<class Key, class Compare, class Allocator> void swap(multiset<Key, Compare, Allocator>& x, multiset<Key, Compare, Allocator>& y) noexcept(noexcept(x.swap(y))); // [multiset.erasure], erasure for multiset template<class Key, class Compare, class Allocator, class Predicate> typename multiset<Key, Compare, Allocator>::size_type erase_if(multiset<Key, Compare, Allocator>& c, Predicate pred); namespace pmr { template<class Key, class Compare = less<Key>> using set = std::set<Key, Compare, polymorphic_allocator<Key>>; template<class Key, class Compare = less<Key>> using multiset = std::multiset<Key, Compare, polymorphic_allocator<Key>>; } }

23.4.6 Class template set [set]

23.4.6.1 Overview [set.overview]

A set is an associative container that supports unique keys (i.e., contains at most one of each key value) and provides for fast retrieval of the keys themselves.
The set class supports bidirectional iterators.
A set meets all of the requirements of a container ([container.reqmts]), of a reversible container ([container.rev.reqmts]), of an allocator-aware container ([container.alloc.reqmts]).
and of an associative container ([associative.reqmts]).
A set also provides most operations described in [associative.reqmts] for unique keys.
This means that a set supports the a_uniq operations in [associative.reqmts] but not the a_eq operations.
For a set<Key> both the key_type and value_type are Key.
Descriptions are provided here only for operations on set that are not described in one of these tables and for operations where there is additional semantic information.
namespace std { template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>> class set { public: // types using key_type = Key; using key_compare = Compare; using value_type = Key; using value_compare = Compare; using allocator_type = Allocator; using pointer = typename allocator_traits<Allocator>::pointer; using const_pointer = typename allocator_traits<Allocator>::const_pointer; using reference = value_type&; using const_reference = const value_type&; using size_type = implementation-defined; // see [container.requirements] using difference_type = implementation-defined; // see [container.requirements] 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 node_type = unspecified; using insert_return_type = insert-return-type<iterator, node_type>; // [set.cons], construct/copy/destroy set() : set(Compare()) { } explicit set(const Compare& comp, const Allocator& = Allocator()); template<class InputIterator> set(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator()); template<container-compatible-range<value_type> R> set(from_range_t, R&& rg, const Compare& comp = Compare(), const Allocator& = Allocator()); set(const set& x); set(set&& x); explicit set(const Allocator&); set(const set&, const type_identity_t<Allocator>&); set(set&&, const type_identity_t<Allocator>&); set(initializer_list<value_type>, const Compare& = Compare(), const Allocator& = Allocator()); template<class InputIterator> set(InputIterator first, InputIterator last, const Allocator& a) : set(first, last, Compare(), a) { } template<container-compatible-range<value_type> R> set(from_range_t, R&& rg, const Allocator& a)) : set(from_range, std::forward<R>(rg), Compare(), a) { } set(initializer_list<value_type> il, const Allocator& a) : set(il, Compare(), a) { } ~set(); set& operator=(const set& x); set& operator=(set&& x) noexcept(allocator_traits<Allocator>::is_always_equal::value && is_nothrow_move_assignable_v<Compare>); set& operator=(initializer_list<value_type>); allocator_type get_allocator() const noexcept; // iterators iterator begin() noexcept; const_iterator begin() const noexcept; iterator end() noexcept; const_iterator end() const noexcept; reverse_iterator rbegin() noexcept; const_reverse_iterator rbegin() const noexcept; reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; const_iterator cbegin() const noexcept; const_iterator cend() const noexcept; const_reverse_iterator crbegin() const noexcept; const_reverse_iterator crend() const noexcept; // capacity bool empty() const noexcept; size_type size() const noexcept; size_type max_size() const noexcept; // [set.modifiers], modifiers template<class... Args> pair<iterator, bool> emplace(Args&&... args); template<class... Args> iterator emplace_hint(const_iterator position, Args&&... args); pair<iterator,bool> insert(const value_type& x); pair<iterator,bool> insert(value_type&& x); template<class K> pair<iterator, bool> insert(K&& x); iterator insert(const_iterator position, const value_type& x); iterator insert(const_iterator position, value_type&& x); template<class K> iterator insert(const_iterator position, K&& x); template<class InputIterator> void insert(InputIterator first, InputIterator last); template<container-compatible-range<value_type> R> void insert_range(R&& rg); void insert(initializer_list<value_type>); node_type extract(const_iterator position); node_type extract(const key_type& x); template<class K> node_type extract(K&& x); insert_return_type insert(node_type&& nh); iterator insert(const_iterator hint, node_type&& nh); iterator erase(iterator position) requires (!same_as<iterator, const_iterator>); iterator erase(const_iterator position); size_type erase(const key_type& x); template<class K> size_type erase(K&& x); iterator erase(const_iterator first, const_iterator last); void swap(set&) noexcept(allocator_traits<Allocator>::is_always_equal::value && is_nothrow_swappable_v<Compare>); void clear() noexcept; template<class C2> void merge(set<Key, C2, Allocator>& source); template<class C2> void merge(set<Key, C2, Allocator>&& source); template<class C2> void merge(multiset<Key, C2, Allocator>& source); template<class C2> void merge(multiset<Key, C2, Allocator>&& source); // observers key_compare key_comp() const; value_compare value_comp() const; // set operations iterator find(const key_type& x); const_iterator find(const key_type& x) const; template<class K> iterator find(const K& x); template<class K> const_iterator find(const K& x) const; size_type count(const key_type& x) const; template<class K> size_type count(const K& x) const; bool contains(const key_type& x) const; template<class K> bool contains(const K& x) const; iterator lower_bound(const key_type& x); const_iterator lower_bound(const key_type& x) const; template<class K> iterator lower_bound(const K& x); template<class K> const_iterator lower_bound(const K& x) const; iterator upper_bound(const key_type& x); const_iterator upper_bound(const key_type& x) const; template<class K> iterator upper_bound(const K& x); template<class K> const_iterator upper_bound(const K& x) const; pair<iterator, iterator> equal_range(const key_type& x); pair<const_iterator, const_iterator> equal_range(const key_type& x) const; template<class K> pair<iterator, iterator> equal_range(const K& x); template<class K> pair<const_iterator, const_iterator> equal_range(const K& x) const; }; template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>, class Allocator = allocator<iter-value-type<InputIterator>>> set(InputIterator, InputIterator, Compare = Compare(), Allocator = Allocator()) -> set<iter-value-type<InputIterator>, Compare, Allocator>; template<ranges::input_range R, class Compare = less<ranges::range_value_t<R>>, class Allocator = allocator<ranges::range_value_t<R>>> set(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) -> set<ranges::range_value_t<R>, Compare, Allocator>; template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>> set(initializer_list<Key>, Compare = Compare(), Allocator = Allocator()) -> set<Key, Compare, Allocator>; template<class InputIterator, class Allocator> set(InputIterator, InputIterator, Allocator) -> set<iter-value-type<InputIterator>, less<iter-value-type<InputIterator>>, Allocator>; template<ranges::input_range R, class Allocator> set(from_range_t, R&&, Allocator) -> set<ranges::range_value_t<R>, less<ranges::range_value_t<R>>, Allocator>; template<class Key, class Allocator> set(initializer_list<Key>, Allocator) -> set<Key, less<Key>, Allocator>; }

23.4.6.2 Constructors, copy, and assignment [set.cons]

explicit set(const Compare& comp, const Allocator& = Allocator());
Effects: Constructs an empty set using the specified comparison object and allocator.
Complexity: Constant.
template<class InputIterator> set(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator());
Effects: Constructs an empty set using the specified comparison object and allocator, and inserts elements from the range [first, last).
Complexity: Linear in N if the range [first, last) is already sorted with respect to comp and otherwise , where N is last - first.
template<container-compatible-range<value_type> R> set(from_range_t, R&& rg, const Compare& comp = Compare(), const Allocator& = Allocator());
Effects: Constructs an empty set using the specified comparison object and allocator, and inserts elements from the range rg.
Complexity: Linear in N if rg is already sorted with respect to comp and otherwise , where N is ranges​::​distance(rg).

23.4.6.3 Erasure [set.erasure]

template<class Key, class Compare, class Allocator, class Predicate> typename set<Key, Compare, Allocator>::size_type erase_if(set<Key, Compare, Allocator>& c, Predicate pred);
Effects: Equivalent to: auto original_size = c.size(); for (auto i = c.begin(), last = c.end(); i != last; ) { if (pred(*i)) { i = c.erase(i); } else { ++i; } } return original_size - c.size();

23.4.6.4 Modifiers [set.modifiers]

template<class K> pair<iterator, bool> insert(K&& x); template<class K> iterator insert(const_iterator hint, K&& x);
Constraints: The qualified-id Compare​::​is_transparent is valid and denotes a type.
For the second overload, is_convertible_v<K&&, const_iterator> and is_convertible_v<K&&, iterator> are both false.
Preconditions: value_type is Cpp17EmplaceConstructible into set from std​::​forward<K>(x).
Effects: If the set already contains an element that is equivalent to x, there is no effect.
Otherwise, let r be equal_range(x).
Constructs an object u of type value_type with std​::​forward<K>(x).
If equal_range(u) == r is false, the behavior is undefined.
Inserts u into *this.
Returns: For the first overload, the bool component of the returned pair is true if and only if the insertion took place.
The returned iterator points to the set element that is equivalent to x.
Complexity: Logarithmic.

23.4.7 Class template multiset [multiset]

23.4.7.1 Overview [multiset.overview]

A multiset is an associative container that supports equivalent keys (i.e., possibly contains multiple copies of the same key value) and provides for fast retrieval of the keys themselves.
The multiset class supports bidirectional iterators.
A multiset meets all of the requirements of a container ([container.reqmts]), of a reversible container ([container.rev.reqmts]), of an allocator-aware container ([container.alloc.reqmts]), of an associative container ([associative.reqmts]).
multiset also provides most operations described in [associative.reqmts] for duplicate keys.
This means that a multiset supports the a_eq operations in [associative.reqmts] but not the a_uniq operations.
For a multiset<Key> both the key_type and value_type are Key.
Descriptions are provided here only for operations on multiset that are not described in one of these tables and for operations where there is additional semantic information.
namespace std { template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>> class multiset { public: // types using key_type = Key; using key_compare = Compare; using value_type = Key; using value_compare = Compare; using allocator_type = Allocator; using pointer = typename allocator_traits<Allocator>::pointer; using const_pointer = typename allocator_traits<Allocator>::const_pointer; using reference = value_type&; using const_reference = const value_type&; using size_type = implementation-defined; // see [container.requirements] using difference_type = implementation-defined; // see [container.requirements] 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 node_type = unspecified; // [multiset.cons], construct/copy/destroy multiset() : multiset(Compare()) { } explicit multiset(const Compare& comp, const Allocator& = Allocator()); template<class InputIterator> multiset(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator()); template<container-compatible-range<value_type> R> multiset(from_range_t, R&& rg, const Compare& comp = Compare(), const Allocator& = Allocator()); multiset(const multiset& x); multiset(multiset&& x); explicit multiset(const Allocator&); multiset(const multiset&, const type_identity_t<Allocator>&); multiset(multiset&&, const type_identity_t<Allocator>&); multiset(initializer_list<value_type>, const Compare& = Compare(), const Allocator& = Allocator()); template<class InputIterator> multiset(InputIterator first, InputIterator last, const Allocator& a) : multiset(first, last, Compare(), a) { } template<container-compatible-range<value_type> R> multiset(from_range_t, R&& rg, const Allocator& a)) : multiset(from_range, std::forward<R>(rg), Compare(), a) { } multiset(initializer_list<value_type> il, const Allocator& a) : multiset(il, Compare(), a) { } ~multiset(); multiset& operator=(const multiset& x); multiset& operator=(multiset&& x) noexcept(allocator_traits<Allocator>::is_always_equal::value && is_nothrow_move_assignable_v<Compare>); multiset& operator=(initializer_list<value_type>); allocator_type get_allocator() const noexcept; // iterators iterator begin() noexcept; const_iterator begin() const noexcept; iterator end() noexcept; const_iterator end() const noexcept; reverse_iterator rbegin() noexcept; const_reverse_iterator rbegin() const noexcept; reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; const_iterator cbegin() const noexcept; const_iterator cend() const noexcept; const_reverse_iterator crbegin() const noexcept; const_reverse_iterator crend() const noexcept; // capacity bool empty() const noexcept; size_type size() const noexcept; size_type max_size() const noexcept; // modifiers template<class... Args> iterator emplace(Args&&... args); template<class... Args> iterator emplace_hint(const_iterator position, Args&&... args); iterator insert(const value_type& x); iterator insert(value_type&& x); iterator insert(const_iterator position, const value_type& x); iterator insert(const_iterator position, value_type&& x); template<class InputIterator> void insert(InputIterator first, InputIterator last); template<container-compatible-range<value_type> R> void insert_range(R&& rg); void insert(initializer_list<value_type>); node_type extract(const_iterator position); node_type extract(const key_type& x); template<class K> node_type extract(K&& x); iterator insert(node_type&& nh); iterator insert(const_iterator hint, node_type&& nh); iterator erase(iterator position) requires (!same_as<iterator, const_iterator>); iterator erase(const_iterator position); size_type erase(const key_type& x); template<class K> size_type erase(K&& x); iterator erase(const_iterator first, const_iterator last); void swap(multiset&) noexcept(allocator_traits<Allocator>::is_always_equal::value && is_nothrow_swappable_v<Compare>); void clear() noexcept; template<class C2> void merge(multiset<Key, C2, Allocator>& source); template<class C2> void merge(multiset<Key, C2, Allocator>&& source); template<class C2> void merge(set<Key, C2, Allocator>& source); template<class C2> void merge(set<Key, C2, Allocator>&& source); // observers key_compare key_comp() const; value_compare value_comp() const; // set operations iterator find(const key_type& x); const_iterator find(const key_type& x) const; template<class K> iterator find(const K& x); template<class K> const_iterator find(const K& x) const; size_type count(const key_type& x) const; template<class K> size_type count(const K& x) const; bool contains(const key_type& x) const; template<class K> bool contains(const K& x) const; iterator lower_bound(const key_type& x); const_iterator lower_bound(const key_type& x) const; template<class K> iterator lower_bound(const K& x); template<class K> const_iterator lower_bound(const K& x) const; iterator upper_bound(const key_type& x); const_iterator upper_bound(const key_type& x) const; template<class K> iterator upper_bound(const K& x); template<class K> const_iterator upper_bound(const K& x) const; pair<iterator, iterator> equal_range(const key_type& x); pair<const_iterator, const_iterator> equal_range(const key_type& x) const; template<class K> pair<iterator, iterator> equal_range(const K& x); template<class K> pair<const_iterator, const_iterator> equal_range(const K& x) const; }; template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>, class Allocator = allocator<iter-value-type<InputIterator>>> multiset(InputIterator, InputIterator, Compare = Compare(), Allocator = Allocator()) -> multiset<iter-value-type<InputIterator>, Compare, Allocator>; template<ranges::input_range R, class Compare = less<ranges::range_value_t<R>>, class Allocator = allocator<ranges::range_value_t<R>>> multiset(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) -> multiset<ranges::range_value_t<R>, Compare, Allocator>; template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>> multiset(initializer_list<Key>, Compare = Compare(), Allocator = Allocator()) -> multiset<Key, Compare, Allocator>; template<class InputIterator, class Allocator> multiset(InputIterator, InputIterator, Allocator) -> multiset<iter-value-type<InputIterator>, less<iter-value-type<InputIterator>>, Allocator>; template<ranges::input_range R, class Allocator> multiset(from_range_t, R&&, Allocator) -> multiset<ranges::range_value_t<R>, less<ranges::range_value_t<R>>, Allocator>; template<class Key, class Allocator> multiset(initializer_list<Key>, Allocator) -> multiset<Key, less<Key>, Allocator>; }

23.4.7.2 Constructors [multiset.cons]

explicit multiset(const Compare& comp, const Allocator& = Allocator());
Effects: Constructs an empty multiset using the specified comparison object and allocator.
Complexity: Constant.
template<class InputIterator> multiset(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator());
Effects: Constructs an empty multiset using the specified comparison object and allocator, and inserts elements from the range [first, last).
Complexity: Linear in N if the range [first, last) is already sorted with respect to comp and otherwise , where N is last - first.
template<container-compatible-range<value_type> R> multiset(from_range_t, R&& rg, const Compare& comp = Compare(), const Allocator& = Allocator());
Effects: Constructs an empty multiset using the specified comparison object and allocator, and inserts elements from the range rg.
Complexity: Linear in N if rg is already sorted with respect to comp and otherwise , where N is ranges​::​distance(rg).

23.4.7.3 Erasure [multiset.erasure]

template<class Key, class Compare, class Allocator, class Predicate> typename multiset<Key, Compare, Allocator>::size_type erase_if(multiset<Key, Compare, Allocator>& c, Predicate pred);
Effects: Equivalent to: auto original_size = c.size(); for (auto i = c.begin(), last = c.end(); i != last; ) { if (pred(*i)) { i = c.erase(i); } else { ++i; } } return original_size - c.size();