24 Containers library [containers]

24.6 Container adaptors [container.adaptors]

24.6.9 Class template flat_map [flat.map]

24.6.9.1 Overview [flat.map.overview]

A flat_map is a container adaptor that provides an associative container interface 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.
flat_map supports iterators that meet the Cpp17InputIterator requirements and model the random_access_iterator concept ([iterator.concept.random.access]).
A flat_map meets all of the requirements of a container ([container.reqmts]) and of a reversible container ([container.rev.reqmts]), plus the optional container requirements ([container.opt.reqmts]).
flat_map meets the requirements of an associative container ([associative.reqmts]), except that:
  • it does not meet the requirements related to node handles ([container.node]),
  • 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 map is linear, including the ones that take an insertion position iterator.
[Note 1: 
A flat_map does not meet the additional requirements of an allocator-aware container ([container.alloc.reqmts]).
— end note]
A flat_map also provides most operations described in [associative.reqmts] for unique keys.
This means that a flat_map supports the a_uniq operations in [associative.reqmts] but not the a_eq operations.
For a flat_map<Key, T> the key_type is Key and the value_type is pair<Key, T>.
Descriptions are provided here only for operations on flat_map that are not described in one of those sets of requirements or for operations where there is additional semantic information.
A flat_map maintains the following invariants:
  • it contains the same number of keys and values;
  • the keys are sorted with respect to the comparison object; and
  • the value at offset off within the value container is the value associated with the key at offset off within the key container.
If any member function in [flat.map.defn] exits via an exception the invariants are restored.
[Note 2: 
This can result in the flat_map being emptied.
— end note]
Any type C that meets the sequence container requirements ([sequence.reqmts]) can be used to instantiate flat_map, as long as C​::​iterator meets the Cpp17RandomAccessIterator requirements and invocations of member functions C​::​size and C​::​max_size do not exit via an exception.
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 or T is not the same type as MappedContainer​::​value_type.
The effect of calling a constructor that takes both key_container_type and mapped_container_type arguments with containers of different sizes is undefined.
The effect of calling a constructor or member function that takes a sorted_unique_t argument with a container, containers, or range that is not sorted with respect to key_comp(), or that contains equal elements, is undefined.

24.6.9.2 Definition [flat.map.defn]

