24 Containers library [containers]

24.6 Container adaptors [container.adaptors]

24.6.11 Class template flat_set [flat.set]

24.6.11.1 Overview [flat.set.overview]

A flat_set 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 the keys themselves.
flat_set supports iterators that model the random_access_iterator concept ([iterator.concept.random.access]).
A flat_set 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_set 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_set does not meet the additional requirements of an allocator-aware container, as described in [container.alloc.reqmts].
— end note]
A flat_set also provides most operations described in [associative.reqmts] for unique keys.
This means that a flat_set supports the a_uniq operations in [associative.reqmts] but not the a_eq operations.
For a flat_set<Key>, both the key_type and value_type are Key.
Descriptions are provided here only for operations on flat_set that are not described in one of those sets of requirements or for operations where there is additional semantic information.
A flat_set maintains the invariant that the keys are sorted with respect to the comparison object.
If any member function in [flat.set.defn] exits via an exception, the invariant is restored.
[Note 2: 
This can result in the flat_set's being emptied.
— end note]
Any sequence container ([sequence.reqmts]) supporting Cpp17RandomAccessIterator can be used to instantiate flat_set.
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_unique_t argument with a range that is not sorted with respect to key_comp(), or that contains equal elements, is undefined.

24.6.11.2 Definition [flat.set.defn]

namespace std { template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>> class flat_set { 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.set.cons], constructors flat_set() : flat_set(key_compare()) { } template<class Allocator> flat_set(const flat_set&, const Allocator& a); template<class Allocator> flat_set(flat_set&&, const Allocator& a); explicit flat_set(container_type cont, const key_compare& comp = key_compare()); template<class Allocator> flat_set(const container_type& cont, const Allocator& a); template<class Allocator> flat_set(const container_type& cont, const key_compare& comp, const Allocator& a); flat_set(sorted_unique_t, container_type cont, const key_compare& comp = key_compare()) : c(std::move(cont)), compare(comp) { } template<class Allocator> flat_set(sorted_unique_t, const container_type& cont, const Allocator& a); template<class Allocator> flat_set(sorted_unique_t, const container_type& cont, const key_compare& comp, const Allocator& a); explicit flat_set(const key_compare& comp) : c(), compare(comp) { } template<class Allocator> flat_set(const key_compare& comp, const Allocator& a); template<class Allocator> explicit flat_set(const Allocator& a); template<class InputIterator> flat_set(InputIterator first, InputIterator last, const key_compare& comp = key_compare()) : c(), compare(comp) { insert(first, last); } template<class InputIterator, class Allocator> flat_set(InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); template<class InputIterator, class Allocator> flat_set(InputIterator first, InputIterator last, const Allocator& a); template<container-compatible-range<value_type> R> flat_set(from_range_t fr, R&& rg) : flat_set(fr, std::forward<R>(rg), key_compare()) { } template<container-compatible-range<value_type> R, class Allocator> flat_set(from_range_t, R&& rg, const Allocator& a); template<container-compatible-range<value_type> R> flat_set(from_range_t, R&& rg, const key_compare& comp) : flat_set(comp) { insert_range(std::forward<R>(rg)); } template<container-compatible-range<value_type> R, class Allocator> flat_set(from_range_t, R&& rg, const key_compare& comp, const Allocator& a); template<class InputIterator> flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp = key_compare()) : c(first, last), compare(comp) { } template<class InputIterator, class Allocator> flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); template<class InputIterator, class Allocator> flat_set(sorted_unique_t, InputIterator first, InputIterator last, const Allocator& a); flat_set(initializer_list<value_type> il, const key_compare& comp = key_compare()) : flat_set(il.begin(), il.end(), comp) { } template<class Allocator> flat_set(initializer_list<value_type> il, const key_compare& comp, const Allocator& a); template<class Allocator> flat_set(initializer_list<value_type> il, const Allocator& a); flat_set(sorted_unique_t s, initializer_list<value_type> il, const key_compare& comp = key_compare()) : flat_set(s, il.begin(), il.end(), comp) { } template<class Allocator> flat_set(sorted_unique_t, initializer_list<value_type> il, const key_compare& comp, const Allocator& a); template<class Allocator> flat_set(sorted_unique_t, initializer_list<value_type> il, const Allocator& a); flat_set& operator=(initializer_list<value_type>); // 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 [[nodiscard]] bool empty() const noexcept; size_type size() const noexcept; size_type max_size() const noexcept; // [flat.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) { return emplace(x); } pair<iterator, bool> insert(value_type&& x) { return emplace(std::move(x)); } template<class K> pair<iterator, bool> insert(K&& 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 K> iterator insert(const_iterator hint, K&& x); 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()); } container_type extract() &&; void replace(container_type&&); 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_set& y) noexcept; void clear() noexcept; // 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; friend bool operator==(const flat_set& x, const flat_set& y); friend synth-three-way-result<value_type> operator<=>(const flat_set& x, const flat_set& y); friend void swap(flat_set& x, flat_set& 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_set(KeyContainer, Compare = Compare()) -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>; template<class KeyContainer, class Allocator> flat_set(KeyContainer, Allocator) -> flat_set<typename KeyContainer::value_type, less<typename KeyContainer::value_type>, KeyContainer>; template<class KeyContainer, class Compare, class Allocator> flat_set(KeyContainer, Compare, Allocator) -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>; template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>> flat_set(sorted_unique_t, KeyContainer, Compare = Compare()) -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>; template<class KeyContainer, class Allocator> flat_set(sorted_unique_t, KeyContainer, Allocator) -> flat_set<typename KeyContainer::value_type, less<typename KeyContainer::value_type>, KeyContainer>; template<class KeyContainer, class Compare, class Allocator> flat_set(sorted_unique_t, KeyContainer, Compare, Allocator) -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>; template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>> flat_set(InputIterator, InputIterator, Compare = Compare()) -> flat_set<iter-value-type<InputIterator>, Compare>; template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>> flat_set(sorted_unique_t, InputIterator, InputIterator, Compare = Compare()) -> flat_set<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_set(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) -> flat_set<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_set(from_range_t, R&&, Allocator) -> flat_set<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_set(initializer_list<Key>, Compare = Compare()) -> flat_set<Key, Compare>; template<class Key, class Compare = less<Key>> flat_set(sorted_unique_t, initializer_list<Key>, Compare = Compare()) -> flat_set<Key, Compare>; template<class Key, class Compare, class KeyContainer, class Allocator> struct uses_allocator<flat_set<Key, Compare, KeyContainer>, Allocator> : bool_constant<uses_allocator_v<KeyContainer, Allocator>> { }; }