namespace std { template<class Key, class T, class Compare = less<Key>, class KeyContainer = vector<Key>, class MappedContainer = vector<T>> class flat_map { public: // types using key_type = Key; using mapped_type = T; using value_type = pair<key_type, mapped_type>; using key_compare = Compare; using reference = pair<const key_type&, mapped_type&>; using const_reference = pair<const key_type&, const mapped_type&>; using size_type = size_t; using difference_type = ptrdiff_t; 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 key_container_type = KeyContainer; using mapped_container_type = MappedContainer; class value_compare { private: key_compare comp; // exposition only value_compare(key_compare c) : comp(c) { } // exposition only public: bool operator()(const_reference x, const_reference y) const { return comp(x.first, y.first); } }; struct containers { key_container_type keys; mapped_container_type values; }; // [flat.map.cons], construct/copy/destroy flat_map() : flat_map(key_compare()) { } template<class Allocator> flat_map(const flat_map&, const Allocator& a); template<class Allocator> flat_map(flat_map&&, const Allocator& a); 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); explicit flat_map(const key_compare& comp) : c(), compare(comp) { } template<class Allocator> flat_map(const key_compare& comp, const Allocator& a); template<class Allocator> explicit flat_map(const Allocator& a); template<class InputIterator> flat_map(InputIterator first, InputIterator last, const key_compare& comp = key_compare()) : c(), compare(comp) { insert(first, last); } template<class InputIterator, class Allocator> flat_map(InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); template<class InputIterator, class Allocator> flat_map(InputIterator first, InputIterator last, const Allocator& a); template<container-compatible-range<value_type> R> flat_map(from_range_t fr, R&& rg) : flat_map(fr, std::forward<R>(rg), key_compare()) { } template<container-compatible-range<value_type> R, class Allocator> flat_map(from_range_t, R&& rg, const Allocator& a); template<container-compatible-range<value_type> R> flat_map(from_range_t, R&& rg, const key_compare& comp) : flat_map(comp) { insert_range(std::forward<R>(rg)); } template<container-compatible-range<value_type> R, class Allocator> flat_map(from_range_t, R&& rg, const key_compare& comp, const Allocator& a); template<class InputIterator> flat_map(sorted_unique_t s, InputIterator first, InputIterator last, const key_compare& comp = key_compare()) : c(), compare(comp) { insert(s, first, last); } template<class InputIterator, class Allocator> flat_map(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); template<class InputIterator, class Allocator> flat_map(sorted_unique_t, InputIterator first, InputIterator last, const Allocator& a); flat_map(initializer_list<value_type> il, const key_compare& comp = key_compare()) : flat_map(il.begin(), il.end(), comp) { } template<class Allocator> flat_map(initializer_list<value_type> il, const key_compare& comp, const Allocator& a); template<class Allocator> flat_map(initializer_list<value_type> il, const Allocator& a); flat_map(sorted_unique_t s, initializer_list<value_type> il, const key_compare& comp = key_compare()) : flat_map(s, il.begin(), il.end(), comp) { } template<class Allocator> flat_map(sorted_unique_t, initializer_list<value_type> il, const key_compare& comp, const Allocator& a); template<class Allocator> flat_map(sorted_unique_t, initializer_list<value_type> il, const Allocator& a); flat_map& operator=(initializer_list<value_type> il); // 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; // [flat.map.capacity], capacity [[nodiscard]] bool empty() const noexcept; size_type size() const noexcept; size_type max_size() const noexcept; // [flat.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; // [flat.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) { return emplace(x); } pair<iterator, bool> insert(value_type&& x) { return emplace(std::move(x)); } iterator insert(const_iterator position, const value_type& x) { return emplace_hint(position, x); } iterator insert(const_iterator position, value_type&& x) { return emplace_hint(position, std::move(x)); } template<class P> pair<iterator, bool> insert(P&& x); template<class P> iterator insert(const_iterator position, P&&); template<class InputIterator> void insert(InputIterator first, InputIterator last); template<class InputIterator> void insert(sorted_unique_t, InputIterator first, InputIterator last); template<container-compatible-range<value_type> R> void insert_range(R&& rg); void insert(initializer_list<value_type> il) { insert(il.begin(), il.end()); } void insert(sorted_unique_t s, initializer_list<value_type> il) { insert(s, il.begin(), il.end()); } containers extract() &&; void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont); 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(flat_map& y) noexcept; void clear() noexcept; // observers key_compare key_comp() const; value_compare value_comp() const; const key_container_type& keys() const noexcept { return c.keys; } const mapped_container_type& values() const noexcept { return c.values; } // 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; friend bool operator==(const flat_map& x, const flat_map& y); friend synth-three-way-result<value_type> operator<=>(const flat_map& x, const flat_map& y); friend void swap(flat_map& x, flat_map& y) noexcept { x.swap(y); } private: containers c; // exposition only key_compare compare; // exposition only struct key_equiv { // exposition only key_equiv(key_compare c) : comp(c) { } bool operator()(const_reference x, const_reference y) const { return !comp(x.first, y.first) && !comp(y.first, x.first); } key_compare comp; }; }; 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, Compare, 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, Compare, 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>; template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>> flat_map(InputIterator, InputIterator, Compare = Compare()) -> flat_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Compare>; template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>> flat_map(sorted_unique_t, InputIterator, InputIterator, Compare = Compare()) -> flat_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Compare>; template<ranges::input_range R, class Compare = less<range-key-type<R>>, class Allocator = allocator<byte>> flat_map(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) -> flat_map<range-key-type<R>, range-mapped-type<R>, Compare, vector<range-key-type<R>, alloc-rebind<Allocator, range-key-type<R>>>, vector<range-mapped-type<R>, alloc-rebind<Allocator, range-mapped-type<R>>>>; template<ranges::input_range R, class Allocator> flat_map(from_range_t, R&&, Allocator) -> flat_map<range-key-type<R>, range-mapped-type<R>, less<range-key-type<R>>, vector<range-key-type<R>, alloc-rebind<Allocator, range-key-type<R>>>, vector<range-mapped-type<R>, alloc-rebind<Allocator, range-mapped-type<R>>>>; template<class Key, class T, class Compare = less<Key>> flat_map(initializer_list<pair<Key, T>>, Compare = Compare()) -> flat_map<Key, T, Compare>; template<class Key, class T, class Compare = less<Key>> flat_map(sorted_unique_t, initializer_list<pair<Key, T>>, Compare = Compare()) -> flat_map<Key, T, Compare>; template<class Key, class T, class Compare, class KeyContainer, class MappedContainer, class Allocator> struct uses_allocator<flat_map<Key, T, Compare, KeyContainer, MappedContainer>, Allocator> : bool_constant<uses_allocator_v<KeyContainer, Allocator> && uses_allocator_v<MappedContainer, Allocator>> { }; }
The member type containers has the data members and special members specified above.
It has no base classes or members other than those specified.

24.6.9.3 Constructors [flat.map.cons]

flat_map(key_container_type key_cont, mapped_container_type mapped_cont, const key_compare& comp = key_compare());
Effects: Initializes c.keys with std​::​move(key_cont), c.values with std​::​move(mapped_cont), and compare with comp; sorts the range [begin(), end()) with respect to value_comp(); and finally erases the duplicate elements as if by: auto zv = views::zip(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());
Complexity: Linear in N if the container arguments are already sorted with respect to value_comp() and otherwise , 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);
Constraints: uses_allocator_v<key_container_type, Allocator> is true and uses_allocator_v<mapped_container_type, Allocator> is true.
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]).
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());
Effects: Initializes c.keys with std​::​move(key_cont), c.values with std​::​move(mapped_cont), and compare with comp.
Complexity: Constant.
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);
Constraints: uses_allocator_v<key_container_type, Allocator> is true and uses_allocator_v<mapped_container_type, Allocator> is true.
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]).
Complexity: Linear.
template<class Allocator> flat_map(const flat_map&, const Allocator& a); template<class Allocator> flat_map(flat_map&&, const Allocator& a); template<class Allocator> flat_map(const key_compare& comp, const Allocator& a); template<class Allocator> explicit flat_map(const Allocator& a); template<class InputIterator, class Allocator> flat_map(InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); template<class InputIterator, class Allocator> flat_map(InputIterator first, InputIterator last, const Allocator& a); template<container-compatible-range<value_type> R, class Allocator> flat_map(from_range_t, R&& rg, const Allocator& a); template<container-compatible-range<value_type> R, class Allocator> flat_map(from_range_t, R&& rg, const key_compare& comp, const Allocator& a); template<class InputIterator, class Allocator> flat_map(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); template<class InputIterator, class Allocator> flat_map(sorted_unique_t, InputIterator first, InputIterator last, const Allocator& a); template<class Allocator> flat_map(initializer_list<value_type> il, const key_compare& comp, const Allocator& a); template<class Allocator> flat_map(initializer_list<value_type> il, const Allocator& a); template<class Allocator> flat_map(sorted_unique_t, initializer_list<value_type> il, const key_compare& comp, const Allocator& a); template<class Allocator> flat_map(sorted_unique_t, initializer_list<value_type> il, const Allocator& a);
Constraints: uses_allocator_v<key_container_type, Allocator> is true and uses_allocator_v<mapped_container_type, Allocator> is true.
Effects: Equivalent to the corresponding non-allocator constructors except that c.keys and c.values are constructed with uses-allocator construction ([allocator.uses.construction]).