24.6.11.3 Constructors [flat.set.cons]

explicit flat_set(container_type cont, const key_compare& comp = key_compare());
Effects: Initializes c with std​::​move(cont) and compare with comp, sorts the range [begin(), end()) with respect to compare, and finally erases all but the first element from each group of consecutive equivalent elements.
Complexity: Linear in N if cont is sorted with respect to compare and otherwise , where N is the value of cont.size() before this call.
template<class Allocator> flat_set(const container_type& cont, const Allocator& a); template<class Allocator> flat_set(const container_type& cont, const key_compare& comp, const Allocator& a);
Constraints: uses_allocator_v<container_type, Allocator> is true.
Effects: Equivalent to flat_set(cont) and flat_set(cont, comp), respectively, except that c is constructed with uses-allocator construction ([allocator.uses.construction]).
Complexity: Same as flat_set(cont) and flat_set(cont, comp), respectively.
template<class Allocator> flat_set(sorted_unique_t s, const container_type& cont, const Allocator& a); template<class Allocator> flat_set(sorted_unique_t s, const container_type& cont, const key_compare& comp, const Allocator& a);
Constraints: uses_allocator_v<container_type, Allocator> is true.
Effects: Equivalent to flat_set(s, cont) and flat_set(s, cont, comp), respectively, except that c is constructed with uses-allocator construction ([allocator.uses.construction]).
Complexity: Linear.
template<class Allocator> flat_set(const flat_set&, const Allocator& a); template<class Allocator> flat_set(flat_set&&, const Allocator& a); template<class Allocator> flat_set(const key_compare& comp, const Allocator& a); template<class Allocator> explicit flat_set(const Allocator& a); template<class InputIterator, class Allocator> flat_set(InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); template<class InputIterator, class Allocator> flat_set(InputIterator first, InputIterator last, const Allocator& a); template<container-compatible-range<value_type> R, class Allocator> flat_set(from_range_t, R&& rg, const Allocator& a); template<container-compatible-range<value_type> R, class Allocator> flat_set(from_range_t, R&& rg, const key_compare& comp, const Allocator& a); template<class InputIterator, class Allocator> flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a); template<class InputIterator, class Allocator> flat_set(sorted_unique_t, InputIterator first, InputIterator last, const Allocator& a); template<class Allocator> flat_set(initializer_list<value_type> il, const key_compare& comp, const Allocator& a); template<class Allocator> flat_set(initializer_list<value_type> il, const Allocator& a); template<class Allocator> flat_set(sorted_unique_t, initializer_list<value_type> il, const key_compare& comp, const Allocator& a); template<class Allocator> flat_set(sorted_unique_t, initializer_list<value_type> il, const Allocator& a);
Constraints: uses_allocator_v<container_type, Allocator> is true.
Effects: Equivalent to the corresponding non-allocator constructors except that c is constructed with uses-allocator construction ([allocator.uses.construction]).

24.6.11.4 Modifiers [flat.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.
is_constructible_v<value_type, K> is true.
Preconditions: The conversion from x into value_type constructs an object u, for which find(x) == find(u) is true.
Effects: If the set already contains an element equivalent to x, *this and x are unchanged.
Otherwise, inserts a new element as if by emplace(std​::​forward<K>(x)).
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 element whose key is equivalent to x.
template<class InputIterator> 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; merges the resulting sorted range and the sorted range of pre-existing elements into a single sorted range; and finally erases all but the first element from each group of consecutive equivalent elements.
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: Equivalent to insert(first, last).
Complexity: Linear.
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.insert(c.end(), e); }
Then, sorts the range of newly inserted elements with respect to compare; merges the resulting sorted range and the sorted range of pre-existing elements into a single sorted range; and finally erases all but the first element from each group of consecutive equivalent elements.
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.
void swap(flat_set& y) noexcept;
Effects: Equivalent to: ranges::swap(compare, y.compare); ranges::swap(c, y.c);
container_type extract() &&;
Postconditions: *this is emptied, even if the function exits via an exception.
Returns: std​::​move(c).
void replace(container_type&& cont);
Preconditions: The elements of cont are sorted with respect to compare, and cont contains no equal elements.
Effects: Equivalent to: c = std​::​move(cont);

24.6.11.5 Erasure [flat.set.erasure]

template<class Key, class Compare, class KeyContainer, class Predicate> typename flat_set<Key, Compare, KeyContainer>::size_type erase_if(flat_set<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]