24.6.9.4 Capacity [flat.map.capacity]

size_type size() const noexcept;
Returns: c.keys.size().
size_type max_size() const noexcept;
Returns: min<size_type>(c.keys.max_size(), c.values.max_size()).

24.6.9.5 Access [flat.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 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.

24.6.9.6 Modifiers [flat.map.modifiers]

template<class... Args> pair<iterator, bool> emplace(Args&&... args);
Constraints: is_constructible_v<pair<key_type, mapped_type>, Args...> is true.
Effects: Initializes an object t of type pair<key_type, mapped_type> with std​::​forward<Args>(
args)...
; if the map already contains an element whose key is equivalent to t.first, *this is unchanged.
Otherwise, equivalent to: auto key_it = ranges::upper_bound(c.keys, t.first, compare); auto value_it = c.values.begin() + distance(c.keys.begin(), key_it); c.keys.insert(key_it, std::move(t.first)); c.values.insert(value_it, std::move(t.second));
Returns: The bool component of the returned pair is true if and only if the insertion took place, and the iterator component of the pair points to the element with key equivalent to t.first.
template<class P> pair<iterator, bool> insert(P&& x); template<class P> iterator insert(const_iterator position, P&& x);
Constraints: is_constructible_v<pair<key_type, mapped_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 InputIterator> void insert(InputIterator first, InputIterator last);
Effects: Adds elements to c as if by: for (; first != last; ++first) { value_type value = *first; c.keys.insert(c.keys.end(), std::move(value.first)); c.values.insert(c.values.end(), std::move(value.second)); }
Then, sorts the range of newly inserted elements with respect to value_comp(); merges the resulting sorted range and the sorted range of pre-existing elements into a single sorted range; and finally erases the duplicate elements as if by: auto zv = views::zip(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());
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> void insert(sorted_unique_t, InputIterator first, InputIterator last);
Effects: Adds elements to c as if by: for (; first != last; ++first) { value_type value = *first; c.keys.insert(c.keys.end(), std::move(value.first)); c.values.insert(c.values.end(), std::move(value.second)); }
Then, merges the sorted range of newly added elements and the sorted range of pre-existing elements into a single sorted range; and finally erases the duplicate elements as if by: auto zv = views::zip(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());
Complexity: Linear in N, where N is size() after the operation.
Remarks: Since this operation performs an in-place merge, it may allocate memory.
template<container-compatible-range<value_type> R> void insert_range(R&& rg);
Effects: Adds elements to c as if by: for (const auto& e : rg) { c.keys.insert(c.keys.end(), e.first); c.values.insert(c.values.end(), e.second); }
Then, sorts the range of newly inserted elements with respect to value_comp(); merges the resulting sorted range and the sorted range of pre-existing elements into a single sorted range; and finally erases the duplicate elements as if by: auto zv = views::zip(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());
Complexity: N + , where N is size() before the operation and M is ranges​::​distance(rg).
Remarks: Since this operation performs an in-place merge, it may allocate memory.
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... 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);
Constraints: is_constructible_v<mapped_type, Args...> is true.
Effects: If the map already contains an element whose key is equivalent to k, *this and args... are unchanged.
Otherwise equivalent to: auto key_it = ranges::upper_bound(c.keys, k, compare); auto value_it = c.values.begin() + distance(c.keys.begin(), key_it); c.keys.insert(key_it, std::forward<decltype(k)>(k)); c.values.emplace(value_it, std::forward<Args>(args)...);
Returns: In the first two overloads, 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 for the first two overloads, and the same as emplace_hint for the last two overloads.
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.
  • is_constructible_v<key_type, K> is true.
  • is_constructible_v<mapped_type, Args...> is true.
  • For the first overload, is_convertible_v<K&&, const_iterator> and is_convertible_v<K&&, iterator> are both false.
Preconditions: The conversion from k into key_type constructs an object u, for which find(k) == find(u) is true.
Effects: If the map already contains an element whose key is equivalent to k, *this and args... are unchanged.
Otherwise equivalent to: auto key_it = ranges::upper_bound(c.keys, k, compare); auto value_it = c.values.begin() + distance(c.keys.begin(), key_it); c.keys.emplace(key_it, std::forward<K>(k)); c.values.emplace(value_it, 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 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 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);
Constraints: is_assignable_v<mapped_type&, M> is true and is_constructible_v<mapped_type, M> is true.
Effects: If the map already contains an element e whose key is equivalent to k, assigns std​::​forward<
M>(obj)
to e.second.
Otherwise, equivalent to try_emplace(std::forward<decltype(k)>(k), std::forward<M>(obj)) for the first two overloads or try_emplace(hint, std::forward<decltype(k)>(k), std::forward<M>(obj)) for the last two overloads.
Returns: In the first two overloads, 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 for the first two overloads and the same as emplace_hint for the last two overloads.
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.
  • is_constructible_v<key_type, K> is true.
  • is_assignable_v<mapped_type&, M> is true.
  • is_constructible_v<mapped_type, M> is true.
Preconditions: The conversion from k into key_type constructs an object u, for which find(k) == find(u) is true.
Effects: If the map already contains an element e whose key is equivalent to k, assigns std​::​forward<
M>(obj)
to e.second.
Otherwise, equivalent to try_emplace(std::forward<K>(k), std::forward<M>(obj)) for the first overload or try_emplace(hint, std::forward<K>(k), std::forward<M>(obj)) for the second overload.
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.
void swap(flat_map& y) noexcept;
Effects: Equivalent to: ranges::swap(compare, y.compare); ranges::swap(c.keys, y.c.keys); ranges::swap(c.values, y.c.values);
containers extract() &&;
Postconditions: *this is emptied, even if the function exits via an exception.
Returns: std​::​move(c).
void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont);
Preconditions: key_cont.size() == mapped_cont.size() is true, the elements of key_cont are sorted with respect to compare, and key_cont contains no equal elements.
Effects: Equivalent to: c.keys = std::move(key_cont); c.values = std::move(mapped_cont);

24.6.9.7 Erasure [flat.map.erasure]

template<class Key, class T, class Compare, class KeyContainer, class MappedContainer, class Predicate> typename flat_map<Key, T, Compare, KeyContainer, MappedContainer>::size_type erase_if(flat_map<Key, T, Compare, KeyContainer, MappedContainer>& c, Predicate pred);
Preconditions: Key and T meet the Cpp17MoveAssignable requirements.
Effects: Let E be bool(pred(pair<const Key&, const T&>(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]