constexpr containers and adaptors
This paper proposes marking all containers and adaptors constexpr
. This will make compile time programming much easier by making normal C++ and constexpr
C++ more similar.
- R0 → R1: Added implementation specific problems with
std::less<T*>
.
All necessary constexpr
functionality required by the containers to be changed is supported by the language. There is no reason for them not to be constexpr, and the standard library should support these in order for them to properly serve as vocabulary types.
The following table shows what this paper proposes, and the status quo:
container / adapter | before | after | note |
std::array | ✔︎ | ✔︎ | since C++11/14 |
std::deque | x | ✔︎ | |
std::forward_list | x | ✔︎ | |
std::list | x | ✔︎ | |
std::vector | ✔︎ | ✔︎ | since C++20 🍫 |
std::map | x | ✔︎ | using node_handle::key() is UB (CWG-2514) |
std::multimap | x | ✔︎ | using node_handle::key() is UB (CWG-2514) |
std::set | x | ✔︎ | |
std::multiset | x | ✔︎ | |
std::unordered_map | x | ✔︎ | using node_handle::key() is UB (CWG-2514) |
std::unordered_multimap | x | ✔︎ | using node_handle::key() is UB (CWG-2514) |
std::unordered_set | x | ✔︎ | |
std::unordered_multiset | x | ✔︎ | |
std::queue | x | ✔︎ | |
std::priority_queue | x | ✔︎ | |
std::stack | x | ✔︎ | |
std::flat_map | x | ✔︎ | new adapter in C++23, originally proposed for C++20 |
std::flat_multimap | x | ✔︎ | new adapter in C++23, originally proposed for C++20 |
std::flat_set | x | ✔︎ | new adapter in C++23, originally proposed for C++20 |
std::flat_multiset | x | ✔︎ | new adapter in C++23, originally proposed for C++20 |
std::span | ✔︎ | ✔︎ | |
std::mdspan | ✔︎ | ✔︎ | |
std::basic_string | ✔︎ | ✔︎ | since C++20 🍫 |
std::basic_string_view | ✔︎ | ✔︎ | since C++17 |
I implemented the proposal in a personal fork of libc++ by marking all functions and member functions associated with containers with constexpr
. Containers deque
, forward_list
, list
, and all adaptors (note: libc++ doesn't have flat_map and flat_set yet) were modified without any problem.
When marking set
, map
, unordered_set
, and unordered_map
I ran into problems with UB in the construction of nodes, where the node is allocated but not constructed and only its subobject with value is constructed. Another UB I ran into was type-punning via union
and static_cast
from size_t
into unsigned char
when calculating hash; both these issues were fixed by using std::bit_cast
instead. This is actually a good argument for constexpr ALL the things as proper testing during constant evaluation can easily catch such problems.
Another problem with unordered_set
and unordered_map
was the absence of constexpr ceilf(float)
function, a prime calculation function in hash.cpp
, and a non-constexpr
std::hash
type template.
Here are examples with iterators and here are examples with normal operations.
One remaining UB needs to be solved in order to make std::hash<T *>
constexpr
: converting pointer to a number. For my implementation I did it by extending std::bit_cast
to convert constexpr
symbolic address to an integer.
This approach has the problem of returning an inconsistent result for constant evaluated hash in comparison to runtime computation. Same thing already applies to comparing pointers with std::less<T*>
.
Personally I would just allow std::bit_cast
from (but not to) pointer. Another alternative implementation would be a single purpose builtin __builtin_ptr_to_hash
.
Similar problem as with std::hash
is present in std::less
and other comparison functors too. Interprets of constant evaluated code don't know addresses of objects during normal execution of program (subject to optimizer, linker, and ASLR changes). If we allow comparing pointers with an implementation specific strict total ordering (as specified for functors and currently not implementable for constant evaluation). The final ordering within container can't be same for constant evaluation and runtime.
Another problem I ran into is the already existing CWG-2514 where node_handle::key()
returns non-const reference to key
which is const
inside node_type
. I don't think this is a problem with constexpr
; more with the general specification of map
and unordered_map
and when fixed it will allow using this functionality in constexpr
too.
This change does not allow non-transient allocation, so no allocation done during constant evaluation can survive to runtime. This is currently an unsolved problem and is not specific to the proposed change. This is also an argument to allow constexpr std::hash<T *>
as we can see constexpr pointers and runtime pointers as two different address spaces.
None, this is purely an API extension as the previous API wasn't usable in constexpr, and all types are templates and must be available in headers already.
Mechanically mark all functionality in [container] constexpr. Also make sure all iterator types are constexpr.
It may be used to transfer that
ownership to another container with compatible nodes
. Containers with
compatible nodes have the same node handle type
. Elements may be transferred in
either direction between container types in the same row of
Table
86. Table
86: Container types with compatible nodes
[tab:container.node.compat] | | |
| | |
| | |
| | |
| unordered_map<K, T, H1, E1, A> | unordered_map<K, T, H2, E2, A> |
| unordered_map<K, T, H1, E1, A> | unordered_multimap<K, T, H2, E2, A> |
| unordered_set<K, H1, E1, A> | unordered_set<K, H2, E2, A> |
| unordered_set<K, H1, E1, A> | unordered_multiset<K, H2, E2, A> |
If a node handle is not empty, then it contains an allocator that is equal to
the allocator of the container when the element was extracted
. If a node handle
is empty, it contains no allocator
.Class
node-handle is for exposition only
.If a user-defined specialization of
pair exists for
pair<const Key, T> or
pair<Key, T>, where
Key is the
container's
key_type and
T is the container's
mapped_type, the behavior of operations involving node handles is
undefined
.template<unspecified>
class node-handle {
public:
using value_type = see below;
using key_type = see below;
using mapped_type = see below;
using allocator_type = see below;
private:
using container_node_type = unspecified;
using ator_traits = allocator_traits<allocator_type>;
typename ator_traits::template
rebind_traits<container_node_type>::pointer ptr_;
optional<allocator_type> alloc_;
public:
constexpr node-handle() noexcept : ptr_(), alloc_() {}
constexpr node-handle(node-handle&&) noexcept;
constexpr node-handle& operator=(node-handle&&);
constexpr ~node-handle();
constexpr value_type& value() const;
constexpr key_type& key() const;
constexpr mapped_type& mapped() const;
constexpr allocator_type get_allocator() const;
constexpr explicit operator bool() const noexcept;
constexpr bool empty() const noexcept;
constexpr void swap(node-handle&)
noexcept(ator_traits::propagate_on_container_swap::value ||
ator_traits::is_always_equal::value);
constexpr friend void swap(node-handle& x, node-handle& y) noexcept(noexcept(x.swap(y))) {
x.swap(y);
}
};
constexpr node-handle(node-handle&& nh) noexcept;
Effects: Constructs a
node-handle object initializing
ptr_ with
nh.ptr_. Move constructs
alloc_ with
nh.alloc_. Assigns
nullptr to
nh.ptr_ and assigns
nullopt to
nh.alloc_.constexpr node-handle& operator=(node-handle&& nh);
Preconditions: Either
!alloc_, or
ator_traits::propagate_on_container_move_assignment::value
is
true, or
alloc_ == nh.alloc_. Effects:
If
ptr_ != nullptr, destroys the
value_type
subobject in the
container_node_type object pointed to by
ptr_
by calling
ator_traits::destroy, then deallocates
ptr_ by
calling
ator_traits::template rebind_traits<container_node_type>::deallocate.If
!alloc_ or
ator_traits::propagate_on_container_move_assignment::value
is
true, move assigns
nh.alloc_ to
alloc_.Assigns
nullptr to
nh.ptr_ and assigns
nullopt to
nh.alloc_.
constexpr ~node-handle();
Effects: If
ptr_ != nullptr, destroys the
value_type subobject
in the
container_node_type object pointed to by
ptr_ by calling
ator_traits::destroy, then deallocates
ptr_ by calling
ator_traits::template rebind_traits<container_node_type>::deallocate. constexpr value_type& value() const;
Preconditions:
empty() == false. Returns: A reference to the
value_type subobject in the
container_node_type object pointed to by
ptr_. constexpr key_type& key() const;
Preconditions:
empty() == false. Returns: A non-const reference to the
key_type member of the
value_type subobject in the
container_node_type object
pointed to by
ptr_. Remarks: Modifying the key through the returned reference is permitted
. constexpr mapped_type& mapped() const;
Preconditions:
empty() == false. Returns: A reference to the
mapped_type member of the
value_type subobject in the
container_node_type object
pointed to by
ptr_. constexpr allocator_type get_allocator() const;
Preconditions:
empty() == false. constexpr explicit operator bool() const noexcept;
Returns:
ptr_ != nullptr. constexpr bool empty() const noexcept;
Returns:
ptr_ == nullptr. constexpr void swap(node-handle& nh)
noexcept(ator_traits::propagate_on_container_swap::value ||
ator_traits::is_always_equal::value);
Preconditions:
!alloc_, or
!nh.alloc_, or
ator_traits::propagate_on_container_swap::value is
true,
or
alloc_ == nh.alloc_. Effects: Calls
swap(ptr_, nh.ptr_). If
!alloc_, or
!nh.alloc_, or
ator_traits::propagate_on_container_swap::value
is
true calls
swap(alloc_, nh.alloc_).
In addition, it supports constant time insert and erase operations at the beginning or the end;
insert and erase in the middle take linear time
. That is, a deque is especially optimized for pushing and popping elements at the beginning and end
. Storage management is handled automatically
. Descriptions are provided here only for operations on
deque
that are not described in one of these tables
or for operations where there is additional semantic information
.
namespace std {
template<class T, class Allocator = allocator<T>>
class deque {
public:
using value_type = T;
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;
using difference_type = implementation-defined;
using iterator = implementation-defined;
using const_iterator = implementation-defined;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
constexpr deque() : deque(Allocator()) { }
constexpr explicit deque(const Allocator&);
constexpr explicit deque(size_type n, const Allocator& = Allocator());
constexpr deque(size_type n, const T& value, const Allocator& = Allocator());
template<class InputIterator>
constexpr deque(InputIterator first, InputIterator last, const Allocator& = Allocator());
template<container-compatible-range<T> R>
constexpr deque(from_range_t, R&& rg, const Allocator& = Allocator());
constexpr deque(const deque& x);
constexpr deque(deque&&);
constexpr deque(const deque&, const type_identity_t<Allocator>&);
constexpr deque(deque&&, const type_identity_t<Allocator>&);
constexpr deque(initializer_list<T>, const Allocator& = Allocator());
constexpr ~deque();
constexpr deque& operator=(const deque& x);
constexpr deque& operator=(deque&& x)
noexcept(allocator_traits<Allocator>::is_always_equal::value);
constexpr deque& operator=(initializer_list<T>);
template<class InputIterator>
constexpr void assign(InputIterator first, InputIterator last);
template<container-compatible-range<T> R>
constexpr void assign_range(R&& rg);
constexpr void assign(size_type n, const T& t);
constexpr void assign(initializer_list<T>);
constexpr allocator_type get_allocator() const noexcept;
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
constexpr reverse_iterator rbegin() noexcept;
constexpr const_reverse_iterator rbegin() const noexcept;
constexpr reverse_iterator rend() noexcept;
constexpr const_reverse_iterator rend() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator cend() const noexcept;
constexpr const_reverse_iterator crbegin() const noexcept;
constexpr const_reverse_iterator crend() const noexcept;
constexpr bool empty() const noexcept;
constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;
constexpr void resize(size_type sz);
constexpr void resize(size_type sz, const T& c);
constexpr void shrink_to_fit();
constexpr reference operator[](size_type n);
constexpr const_reference operator[](size_type n) const;
constexpr reference at(size_type n);
constexpr const_reference at(size_type n) const;
constexpr reference front();
constexpr const_reference front() const;
constexpr reference back();
constexpr const_reference back() const;
template<class... Args> constexpr reference emplace_front(Args&&... args);
template<class... Args> constexpr reference emplace_back(Args&&... args);
template<class... Args> constexpr iterator emplace(const_iterator position, Args&&... args);
constexpr void push_front(const T& x);
constexpr void push_front(T&& x);
template<container-compatible-range<T> R>
constexpr void prepend_range(R&& rg);
constexpr void push_back(const T& x);
constexpr void push_back(T&& x);
template<container-compatible-range<T> R>
constexpr void append_range(R&& rg);
constexpr iterator insert(const_iterator position, const T& x);
constexpr iterator insert(const_iterator position, T&& x);
constexpr iterator insert(const_iterator position, size_type n, const T& x);
template<class InputIterator>
constexpr iterator insert(const_iterator position, InputIterator first, InputIterator last);
template<container-compatible-range<T> R>
constexpr iterator insert_range(const_iterator position, R&& rg);
constexpr iterator insert(const_iterator position, initializer_list<T>);
constexpr void pop_front();
constexpr void pop_back();
constexpr iterator erase(const_iterator position);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void swap(deque&)
noexcept(allocator_traits<Allocator>::is_always_equal::value);
constexpr void clear() noexcept;
};
template<class InputIterator, class Allocator = allocator<iter-value-type<InputIterator>>>
deque(InputIterator, InputIterator, Allocator = Allocator())
-> deque<iter-value-type<InputIterator>, Allocator>;
template<ranges::input_range R, class Allocator = allocator<ranges::range_value_t<R>>>
deque(from_range_t, R&&, Allocator = Allocator())
-> deque<ranges::range_value_t<R>, Allocator>;
}
constexpr explicit deque(const Allocator&);
Effects: Constructs an empty
deque,
using the specified allocator
. constexpr explicit deque(size_type n, const Allocator& = Allocator());
Preconditions:
T is
Cpp17DefaultInsertable into
deque. Effects: Constructs a
deque with
n default-inserted elements using the specified allocator
. constexpr deque(size_type n, const T& value, const Allocator& = Allocator());
Preconditions:
T is
Cpp17CopyInsertable into
deque. Effects: Constructs a
deque
with
n copies of
value,
using the specified allocator
. template<class InputIterator>
constexpr deque(InputIterator first, InputIterator last, const Allocator& = Allocator());
Effects: Constructs a
deque
equal to the range
[
first, last),
using the specified allocator
. Complexity: Linear in
distance(first, last). Effects: Constructs a
deque with the elements of the range
rg,
using the specified allocator
. Complexity: Linear in
ranges::distance(rg). constexpr void resize(size_type sz);
Preconditions:
T is
Cpp17MoveInsertable and
Cpp17DefaultInsertable into
deque. Effects: If
sz < size(), erases the last
size() - sz elements
from the sequence
. Otherwise,
appends
sz - size() default-inserted elements to the sequence
.constexpr void resize(size_type sz, const T& c);
Preconditions:
T is
Cpp17CopyInsertable into
deque. Effects: If
sz < size(), erases the last
size() - sz elements
from the sequence
. Otherwise,
appends
sz - size() copies of
c to the sequence
.constexpr void shrink_to_fit();
Preconditions:
T is
Cpp17MoveInsertable into
deque. Effects:
shrink_to_fit is a non-binding request to reduce memory use
but does not change the size of the sequence
. [
Note 1:
The request is non-binding to allow latitude for
implementation-specific optimizations
. —
end note]
If the size is equal to the old capacity, or
if an exception is thrown other than by the move constructor
of a non-
Cpp17CopyInsertable T,
then there are no effects
.Complexity: If the size is not equal to the old capacity,
linear in the size of the sequence;
otherwise constant
. Remarks: If the size is not equal to the old capacity,
then invalidates all the references, pointers, and iterators
referring to the elements in the sequence,
as well as the past-the-end iterator
. constexpr iterator insert(const_iterator position, const T& x);
constexpr iterator insert(const_iterator position, T&& x);
constexpr iterator insert(const_iterator position, size_type n, const T& x);
template<class InputIterator>
constexpr iterator insert(const_iterator position,
InputIterator first, InputIterator last);
template<container-compatible-range<T> R>
constexpr iterator insert_range(const_iterator position, R&& rg);
constexpr iterator insert(const_iterator position, initializer_list<T>);
template<class... Args> constexpr reference emplace_front(Args&&... args);
template<class... Args> constexpr reference emplace_back(Args&&... args);
template<class... Args> constexpr iterator emplace(const_iterator position, Args&&... args);
constexpr void push_front(const T& x);
constexpr void push_front(T&& x);
template<container-compatible-range<T> R>
constexpr void prepend_range(R&& rg);
constexpr void push_back(const T& x);
constexpr void push_back(T&& x);
template<container-compatible-range<T> R>
constexpr void append_range(R&& rg);
Effects: An insertion in the middle of the deque invalidates all the iterators and
references to elements of the deque
. An insertion at either end of the
deque invalidates all the iterators to the deque, but has no effect on
the validity of references to elements of the deque
.Complexity: The complexity is linear in the number of elements inserted plus the lesser
of the distances to the beginning and end of the deque
. Inserting a single element at either the beginning or end of a deque always takes constant time
and causes a single call to a constructor of
T.Remarks: If an exception is thrown other than by the
copy constructor, move constructor,
assignment operator, or move assignment operator of
T
there are no effects
. If an exception is thrown while inserting a single element at either end,
there are no effects
. Otherwise, if an exception is thrown by the move constructor of a
non-
Cpp17CopyInsertable
T, the effects are unspecified
.constexpr iterator erase(const_iterator position);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void pop_front();
constexpr void pop_back();
Effects: An erase operation that erases the last element of a deque invalidates only the past-the-end iterator
and all iterators and references to the erased elements
. An erase operation that erases the first
element of a deque but not the last element invalidates only iterators
and references to the erased elements
. An erase operation
that erases neither the first element nor the last element of a deque invalidates the past-the-end
iterator and all iterators and references to all the elements of the deque
. [
Note 1:
pop_front and
pop_back are erase operations
. —
end note]
Throws: Nothing unless an exception is thrown by the assignment operator of
T. Complexity: The number of calls to the destructor of
T is the same as the
number of elements erased, but the number of calls to the assignment operator of
T is
no more than the lesser of the number of elements before the erased elements and the number of elements after the erased elements
. template<class T, class Allocator, class U = T>
constexpr typename deque<T, Allocator>::size_type
erase(deque<T, Allocator>& c, const U& value);
Effects: Equivalent to:
auto it = remove(c.begin(), c.end(), value);
auto r = distance(it, c.end());
c.erase(it, c.end());
return r;
template<class T, class Allocator, class Predicate>
constexpr typename deque<T, Allocator>::size_type
erase_if(deque<T, Allocator>& c, Predicate pred);
Effects: Equivalent to:
auto it = remove_if(c.begin(), c.end(), pred);
auto r = distance(it, c.end());
c.erase(it, c.end());
return r;
A
forward_list is a container that supports forward iterators and allows
constant time insert and erase operations anywhere within the sequence, with storage
management handled automatically
. Fast random access to list elements is not supported
. [
Note 1:
It is intended that
forward_list have zero space or time overhead
relative to a hand-written C-style singly linked list
. Features that would conflict with
that goal have been omitted
. —
end note]
A
forward_list meets all of the requirements
of a container (
[container.reqmts]),
except that the
size() member function is not provided and
operator== has linear complexity,
A
forward_list also meets all of the requirements
for an allocator-aware container (
[container.alloc.reqmts])
. In addition, a
forward_list
provides the
assign member functions and
several of the optional sequence container requirements (
[sequence.reqmts])
. Descriptions are provided here only for operations on
forward_list that are not described in that table or for operations where there
is additional semantic information
.
[
Note 2:
Modifying any list requires access to the element preceding the first element
of interest, but in a
forward_list there is no constant-time way to access a
preceding element
. For this reason,
erase_after and
splice_after
take fully-open ranges, not semi-open ranges
. —
end note]
namespace std {
template<class T, class Allocator = allocator<T>>
class forward_list {
public:
using value_type = T;
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;
using difference_type = implementation-defined;
using iterator = implementation-defined;
using const_iterator = implementation-defined;
constexpr forward_list() : forward_list(Allocator()) { }
constexpr explicit forward_list(const Allocator&);
constexpr explicit forward_list(size_type n, const Allocator& = Allocator());
constexpr forward_list(size_type n, const T& value, const Allocator& = Allocator());
template<class InputIterator>
constexpr forward_list(InputIterator first, InputIterator last, const Allocator& = Allocator());
template<container-compatible-range<T> R>
constexpr forward_list(from_range_t, R&& rg, const Allocator& = Allocator());
constexpr forward_list(const forward_list& x);
constexpr forward_list(forward_list&& x);
constexpr forward_list(const forward_list& x, const type_identity_t<Allocator>&);
constexpr forward_list(forward_list&& x, const type_identity_t<Allocator>&);
constexpr forward_list(initializer_list<T>, const Allocator& = Allocator());
constexpr ~forward_list();
constexpr forward_list& operator=(const forward_list& x);
constexpr forward_list& operator=(forward_list&& x)
noexcept(allocator_traits<Allocator>::is_always_equal::value);
constexpr forward_list& operator=(initializer_list<T>);
template<class InputIterator>
constexpr void assign(InputIterator first, InputIterator last);
template<container-compatible-range<T> R>
constexpr void assign_range(R&& rg);
constexpr void assign(size_type n, const T& t);
constexpr void assign(initializer_list<T>);
constexpr allocator_type get_allocator() const noexcept;
constexpr iterator before_begin() noexcept;
constexpr const_iterator before_begin() const noexcept;
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator cbefore_begin() const noexcept;
constexpr const_iterator cend() const noexcept;
constexpr bool empty() const noexcept;
constexpr size_type max_size() const noexcept;
constexpr reference front();
constexpr const_reference front() const;
template<class... Args> constexpr reference emplace_front(Args&&... args);
constexpr void push_front(const T& x);
constexpr void push_front(T&& x);
template<container-compatible-range<T> R>
constexpr void prepend_range(R&& rg);
constexpr void pop_front();
template<class... Args> constexpr iterator emplace_after(const_iterator position, Args&&... args);
constexpr iterator insert_after(const_iterator position, const T& x);
constexpr iterator insert_after(const_iterator position, T&& x);
constexpr iterator insert_after(const_iterator position, size_type n, const T& x);
template<class InputIterator>
constexpr iterator insert_after(const_iterator position, InputIterator first, InputIterator last);
constexpr iterator insert_after(const_iterator position, initializer_list<T> il);
template<container-compatible-range<T> R>
constexpr iterator insert_range_after(const_iterator position, R&& rg);
constexpr iterator erase_after(const_iterator position);
constexpr iterator erase_after(const_iterator position, const_iterator last);
constexpr void swap(forward_list&)
noexcept(allocator_traits<Allocator>::is_always_equal::value);
constexpr void resize(size_type sz);
constexpr void resize(size_type sz, const value_type& c);
constexpr void clear() noexcept;
constexpr void splice_after(const_iterator position, forward_list& x);
constexpr void splice_after(const_iterator position, forward_list&& x);
constexpr void splice_after(const_iterator position, forward_list& x, const_iterator i);
constexpr void splice_after(const_iterator position, forward_list&& x, const_iterator i);
constexpr void splice_after(const_iterator position, forward_list& x,
const_iterator first, const_iterator last);
constexpr void splice_after(const_iterator position, forward_list&& x,
const_iterator first, const_iterator last);
constexpr size_type remove(const T& value);
template<class Predicate> constexpr size_type remove_if(Predicate pred);
constexpr size_type unique();
template<class BinaryPredicate> constexpr size_type unique(BinaryPredicate binary_pred);
constexpr void merge(forward_list& x);
constexpr void merge(forward_list&& x);
template<class Compare> constexpr void merge(forward_list& x, Compare comp);
template<class Compare> constexpr void merge(forward_list&& x, Compare comp);
constexpr void sort();
template<class Compare> constexpr void sort(Compare comp);
constexpr void reverse() noexcept;
};
template<class InputIterator, class Allocator = allocator<iter-value-type<InputIterator>>>
forward_list(InputIterator, InputIterator, Allocator = Allocator())
-> forward_list<iter-value-type<InputIterator>, Allocator>;
template<ranges::input_range R, class Allocator = allocator<ranges::range_value_t<R>>>
forward_list(from_range_t, R&&, Allocator = Allocator())
-> forward_list<ranges::range_value_t<R>, Allocator>;
}
T shall be complete before any member of the resulting specialization
of
forward_list is referenced
. constexpr explicit forward_list(const Allocator&);
Effects: Constructs an empty
forward_list object using the specified allocator
. constexpr explicit forward_list(size_type n, const Allocator& = Allocator());
Preconditions:
T is
Cpp17DefaultInsertable into
forward_list. Effects: Constructs a
forward_list object with
n
default-inserted elements using the specified allocator
. constexpr forward_list(size_type n, const T& value, const Allocator& = Allocator());
Preconditions:
T is
Cpp17CopyInsertable into
forward_list. Effects: Constructs a
forward_list object with
n copies of
value using the specified allocator
. template<class InputIterator>
constexpr forward_list(InputIterator first, InputIterator last, const Allocator& = Allocator());
Effects: Constructs a
forward_list object equal to the range [
first, last)
. Complexity: Linear in
distance(first, last). Effects: Constructs a
forward_list object
with the elements of the range
rg. Complexity: Linear in
ranges::distance(rg). constexpr iterator before_begin() noexcept;
constexpr const_iterator before_begin() const noexcept;
constexpr const_iterator cbefore_begin() const noexcept;
Effects:
cbefore_begin() is equivalent to
const_cast<forward_list const&>(*this).before_begin(). Returns: A non-dereferenceable iterator that, when incremented, is equal to the iterator
returned by
begin(). Remarks:
before_begin() == end() shall equal
false. constexpr reference front();
constexpr const_reference front() const;
None of the overloads of
insert_after shall affect the validity of iterators and
references, and
erase_after shall invalidate only iterators and references to
the erased elements
. If an exception is thrown during
insert_after there shall
be no effect
. Inserting
n elements into a
forward_list is linear in
n, and the number of calls to the copy or move constructor of
T is
exactly equal to
n. Erasing
n elements from a
forward_list is
linear in
n and the number of calls to the destructor of type
T is
exactly equal to
n.template<class... Args> constexpr reference emplace_front(Args&&... args);
Effects: Inserts an object of type
value_type constructed with
value_type(std::forward<Args>(args)...) at the beginning of the list
. constexpr void push_front(const T& x);
constexpr void push_front(T&& x);
Effects: Inserts a copy of
x at the beginning of the list
. Effects: Inserts a copy of each element of
rg at the beginning of the list
. [
Note 1:
The order of elements is not reversed
. —
end note]
constexpr void pop_front();
Effects: As if by
erase_after(before_begin()). constexpr iterator insert_after(const_iterator position, const T& x);
Preconditions:
T is
Cpp17CopyInsertable into
forward_list. position is
before_begin() or is a dereferenceable
iterator in the range [
begin(), end())
. Effects: Inserts a copy of
x after
position. Returns: An iterator pointing to the copy of
x. constexpr iterator insert_after(const_iterator position, T&& x);
Preconditions:
T is
Cpp17MoveInsertable into
forward_list. position is
before_begin() or is a dereferenceable
iterator in the range [
begin(), end())
. Effects: Inserts a copy of
x after
position. Returns: An iterator pointing to the copy of
x. constexpr iterator insert_after(const_iterator position, size_type n, const T& x);
Preconditions:
T is
Cpp17CopyInsertable into
forward_list. position is
before_begin() or is a dereferenceable
iterator in the range [
begin(), end())
. Effects: Inserts
n copies of
x after
position. Returns: An iterator pointing to the last inserted copy of
x, or
position if
n == 0 is
true. template<class InputIterator>
constexpr iterator insert_after(const_iterator position, InputIterator first, InputIterator last);
Preconditions:
T is
Cpp17EmplaceConstructible into
forward_list
from
*first. position is
before_begin() or is a dereferenceable
iterator in the range [
begin(), end())
. Neither
first nor
last are iterators in
*this.Effects: Inserts copies of elements in [
first, last) after
position. Returns: An iterator pointing to the last inserted element, or
position if
first == last is
true. Preconditions:
T is
Cpp17EmplaceConstructible into
forward_list
from
*ranges::begin(rg). position is
before_begin() or
is a dereferenceable iterator in the range [
begin(), end())
. rg and
*this do not overlap
. Effects: Inserts copies of elements in the range
rg after
position. Returns: An iterator pointing to the last inserted element,
or
position if
rg is empty
. constexpr iterator insert_after(const_iterator position, initializer_list<T> il);
Effects: Equivalent to: return insert_after(position, il.begin(), il.end());
template<class... Args>
constexpr iterator emplace_after(const_iterator position, Args&&... args);
Preconditions:
T is
Cpp17EmplaceConstructible into
forward_list
from
std::forward<Args>(args).... position is
before_begin() or is a dereferenceable
iterator in the range [
begin(), end())
. Effects: Inserts an object of type
value_type direct-non-list-initialized with
std::forward<Args>(args)... after
position. Returns: An iterator pointing to the new object
. constexpr iterator erase_after(const_iterator position);
Preconditions: The iterator following
position is dereferenceable
. Effects: Erases the element pointed to by the iterator following
position. Returns: An iterator pointing to the element following the one that was
erased, or
end() if no such element exists
. constexpr iterator erase_after(const_iterator position, const_iterator last);
Preconditions: All iterators in the range (
position, last) are dereferenceable
. Effects: Erases the elements in the range (
position, last)
. constexpr void resize(size_type sz);
Preconditions:
T is
Cpp17DefaultInsertable into
forward_list. Effects: If
sz < distance(begin(), end()), erases the last
distance(begin(),
end()) - sz elements from the list
. Otherwise, inserts
sz - distance(begin(), end()) default-inserted
elements at the end of the list
.constexpr void resize(size_type sz, const value_type& c);
Preconditions:
T is
Cpp17CopyInsertable into
forward_list. Effects: If
sz < distance(begin(), end()), erases the last
distance(begin(),
end()) - sz elements from the list
. Otherwise, inserts
sz - distance(begin(), end())
copies of
c at the end of the list
.constexpr void clear() noexcept;
Effects: Erases all elements in the range [
begin(), end())
. Remarks: Does not invalidate past-the-end iterators
. In this subclause,
arguments for a template parameter
named
Predicate or
BinaryPredicate
shall meet the corresponding requirements in
[algorithms.requirements]. The semantics of
i + n,
where
i is an iterator into the list and
n is an integer,
are the same as those of
next(i, n). The expression
i - n,
where
i is an iterator into the list and
n is an integer,
means an iterator
j such that
j + n == i is
true. For
merge and
sort,
the definitions and requirements in
[alg.sorting] apply
.constexpr void splice_after(const_iterator position, forward_list& x);
constexpr void splice_after(const_iterator position, forward_list&& x);
Preconditions:
position is
before_begin() or is a dereferenceable
iterator in the range [
begin(), end())
. get_allocator() == x.get_allocator() is
true. addressof(x) != this is
true. Effects: Inserts the contents of
x after
position, and
x becomes empty
. Pointers and references to the moved
elements of
x now refer to those same elements but as members of
*this. Iterators referring to the moved elements will continue to refer to their elements, but
they now behave as iterators into
*this, not into
x.Complexity: O(distance(x.begin(), x.end()))
constexpr void splice_after(const_iterator position, forward_list& x, const_iterator i);
constexpr void splice_after(const_iterator position, forward_list&& x, const_iterator i);
Preconditions:
position is
before_begin() or is a dereferenceable
iterator in the range [
begin(), end())
. The iterator following
i is a dereferenceable iterator in
x. get_allocator() == x.get_allocator() is
true. Effects: Inserts the element following
i into
*this, following
position, and removes it from
x. The result is unchanged if
position == i or
position == ++i. Pointers
and references to
*++i continue to refer to the same element but as a member of
*this. Iterators to
*++i continue to refer to
the same element, but now behave as iterators into
*this, not into
x.constexpr void splice_after(const_iterator position, forward_list& x,
const_iterator first, const_iterator last);
constexpr void splice_after(const_iterator position, forward_list&& x,
const_iterator first, const_iterator last);
Preconditions:
position is
before_begin() or is a
dereferenceable iterator in the range [
begin(), end())
. (
first, last) is a
valid range in
x, and all iterators in the range (
first, last) are
dereferenceable
. position is not an iterator in the range (
first, last)
. get_allocator() == x.get_allocator() is
true. Effects: Inserts elements in the range (
first, last) after
position and
removes the elements from
x. Pointers and references to the moved elements of
x now refer to those same elements but as members of
*this. Iterators
referring to the moved elements will continue to refer to their elements, but they now
behave as iterators into
*this, not into
x.Complexity: O(distance(first, last))
constexpr size_type remove(const T& value);
template<class Predicate> constexpr size_type remove_if(Predicate pred);
Effects: Erases all the elements in the list referred to by a list iterator
i for
which the following conditions hold:
*i == value (for
remove()),
pred(*i) is
true (for
remove_if())
. Invalidates only the iterators and references to the erased elements
.Returns: The number of elements erased
. Throws: Nothing unless an exception is thrown by the equality comparison or the
predicate
. Complexity: Exactly
distance(begin(), end()) applications of the corresponding
predicate
. constexpr size_type unique();
template<class BinaryPredicate> constexpr size_type unique(BinaryPredicate binary_pred);
Let
binary_pred be
equal_to<>{} for the first overload
.Preconditions:
binary_pred is an equivalence relation
. Effects: Erases all but the first element from every consecutive
group of equivalent elements
. That is, for a nonempty list, erases all elements referred to
by the iterator
i in the range [
begin() + 1, end())
for which
binary_pred(*i, *(i - 1)) is
true. Invalidates only the iterators and references to the erased elements
.Returns: The number of elements erased
. Throws: Nothing unless an exception is thrown by the predicate
. Complexity: If
empty() is
false,
exactly
distance(begin(), end()) - 1 applications of
the corresponding predicate,
otherwise no applications of the predicate
. constexpr void merge(forward_list& x);
constexpr void merge(forward_list&& x);
template<class Compare> constexpr void merge(forward_list& x, Compare comp);
template<class Compare> constexpr void merge(forward_list&& x, Compare comp);
Let
comp be
less<> for the first two overloads
.Preconditions:
*this and
x are both sorted
with respect to the comparator
comp, and
get_allocator() == x.get_allocator() is
true. Effects: If
addressof(x) == this, there are no effects
. Otherwise, merges
the two sorted ranges [
begin(), end()) and [
x.begin(), x.end())
. The result is a range
that is sorted with respect to the comparator
comp. Pointers and references to the moved elements of
x now refer to those same elements
but as members of
*this. Iterators referring to the moved elements will continue to
refer to their elements, but they now behave as iterators into
*this, not into
x.Complexity: At most
distance(begin(),
end()) + distance(x.begin(), x.end()) - 1 comparisons
if
addressof(x) != this; otherwise, no comparisons are performed
. If
addressof(x) != this,
x is empty after the merge
. No elements are copied by this operation
. If an exception is thrown other than by a comparison, there are no effects
. constexpr void sort();
template<class Compare> constexpr void sort(Compare comp);
Effects: Sorts the list according to the
operator< or the
comp function object
. If an exception is thrown, the order of the elements in
*this is unspecified
. Does not affect the validity of iterators and references
.Complexity: Approximately
NlogN comparisons, where
N is
distance(begin(), end()). constexpr void reverse() noexcept;
Effects: Reverses the order of the elements in the list
. Does not affect the validity of iterators and references
.template<class T, class Allocator, class U = T>
constexpr typename forward_list<T, Allocator>::size_type
erase(forward_list<T, Allocator>& c, const U& value);
Effects: Equivalent to: return erase_if(c, [&](auto& elem) { return elem == value; });
template<class T, class Allocator, class Predicate>
constexpr typename forward_list<T, Allocator>::size_type
erase_if(forward_list<T, Allocator>& c, Predicate pred);
Effects: Equivalent to: return c.remove_if(pred);
A
list
is a sequence container that supports
bidirectional iterators and allows constant time insert and erase
operations anywhere within the sequence, with storage management handled
automatically
. Unlike
vectors and
deques,
fast random access to list elements is not supported, but many
algorithms only need sequential access anyway
. The exceptions are the
operator[]
and
at
member functions, which are not provided
.
Descriptions are provided here only for operations on
list
that are not described in one of these tables
or for operations where there is additional semantic information
.
namespace std {
template<class T, class Allocator = allocator<T>>
class list {
public:
using value_type = T;
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;
using difference_type = implementation-defined;
using iterator = implementation-defined;
using const_iterator = implementation-defined;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
constexpr list() : list(Allocator()) { }
constexpr explicit list(const Allocator&);
constexpr explicit list(size_type n, const Allocator& = Allocator());
constexpr list(size_type n, const T& value, const Allocator& = Allocator());
template<class InputIterator>
constexpr list(InputIterator first, InputIterator last, const Allocator& = Allocator());
template<container-compatible-range<T> R>
constexpr list(from_range_t, R&& rg, const Allocator& = Allocator());
constexpr list(const list& x);
constexpr list(list&& x);
constexpr list(const list&, const type_identity_t<Allocator>&);
constexpr list(list&&, const type_identity_t<Allocator>&);
constexpr list(initializer_list<T>, const Allocator& = Allocator());
constexpr ~list();
constexpr list& operator=(const list& x);
constexpr list& operator=(list&& x)
noexcept(allocator_traits<Allocator>::is_always_equal::value);
constexpr list& operator=(initializer_list<T>);
template<class InputIterator>
constexpr void assign(InputIterator first, InputIterator last);
template<container-compatible-range<T> R>
constexpr void assign_range(R&& rg);
constexpr void assign(size_type n, const T& t);
constexpr void assign(initializer_list<T>);
constexpr allocator_type get_allocator() const noexcept;
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
constexpr reverse_iterator rbegin() noexcept;
constexpr const_reverse_iterator rbegin() const noexcept;
constexpr reverse_iterator rend() noexcept;
constexpr const_reverse_iterator rend() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator cend() const noexcept;
constexpr const_reverse_iterator crbegin() const noexcept;
constexpr const_reverse_iterator crend() const noexcept;
constexpr bool empty() const noexcept;
constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;
constexpr void resize(size_type sz);
constexpr void resize(size_type sz, const T& c);
constexpr reference front();
constexpr const_reference front() const;
constexpr reference back();
constexpr const_reference back() const;
template<class... Args> constexpr reference emplace_front(Args&&... args);
template<class... Args> constexpr reference emplace_back(Args&&... args);
constexpr void push_front(const T& x);
constexpr void push_front(T&& x);
template<container-compatible-range<T> R>
constexpr void prepend_range(R&& rg);
constexpr void pop_front();
constexpr void push_back(const T& x);
constexpr void push_back(T&& x);
template<container-compatible-range<T> R>
constexpr void append_range(R&& rg);
constexpr void pop_back();
template<class... Args> iterator emplace(const_iterator position, Args&&... args);
constexpr iterator insert(const_iterator position, const T& x);
constexpr iterator insert(const_iterator position, T&& x);
constexpr iterator insert(const_iterator position, size_type n, const T& x);
template<class InputIterator>
constexpr iterator insert(const_iterator position, InputIterator first, InputIterator last);
template<container-compatible-range<T> R>
constexpr iterator insert_range(const_iterator position, R&& rg);
constexpr iterator insert(const_iterator position, initializer_list<T> il);
constexpr iterator erase(const_iterator position);
constexpr iterator erase(const_iterator position, const_iterator last);
constexpr void swap(list&) noexcept(allocator_traits<Allocator>::is_always_equal::value);
constexpr void clear() noexcept;
constexpr void splice(const_iterator position, list& x);
constexpr void splice(const_iterator position, list&& x);
constexpr void splice(const_iterator position, list& x, const_iterator i);
constexpr void splice(const_iterator position, list&& x, const_iterator i);
constexpr void splice(const_iterator position, list& x, const_iterator first, const_iterator last);
constexpr void splice(const_iterator position, list&& x, const_iterator first, const_iterator last);
constexpr size_type remove(const T& value);
template<class Predicate> constexpr size_type remove_if(Predicate pred);
constexpr size_type unique();
template<class BinaryPredicate>
constexpr size_type unique(BinaryPredicate binary_pred);
constexpr void merge(list& x);
constexpr void merge(list&& x);
template<class Compare> constexpr void merge(list& x, Compare comp);
template<class Compare> constexpr void merge(list&& x, Compare comp);
constexpr void sort();
template<class Compare> constexpr void sort(Compare comp);
constexpr void reverse() noexcept;
};
template<class InputIterator, class Allocator = allocator<iter-value-type<InputIterator>>>
list(InputIterator, InputIterator, Allocator = Allocator())
-> list<iter-value-type<InputIterator>, Allocator>;
template<ranges::input_range R, class Allocator = allocator<ranges::range_value_t<R>>>
list(from_range_t, R&&, Allocator = Allocator())
-> list<ranges::range_value_t<R>, Allocator>;
}
T shall be complete before any member of the resulting specialization
of
list is referenced
. constexpr explicit list(const Allocator&);
Effects: Constructs an empty list, using the specified allocator
. constexpr explicit list(size_type n, const Allocator& = Allocator());
Preconditions:
T is
Cpp17DefaultInsertable into
list. Effects: Constructs a
list with
n default-inserted elements using the specified allocator
. constexpr list(size_type n, const T& value, const Allocator& = Allocator());
Preconditions:
T is
Cpp17CopyInsertable into
list. Effects: Constructs a
list
with
n
copies of
value,
using the specified allocator
. template<class InputIterator>
constexpr list(InputIterator first, InputIterator last, const Allocator& = Allocator());
Effects: Constructs a
list
equal to the range
[
first, last)
. Complexity: Linear in
distance(first, last). Effects: Constructs a
list object with the elements of the range
rg. Complexity: Linear in
ranges::distance(rg). constexpr void resize(size_type sz);
Preconditions:
T is
Cpp17DefaultInsertable into
list. Effects: If
size() < sz,
appends
sz - size() default-inserted elements to the
sequence
. If sz <= size(), equivalent to:
list<T>::iterator it = begin();
advance(it, sz);
erase(it, end());
constexpr void resize(size_type sz, const T& c);
Preconditions:
T is
Cpp17CopyInsertable into
list. Effects: As if by:
if (sz > size())
insert(end(), sz-size(), c);
else if (sz < size()) {
iterator i = begin();
advance(i, sz);
erase(i, end());
}
else
;
constexpr iterator insert(const_iterator position, const T& x);
constexpr iterator insert(const_iterator position, T&& x);
constexpr iterator insert(const_iterator position, size_type n, const T& x);
template<class InputIterator>
constexpr iterator insert(const_iterator position, InputIterator first,
InputIterator last);
template<container-compatible-range<T> R>
constexpr iterator insert_range(const_iterator position, R&& rg);
constexpr iterator insert(const_iterator position, initializer_list<T>);
template<class... Args> constexpr reference emplace_front(Args&&... args);
template<class... Args> constexpr reference emplace_back(Args&&... args);
template<class... Args> constexpr iterator emplace(const_iterator position, Args&&... args);
constexpr void push_front(const T& x);
constexpr void push_front(T&& x);
template<container-compatible-range<T> R>
constexpr void prepend_range(R&& rg);
constexpr void push_back(const T& x);
constexpr void push_back(T&& x);
template<container-compatible-range<T> R>
constexpr void append_range(R&& rg);
Complexity: Insertion of a single element into a list takes constant time and
exactly one call to a constructor of
T. Insertion of multiple elements into a list is linear in the
number of elements inserted, and the number of calls to the copy
constructor or move constructor of
T is exactly equal
to the number of elements inserted
.Remarks: Does not affect the validity of iterators and references
. If an exception is thrown there are no effects
.constexpr iterator erase(const_iterator position);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void pop_front();
constexpr void pop_back();
constexpr void clear() noexcept;
Effects: Invalidates only the iterators and references to the erased elements
. Complexity: Erasing a single element is a constant time operation with a single call to the destructor of
T. Erasing a range in a list is linear time in the
size of the range and the number of calls to the destructor of type
T
is exactly equal to the size of the range
.Since lists allow fast insertion and erasing from the middle of a list, certain
operations are provided specifically for them
.
In this subclause,
arguments for a template parameter
named
Predicate or
BinaryPredicate
shall meet the corresponding requirements in
[algorithms.requirements]. The semantics of
i + n and
i - n,
where
i is an iterator into the list and
n is an integer,
are the same as those of
next(i, n) and
prev(i, n),
respectively
. For
merge and
sort,
the definitions and requirements in
[alg.sorting] apply
.list provides three splice operations that destructively move elements from one list to
another
. The behavior of splice operations is undefined if
get_allocator() !=
x.get_allocator().constexpr void splice(const_iterator position, list& x);
constexpr void splice(const_iterator position, list&& x);
Preconditions:
addressof(x) != this is
true. Effects: Inserts the contents of
x
before
position
and
x
becomes empty
. Pointers and references to the moved elements of
x
now refer to those same elements but as members of
*this. Iterators referring to the moved elements will continue to refer to their
elements, but they now behave as iterators into
*this,
not into
x.Complexity: Constant time
. constexpr void splice(const_iterator position, list& x, const_iterator i);
constexpr void splice(const_iterator position, list&& x, const_iterator i);
Preconditions:
i is a valid dereferenceable iterator of
x. Effects: Inserts an element pointed to by
i
from list
x
before
position and removes the element from
x. The result is unchanged if
position == i
or
position == ++i. Pointers and references to
*i
continue to refer to this same element but as a member of
*this. Iterators
to
*i
(including
i
itself) continue to refer to the same element, but now behave as iterators into
*this,
not into
x.Complexity: Constant time
. constexpr void splice(const_iterator position, list& x, const_iterator first,
const_iterator last);
constexpr void splice(const_iterator position, list&& x, const_iterator first,
const_iterator last);
Preconditions:
[first, last) is a valid range in
x. position is not an iterator in the range [
first, last)
. Effects: Inserts elements in the range
[
first, last)
before
position
and removes the elements from
x. Pointers and references to the moved elements of
x
now refer to those same elements but as members of
*this. Iterators referring to the moved elements will continue to refer to their
elements, but they now behave as iterators into
*this,
not into
x.Complexity: Constant time if
addressof(x) == this;
otherwise, linear time
. constexpr size_type remove(const T& value);
template<class Predicate> constexpr size_type remove_if(Predicate pred);
Effects: Erases all the elements in the list referred to by a list iterator
i for which the
following conditions hold:
*i == value,
pred(*i) != false. Invalidates only the iterators and references to the erased elements
.Returns: The number of elements erased
. Throws: Nothing unless an exception is thrown by
*i == value
or
pred(*i) != false. Complexity: Exactly
size()
applications of the corresponding predicate
. constexpr size_type unique();
template<class BinaryPredicate> constexpr size_type unique(BinaryPredicate binary_pred);
Let
binary_pred be
equal_to<>{} for the first overload
.Preconditions:
binary_pred is an equivalence relation
. Effects: Erases all but the first element from every
consecutive group of equivalent elements
. That is, for a nonempty list, erases all elements referred to
by the iterator
i in the range [
begin() + 1, end())
for which
binary_pred(*i, *(i - 1)) is
true. Invalidates only the iterators and references to the erased elements
.Returns: The number of elements erased
. Throws: Nothing unless an exception is thrown by the predicate
. Complexity: If
empty() is
false,
exactly
size() - 1 applications of the corresponding predicate,
otherwise no applications of the predicate
. constexpr void merge(list& x);
constexpr void merge(list&& x);
template<class Compare> constexpr void merge(list& x, Compare comp);
template<class Compare> constexpr void merge(list&& x, Compare comp);
Let
comp be
less<> for the first two overloads
.Preconditions:
*this and
x are both sorted
with respect to the comparator
comp, and
get_allocator() == x.get_allocator() is
true. Effects: If
addressof(x) == this, there are no effects
. Otherwise, merges
the two sorted ranges [
begin(), end()) and [
x.begin(), x.end())
. The result is a range
that is sorted with respect to the comparator
comp. Pointers and references to the moved elements of
x now refer to those same elements
but as members of
*this. Iterators referring to the moved elements will continue to
refer to their elements, but they now behave as iterators into
*this, not into
x.Complexity: At most
size() + x.size() - 1 comparisons
if
addressof(x) != this;
otherwise, no comparisons are performed
. If
addressof(x) != this,
x is empty after the merge
. No elements are copied by this operation
. If an exception is thrown other than by a comparison there are no effects
. constexpr void reverse() noexcept;
Effects: Reverses the order of the elements in the list
. Does not affect the validity of iterators and references
.constexpr void sort();
template<class Compare> constexpr void sort(Compare comp);
Effects: Sorts the list according to the
operator< or a
Compare function object
. If an exception is thrown,
the order of the elements in
*this is unspecified
. Does not affect the validity of iterators and references
.Complexity: Approximately
NlogN
comparisons, where
N == size(). template<class T, class Allocator, class U = T>
constexpr typename list<T, Allocator>::size_type
erase(list<T, Allocator>& c, const U& value);
Effects: Equivalent to: return erase_if(c, [&](auto& elem) { return elem == value; });
template<class T, class Allocator, class Predicate>
constexpr typename list<T, Allocator>::size_type
erase_if(list<T, Allocator>& c, Predicate pred);
Effects: Equivalent to: return c.remove_if(pred);
The header
defines the class templates
map and
multimap;
the header
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;
template<class InputIterator>
using iter-key-type = remove_const_t<
tuple_element_t<0, iter-value-type<InputIterator>>>;
template<class InputIterator>
using iter-mapped-type =
tuple_element_t<1, iter-value-type<InputIterator>>;
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>>>;
template<ranges::input_range Range>
using range-key-type =
remove_const_t<typename ranges::range_value_t<Range>::first_type>;
template<ranges::input_range Range>
using range-mapped-type = typename ranges::range_value_t<Range>::second_type;
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>;
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
. 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:
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;
using difference_type = implementation-defined;
using iterator = implementation-defined;
using const_iterator = implementation-defined;
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 {
friend class map;
protected:
Compare comp;
constexpr value_compare(Compare c) : comp(c) {}
public:
constexpr bool operator()(const value_type& x, const value_type& y) const {
return comp(x.first, y.first);
}
};
constexpr map() : map(Compare()) { }
constexpr explicit map(const Compare& comp, const Allocator& = Allocator());
template<class InputIterator>
constexpr map(InputIterator first, InputIterator last,
const Compare& comp = Compare(), const Allocator& = Allocator());
template<container-compatible-range<value_type> R>
constexpr map(from_range_t, R&& rg, const Compare& comp = Compare(), const Allocator& = Allocator());
constexpr map(const map& x);
constexpr map(map&& x);
explicit map(const Allocator&);
constexpr map(const map&, const type_identity_t<Allocator>&);
constexpr map(map&&, const type_identity_t<Allocator>&);
constexpr map(initializer_list<value_type>,
const Compare& = Compare(),
const Allocator& = Allocator());
template<class InputIterator>
constexpr map(InputIterator first, InputIterator last, const Allocator& a)
: map(first, last, Compare(), a) { }
template<container-compatible-range<value_type> R>
constexpr map(from_range_t, R&& rg, const Allocator& a))
: map(from_range, std::forward<R>(rg), Compare(), a) { }
constexpr map(initializer_list<value_type> il, const Allocator& a)
: map(il, Compare(), a) { }
constexpr ~map();
constexpr map& operator=(const map& x);
constexpr map& operator=(map&& x)
noexcept(allocator_traits<Allocator>::is_always_equal::value &&
is_nothrow_move_assignable_v<Compare>);
constexpr map& operator=(initializer_list<value_type>);
constexpr allocator_type get_allocator() const noexcept;
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
constexpr reverse_iterator rbegin() noexcept;
constexpr const_reverse_iterator rbegin() const noexcept;
constexpr reverse_iterator rend() noexcept;
constexpr const_reverse_iterator rend() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator cend() const noexcept;
constexpr const_reverse_iterator crbegin() const noexcept;
constexpr const_reverse_iterator crend() const noexcept;
constexpr bool empty() const noexcept;
constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;
constexpr mapped_type& operator[](const key_type& x);
constexpr mapped_type& operator[](key_type&& x);
template<class K> constexpr mapped_type& operator[](K&& x);
constexpr mapped_type& at(const key_type& x);
constexpr const mapped_type& at(const key_type& x) const;
template<class K> constexpr mapped_type& at(const K& x);
template<class K> constexpr const mapped_type& at(const K& x) const;
template<class... Args> constexpr pair<iterator, bool> emplace(Args&&... args);
template<class... Args> constexpr iterator emplace_hint(const_iterator position, Args&&... args);
pair<iterator, bool> constexpr insert(const value_type& x);
pair<iterator, bool> constexpr insert(value_type&& x);
template<class P> constexpr pair<iterator, bool> insert(P&& x);
constexpr iterator insert(const_iterator position, const value_type& x);
constexpr iterator insert(const_iterator position, value_type&& x);
template<class P>
constexpr iterator insert(const_iterator position, P&&);
template<class InputIterator>
constexpr void insert(InputIterator first, InputIterator last);
template<container-compatible-range<value_type> R>
constexpr void insert_range(R&& rg);
constexpr void insert(initializer_list<value_type>);
constexpr node_type extract(const_iterator position);
constexpr node_type extract(const key_type& x);
template<class K> constexpr node_type extract(K&& x);
constexpr insert_return_type insert(node_type&& nh);
constexpr iterator insert(const_iterator hint, node_type&& nh);
template<class... Args>
constexpr pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
template<class... Args>
constexpr pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
template<class K, class... Args>
constexpr pair<iterator, bool> try_emplace(K&& k, Args&&... args);
template<class... Args>
constexpr iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);
template<class... Args>
constexpr iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);
template<class K, class... Args>
constexpr iterator try_emplace(const_iterator hint, K&& k, Args&&... args);
template<class M>
constexpr pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);
template<class M>
constexpr pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);
template<class K, class M>
constexpr pair<iterator, bool> insert_or_assign(K&& k, M&& obj);
template<class M>
constexpr iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);
template<class M>
constexpr iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);
template<class K, class M>
constexpr iterator insert_or_assign(const_iterator hint, K&& k, M&& obj);
constexpr iterator erase(iterator position);
constexpr iterator erase(const_iterator position);
constexpr size_type erase(const key_type& x);
template<class K> constexpr size_type erase(K&& x);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void swap(map&)
noexcept(allocator_traits<Allocator>::is_always_equal::value &&
is_nothrow_swappable_v<Compare>);
constexpr void clear() noexcept;
template<class C2>
constexpr void merge(map<Key, T, C2, Allocator>& source);
template<class C2>
constexpr void merge(map<Key, T, C2, Allocator>&& source);
template<class C2>
constexpr void merge(multimap<Key, T, C2, Allocator>& source);
template<class C2>
constexpr void merge(multimap<Key, T, C2, Allocator>&& source);
constexpr key_compare key_comp() const;
constexpr value_compare value_comp() const;
constexpr iterator find(const key_type& x);
constexpr const_iterator find(const key_type& x) const;
template<class K> constexpr iterator find(const K& x);
template<class K> constexpr const_iterator find(const K& x) const;
constexpr size_type count(const key_type& x) const;
template<class K> constexpr size_type count(const K& x) const;
constexpr bool contains(const key_type& x) const;
template<class K> constexpr bool contains(const K& x) const;
constexpr iterator lower_bound(const key_type& x);
constexpr const_iterator lower_bound(const key_type& x) const;
template<class K> constexpr iterator lower_bound(const K& x);
template<class K> constexpr const_iterator lower_bound(const K& x) const;
constexpr iterator upper_bound(const key_type& x);
constexpr const_iterator upper_bound(const key_type& x) const;
template<class K> constexpr iterator upper_bound(const K& x);
template<class K> constexpr const_iterator upper_bound(const K& x) const;
constexpr pair<iterator, iterator> equal_range(const key_type& x);
constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
template<class K>
constexpr pair<iterator, iterator> equal_range(const K& x);
template<class K>
constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const;
};
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>;
}
constexpr explicit map(const Compare& comp, const Allocator& = Allocator());
Effects: Constructs an empty
map
using the specified comparison object and allocator
. template<class InputIterator>
constexpr 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
NlogN, where
N
is
last - first. template<container-compatible-range<value_type> R>
constexpr 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
NlogN, where
N is
ranges::distance(rg). constexpr mapped_type& operator[](const key_type& x);
Effects: Equivalent to: return try_emplace(x).first->second;
constexpr mapped_type& operator[](key_type&& x);
Effects: Equivalent to: return try_emplace(std::move(x)).first->second;
template<class K> constexpr 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;
constexpr mapped_type& at(const key_type& x);
constexpr 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
. template<class K> constexpr mapped_type& at(const K& x);
template<class K> constexpr 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. template<class P>
constexpr pair<iterator, bool> insert(P&& x);
template<class P>
constexpr 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>
constexpr pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
template<class... Args>
constexpr 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>
constexpr pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
template<class... Args>
constexpr 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>
constexpr pair<iterator, bool> try_emplace(K&& k, Args&&... args);
template<class K, class... Args>
constexpr 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
. 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>
constexpr pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);
template<class M>
constexpr 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>
constexpr pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);
template<class M>
constexpr 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>
constexpr pair<iterator, bool> insert_or_assign(K&& k, M&& obj);
template<class K, class M>
constexpr 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
. 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 Key, class T, class Compare, class Allocator, class Predicate>
constexpr 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();
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
. 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:
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;
using difference_type = implementation-defined;
using iterator = implementation-defined;
using const_iterator = implementation-defined;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using node_type = unspecified;
class value_compare {
friend class multimap;
protected:
Compare comp;
constexpr value_compare(Compare c) : comp(c) { }
public:
constexpr bool operator()(const value_type& x, const value_type& y) const {
return comp(x.first, y.first);
}
};
constexpr multimap() : multimap(Compare()) { }
constexpr explicit multimap(const Compare& comp, const Allocator& = Allocator());
template<class InputIterator>
constexpr multimap(InputIterator first, InputIterator last,
const Compare& comp = Compare(),
const Allocator& = Allocator());
template<container-compatible-range<value_type> R>
constexpr multimap(from_range_t, R&& rg,
const Compare& comp = Compare(), const Allocator& = Allocator());
constexpr multimap(const multimap& x);
constexpr multimap(multimap&& x);
constexpr explicit multimap(const Allocator&);
constexpr multimap(const multimap&, const type_identity_t<Allocator>&);
constexpr multimap(multimap&&, const type_identity_t<Allocator>&);
constexpr multimap(initializer_list<value_type>,
const Compare& = Compare(),
const Allocator& = Allocator());
template<class InputIterator>
constexpr multimap(InputIterator first, InputIterator last, const Allocator& a)
: multimap(first, last, Compare(), a) { }
template<container-compatible-range<value_type> R>
constexpr multimap(from_range_t, R&& rg, const Allocator& a))
: multimap(from_range, std::forward<R>(rg), Compare(), a) { }
constexpr multimap(initializer_list<value_type> il, const Allocator& a)
: multimap(il, Compare(), a) { }
constexpr ~multimap();
constexpr multimap& operator=(const multimap& x);
constexpr multimap& operator=(multimap&& x)
noexcept(allocator_traits<Allocator>::is_always_equal::value &&
is_nothrow_move_assignable_v<Compare>);
constexpr multimap& operator=(initializer_list<value_type>);
constexpr allocator_type get_allocator() const noexcept;
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
constexpr reverse_iterator rbegin() noexcept;
constexpr const_reverse_iterator rbegin() const noexcept;
constexpr reverse_iterator rend() noexcept;
constexpr const_reverse_iterator rend() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator cend() const noexcept;
constexpr const_reverse_iterator crbegin() const noexcept;
constexpr const_reverse_iterator crend() const noexcept;
constexpr bool empty() const noexcept;
constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;
template<class... Args> constexpr iterator emplace(Args&&... args);
template<class... Args> constexpr iterator emplace_hint(const_iterator position, Args&&... args);
constexpr iterator insert(const value_type& x);
constexpr iterator insert(value_type&& x);
template<class P> constexpr iterator insert(P&& x);
constexpr iterator insert(const_iterator position, const value_type& x);
constexpr iterator insert(const_iterator position, value_type&& x);
template<class P> constexpr iterator insert(const_iterator position, P&& x);
template<class InputIterator>
constexpr void insert(InputIterator first, InputIterator last);
template<container-compatible-range<value_type> R>
constexpr void insert_range(R&& rg);
constexpr void insert(initializer_list<value_type>);
constexpr node_type extract(const_iterator position);
constexpr node_type extract(const key_type& x);
template<class K> constexpr node_type extract(K&& x);
constexpr iterator insert(node_type&& nh);
constexpr iterator insert(const_iterator hint, node_type&& nh);
constexpr iterator erase(iterator position);
constexpr iterator erase(const_iterator position);
constexpr size_type erase(const key_type& x);
template<class K> constexpr size_type erase(K&& x);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void swap(multimap&)
noexcept(allocator_traits<Allocator>::is_always_equal::value &&
is_nothrow_swappable_v<Compare>);
constexpr void clear() noexcept;
template<class C2>
constexpr void merge(multimap<Key, T, C2, Allocator>& source);
template<class C2>
constexpr void merge(multimap<Key, T, C2, Allocator>&& source);
template<class C2>
constexpr void merge(map<Key, T, C2, Allocator>& source);
template<class C2>
constexpr void merge(map<Key, T, C2, Allocator>&& source);
constexpr key_compare key_comp() const;
constexpr value_compare value_comp() const;
constexpr iterator find(const key_type& x);
constexpr const_iterator find(const key_type& x) const;
template<class K> constexpr iterator find(const K& x);
template<class K> constexpr const_iterator find(const K& x) const;
constexpr size_type count(const key_type& x) const;
template<class K> constexpr size_type count(const K& x) const;
constexpr bool contains(const key_type& x) const;
template<class K> constexpr bool contains(const K& x) const;
constexpr iterator lower_bound(const key_type& x);
constexpr const_iterator lower_bound(const key_type& x) const;
template<class K> constexpr iterator lower_bound(const K& x);
template<class K> constexpr const_iterator lower_bound(const K& x) const;
constexpr iterator upper_bound(const key_type& x);
constexpr const_iterator upper_bound(const key_type& x) const;
template<class K> constexpr iterator upper_bound(const K& x);
template<class K> constexpr const_iterator upper_bound(const K& x) const;
constexpr pair<iterator, iterator> equal_range(const key_type& x);
constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
template<class K>
constexpr pair<iterator, iterator> equal_range(const K& x);
template<class K>
constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const;
};
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>;
}
constexpr explicit multimap(const Compare& comp, const Allocator& = Allocator());
Effects: Constructs an empty
multimap
using the specified comparison object and allocator
. template<class InputIterator>
constexpr 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
NlogN,
where
N is
last - first. template<container-compatible-range<value_type> R>
constexpr 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
NlogN, where
N is
ranges::distance(rg). template<class P> constexpr iterator insert(P&& x);
template<class P> constexpr 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 Key, class T, class Compare, class Allocator, class Predicate>
constexpr 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();
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
. 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:
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;
using difference_type = implementation-defined;
using iterator = implementation-defined;
using const_iterator = implementation-defined;
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>;
constexpr set() : set(Compare()) { }
constexpr explicit set(const Compare& comp, const Allocator& = Allocator());
template<class InputIterator>
constexpr set(InputIterator first, InputIterator last,
const Compare& comp = Compare(), const Allocator& = Allocator());
template<container-compatible-range<value_type> R>
constexpr set(from_range_t, R&& rg, const Compare& comp = Compare(), const Allocator& = Allocator());
constexpr set(const set& x);
constexpr set(set&& x);
constexpr explicit set(const Allocator&);
constexpr set(const set&, const type_identity_t<Allocator>&);
constexpr set(set&&, const type_identity_t<Allocator>&);
constexpr set(initializer_list<value_type>, const Compare& = Compare(),
const Allocator& = Allocator());
template<class InputIterator>
constexpr set(InputIterator first, InputIterator last, const Allocator& a)
: set(first, last, Compare(), a) { }
template<container-compatible-range<value_type> R>
constexpr set(from_range_t, R&& rg, const Allocator& a))
: set(from_range, std::forward<R>(rg), Compare(), a) { }
constexpr set(initializer_list<value_type> il, const Allocator& a)
: set(il, Compare(), a) { }
constexpr ~set();
constexpr set& operator=(const set& x);
constexpr set& operator=(set&& x)
noexcept(allocator_traits<Allocator>::is_always_equal::value &&
is_nothrow_move_assignable_v<Compare>);
constexpr set& operator=(initializer_list<value_type>);
constexpr allocator_type get_allocator() const noexcept;
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
constexpr reverse_iterator rbegin() noexcept;
constexpr const_reverse_iterator rbegin() const noexcept;
constexpr reverse_iterator rend() noexcept;
constexpr const_reverse_iterator rend() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator cend() const noexcept;
constexpr const_reverse_iterator crbegin() const noexcept;
constexpr const_reverse_iterator crend() const noexcept;
constexpr bool empty() const noexcept;
constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;
template<class... Args> constexpr pair<iterator, bool> emplace(Args&&... args);
template<class... Args> constexpr iterator emplace_hint(const_iterator position, Args&&... args);
constexpr pair<iterator,bool> insert(const value_type& x);
constexpr pair<iterator,bool> insert(value_type&& x);
template<class K> constexpr pair<iterator, bool> insert(K&& x);
constexpr iterator insert(const_iterator position, const value_type& x);
constexpr iterator insert(const_iterator position, value_type&& x);
template<class K> constexpr iterator insert(const_iterator position, K&& x);
template<class InputIterator>
constexpr void insert(InputIterator first, InputIterator last);
template<container-compatible-range<value_type> R>
constexpr void insert_range(R&& rg);
constexpr void insert(initializer_list<value_type>);
constexpr node_type extract(const_iterator position);
constexpr node_type extract(const key_type& x);
template<class K> constexpr node_type extract(K&& x);
constexpr insert_return_type insert(node_type&& nh);
constexpr iterator insert(const_iterator hint, node_type&& nh);
constexpr iterator erase(iterator position)
requires (!same_as<iterator, const_iterator>);
constexpr iterator erase(const_iterator position);
constexpr size_type erase(const key_type& x);
template<class K> constexpr size_type erase(K&& x);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void swap(set&)
noexcept(allocator_traits<Allocator>::is_always_equal::value &&
is_nothrow_swappable_v<Compare>);
constexpr void clear() noexcept;
template<class C2>
constexpr void merge(set<Key, C2, Allocator>& source);
template<class C2>
constexpr void merge(set<Key, C2, Allocator>&& source);
template<class C2>
constexpr void merge(multiset<Key, C2, Allocator>& source);
template<class C2>
constexpr void merge(multiset<Key, C2, Allocator>&& source);
constexpr key_compare key_comp() const;
constexpr value_compare value_comp() const;
constexpr iterator find(const key_type& x);
constexpr const_iterator find(const key_type& x) const;
template<class K> constexpr iterator find(const K& x);
template<class K> constexpr const_iterator find(const K& x) const;
constexpr size_type count(const key_type& x) const;
template<class K> constexpr size_type count(const K& x) const;
constexpr bool contains(const key_type& x) const;
template<class K> constexpr bool contains(const K& x) const;
constexpr iterator lower_bound(const key_type& x);
constexpr const_iterator lower_bound(const key_type& x) const;
template<class K> constexpr iterator lower_bound(const K& x);
template<class K> constexpr const_iterator lower_bound(const K& x) const;
constexpr iterator upper_bound(const key_type& x);
constexpr const_iterator upper_bound(const key_type& x) const;
template<class K> constexpr iterator upper_bound(const K& x);
template<class K> constexpr const_iterator upper_bound(const K& x) const;
constexpr pair<iterator, iterator> equal_range(const key_type& x);
constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
template<class K>
constexpr pair<iterator, iterator> equal_range(const K& x);
template<class K>
constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const;
};
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>;
}
constexpr explicit set(const Compare& comp, const Allocator& = Allocator());
Effects: Constructs an empty
set using the specified comparison object and allocator
. template<class InputIterator>
constexpr 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
NlogN,
where
N is
last - first. template<container-compatible-range<value_type> R>
constexpr 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
NlogN, where
N is
ranges::distance(rg). template<class Key, class Compare, class Allocator, class Predicate>
constexpr 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();
template<class K> constexpr pair<iterator, bool> insert(K&& x);
template<class K> constexpr 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
. 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.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
. 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:
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;
using difference_type = implementation-defined;
using iterator = implementation-defined;
using const_iterator = implementation-defined;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using node_type = unspecified;
constexpr multiset() : multiset(Compare()) { }
constexpr explicit multiset(const Compare& comp, const Allocator& = Allocator());
template<class InputIterator>
constexpr multiset(InputIterator first, InputIterator last,
const Compare& comp = Compare(), const Allocator& = Allocator());
template<container-compatible-range<value_type> R>
constexpr multiset(from_range_t, R&& rg,
const Compare& comp = Compare(), const Allocator& = Allocator());
constexpr multiset(const multiset& x);
constexpr multiset(multiset&& x);
constexpr explicit multiset(const Allocator&);
constexpr multiset(const multiset&, const type_identity_t<Allocator>&);
constexpr multiset(multiset&&, const type_identity_t<Allocator>&);
constexpr multiset(initializer_list<value_type>, const Compare& = Compare(),
const Allocator& = Allocator());
template<class InputIterator>
constexpr multiset(InputIterator first, InputIterator last, const Allocator& a)
: multiset(first, last, Compare(), a) { }
template<container-compatible-range<value_type> R>
constexpr multiset(from_range_t, R&& rg, const Allocator& a))
: multiset(from_range, std::forward<R>(rg), Compare(), a) { }
constexpr multiset(initializer_list<value_type> il, const Allocator& a)
: multiset(il, Compare(), a) { }
constexpr ~multiset();
constexpr multiset& operator=(const multiset& x);
constexpr multiset& operator=(multiset&& x)
noexcept(allocator_traits<Allocator>::is_always_equal::value &&
is_nothrow_move_assignable_v<Compare>);
constexpr multiset& operator=(initializer_list<value_type>);
constexpr allocator_type get_allocator() const noexcept;
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
constexpr reverse_iterator rbegin() noexcept;
constexpr const_reverse_iterator rbegin() const noexcept;
constexpr reverse_iterator rend() noexcept;
constexpr const_reverse_iterator rend() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator cend() const noexcept;
constexpr const_reverse_iterator crbegin() const noexcept;
constexpr const_reverse_iterator crend() const noexcept;
constexpr bool empty() const noexcept;
constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;
template<class... Args> constexpr iterator emplace(Args&&... args);
template<class... Args> constexpr iterator emplace_hint(const_iterator position, Args&&... args);
constexpr iterator insert(const value_type& x);
constexpr iterator insert(value_type&& x);
constexpr iterator insert(const_iterator position, const value_type& x);
constexpr iterator insert(const_iterator position, value_type&& x);
template<class InputIterator>
constexpr void insert(InputIterator first, InputIterator last);
template<container-compatible-range<value_type> R>
constexpr void insert_range(R&& rg);
constexpr void insert(initializer_list<value_type>);
constexpr node_type extract(const_iterator position);
constexpr node_type extract(const key_type& x);
template<class K> constexpr node_type extract(K&& x);
constexpr iterator insert(node_type&& nh);
constexpr iterator insert(const_iterator hint, node_type&& nh);
constexpr iterator erase(iterator position)
requires (!same_as<iterator, const_iterator>);
constexpr iterator erase(const_iterator position);
constexpr size_type erase(const key_type& x);
template<class K> constexpr size_type erase(K&& x);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void swap(multiset&)
noexcept(allocator_traits<Allocator>::is_always_equal::value &&
is_nothrow_swappable_v<Compare>);
constexpr void clear() noexcept;
template<class C2>
constexpr void merge(multiset<Key, C2, Allocator>& source);
template<class C2>
constexpr void merge(multiset<Key, C2, Allocator>&& source);
template<class C2>
constexpr void merge(set<Key, C2, Allocator>& source);
template<class C2>
constexpr void merge(set<Key, C2, Allocator>&& source);
constexpr key_compare key_comp() const;
constexpr value_compare value_comp() const;
constexpr iterator find(const key_type& x);
constexpr const_iterator find(const key_type& x) const;
template<class K> constexpr iterator find(const K& x);
template<class K> constexpr const_iterator find(const K& x) const;
constexpr size_type count(const key_type& x) const;
template<class K> constexpr size_type count(const K& x) const;
constexpr bool contains(const key_type& x) const;
template<class K> constexpr bool contains(const K& x) const;
constexpr iterator lower_bound(const key_type& x);
constexpr const_iterator lower_bound(const key_type& x) const;
template<class K> constexpr iterator lower_bound(const K& x);
template<class K> constexpr const_iterator lower_bound(const K& x) const;
constexpr iterator upper_bound(const key_type& x);
constexpr const_iterator upper_bound(const key_type& x) const;
template<class K> constexpr iterator upper_bound(const K& x);
template<class K> constexpr const_iterator upper_bound(const K& x) const;
constexpr pair<iterator, iterator> equal_range(const key_type& x);
constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
template<class K>
constexpr pair<iterator, iterator> equal_range(const K& x);
template<class K>
constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const;
};
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>;
}
constexpr explicit multiset(const Compare& comp, const Allocator& = Allocator());
Effects: Constructs an empty
multiset using the specified comparison object and allocator
. template<class InputIterator>
constexpr 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
NlogN,
where
N is
last - first. template<container-compatible-range<value_type> R>
constexpr 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
NlogN, where
N is
ranges::distance(rg). template<class Key, class Compare, class Allocator, class Predicate>
constexpr 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();
24.5 Unordered associative containers [unord]
The header
defines the class
templates
unordered_map and
unordered_multimap;
the header
defines the class
templates
unordered_set and
unordered_multiset.The exposition-only alias templates
iter-value-type,
iter-key-type,
iter-mapped-type,
iter-to-alloc-type,
range-key-type,
range-mapped-type,
and
range-to-alloc-type
defined in
[associative.general] may appear in deduction guides for unordered containers
.An
unordered_map is an unordered associative container that
supports unique keys (an
unordered_map contains at most one of each
key value) and that associates values of another type
mapped_type with the keys
. The
unordered_map class
supports forward iterators
. It provides the operations described in the preceding requirements table for unique keys;
that is, an
unordered_map supports the
a_uniq operations in that table,
not the
a_eq operations
. For an
unordered_map<Key, T> the
key_type is
Key,
the
mapped_type is
T,
and the
value_type is
pair<const Key, T>. Subclause
[unord.map] only describes operations on
unordered_map that
are not described in one of the requirement tables, or for which there
is additional semantic information
.
namespace std {
template<class Key,
class T,
class Hash = hash<Key>,
class Pred = equal_to<Key>,
class Allocator = allocator<pair<const Key, T>>>
class unordered_map {
public:
using key_type = Key;
using mapped_type = T;
using value_type = pair<const Key, T>;
using hasher = Hash;
using key_equal = Pred;
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;
using difference_type = implementation-defined;
using iterator = implementation-defined;
using const_iterator = implementation-defined;
using local_iterator = implementation-defined;
using const_local_iterator = implementation-defined;
using node_type = unspecified;
using insert_return_type = insert-return-type<iterator, node_type>;
constexpr unordered_map();
constexpr explicit unordered_map(size_type n,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
template<class InputIterator>
constexpr unordered_map(InputIterator f, InputIterator l,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
template<container-compatible-range<value_type> R>
constexpr unordered_map(from_range_t, R&& rg, size_type n = see below,
const hasher& hf = hasher(), const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
constexpr unordered_map(const unordered_map&);
constexpr unordered_map(unordered_map&&);
constexpr explicit unordered_map(const Allocator&);
constexpr unordered_map(const unordered_map&, const type_identity_t<Allocator>&);
constexpr unordered_map(unordered_map&&, const type_identity_t<Allocator>&);
constexpr unordered_map(initializer_list<value_type> il,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
constexpr unordered_map(size_type n, const allocator_type& a)
: unordered_map(n, hasher(), key_equal(), a) { }
constexpr unordered_map(size_type n, const hasher& hf, const allocator_type& a)
: unordered_map(n, hf, key_equal(), a) { }
template<class InputIterator>
constexpr unordered_map(InputIterator f, InputIterator l, size_type n, const allocator_type& a)
: unordered_map(f, l, n, hasher(), key_equal(), a) { }
template<class InputIterator>
constexpr unordered_map(InputIterator f, InputIterator l, size_type n, const hasher& hf,
const allocator_type& a)
: unordered_map(f, l, n, hf, key_equal(), a) { }
template<container-compatible-range<value_type> R>
constexpr unordered_map(from_range_t, R&& rg, size_type n, const allocator_type& a)
: unordered_map(from_range, std::forward<R>(rg), n, hasher(), key_equal(), a) { }
template<container-compatible-range<value_type> R>
constexpr unordered_map(from_range_t, R&& rg, size_type n, const hasher& hf, const allocator_type& a)
: unordered_map(from_range, std::forward<R>(rg), n, hf, key_equal(), a) { }
constexpr unordered_map(initializer_list<value_type> il, size_type n, const allocator_type& a)
: unordered_map(il, n, hasher(), key_equal(), a) { }
constexpr unordered_map(initializer_list<value_type> il, size_type n, const hasher& hf,
const allocator_type& a)
: unordered_map(il, n, hf, key_equal(), a) { }
constexpr ~unordered_map();
constexpr unordered_map& operator=(const unordered_map&);
constexpr unordered_map& operator=(unordered_map&&)
noexcept(allocator_traits<Allocator>::is_always_equal::value &&
is_nothrow_move_assignable_v<Hash> &&
is_nothrow_move_assignable_v<Pred>);
constexpr unordered_map& operator=(initializer_list<value_type>);
constexpr allocator_type get_allocator() const noexcept;
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator cend() const noexcept;
constexpr bool empty() const noexcept;
constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;
template<class... Args> constexpr pair<iterator, bool> emplace(Args&&... args);
template<class... Args> constexpr iterator emplace_hint(const_iterator position, Args&&... args);
constexpr pair<iterator, bool> insert(const value_type& obj);
constexpr pair<iterator, bool> insert(value_type&& obj);
template<class P> constexpr pair<iterator, bool> insert(P&& obj);
constexpr iterator insert(const_iterator hint, const value_type& obj);
constexpr iterator insert(const_iterator hint, value_type&& obj);
template<class P> constexpr iterator insert(const_iterator hint, P&& obj);
template<class InputIterator> constexpr void insert(InputIterator first, InputIterator last);
template<container-compatible-range<value_type> R>
constexpr void insert_range(R&& rg);
constexpr void insert(initializer_list<value_type>);
constexpr node_type extract(const_iterator position);
constexpr node_type extract(const key_type& x);
template<class K> constexpr node_type extract(K&& x);
constexpr insert_return_type insert(node_type&& nh);
constexpr iterator insert(const_iterator hint, node_type&& nh);
template<class... Args>
constexpr pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
template<class... Args>
constexpr pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
template<class K, class... Args>
constexpr pair<iterator, bool> try_emplace(K&& k, Args&&... args);
template<class... Args>
constexpr iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);
template<class... Args>
constexpr iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);
template<class K, class... Args>
constexpr iterator try_emplace(const_iterator hint, K&& k, Args&&... args);
template<class M>
constexpr pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);
template<class M>
constexpr pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);
template<class K, class M>
constexpr pair<iterator, bool> insert_or_assign(K&& k, M&& obj);
template<class M>
constexpr iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);
template<class M>
constexpr iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);
template<class K, class M>
constexpr iterator insert_or_assign(const_iterator hint, K&& k, M&& obj);
constexpr iterator erase(iterator position);
constexpr iterator erase(const_iterator position);
constexpr size_type erase(const key_type& k);
template<class K> constexpr size_type erase(K&& x);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void swap(unordered_map&)
noexcept(allocator_traits<Allocator>::is_always_equal::value &&
is_nothrow_swappable_v<Hash> &&
is_nothrow_swappable_v<Pred>);
constexpr void clear() noexcept;
template<class H2, class P2>
constexpr void merge(unordered_map<Key, T, H2, P2, Allocator>& source);
template<class H2, class P2>
constexpr void merge(unordered_map<Key, T, H2, P2, Allocator>&& source);
template<class H2, class P2>
constexpr void merge(unordered_multimap<Key, T, H2, P2, Allocator>& source);
template<class H2, class P2>
constexpr void merge(unordered_multimap<Key, T, H2, P2, Allocator>&& source);
constexpr hasher hash_function() const;
constexpr key_equal key_eq() const;
constexpr iterator find(const key_type& k);
constexpr const_iterator find(const key_type& k) const;
template<class K>
constexpr iterator find(const K& k);
template<class K>
constexpr const_iterator find(const K& k) const;
constexpr size_type count(const key_type& k) const;
template<class K>
constexpr size_type count(const K& k) const;
constexpr bool contains(const key_type& k) const;
template<class K>
constexpr bool contains(const K& k) const;
constexpr pair<iterator, iterator> equal_range(const key_type& k);
constexpr pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
template<class K>
constexpr pair<iterator, iterator> equal_range(const K& k);
template<class K>
constexpr pair<const_iterator, const_iterator> equal_range(const K& k) const;
constexpr mapped_type& operator[](const key_type& k);
constexpr mapped_type& operator[](key_type&& k);
template<class K> constexpr mapped_type& operator[](K&& k);
constexpr mapped_type& at(const key_type& k);
constexpr const mapped_type& at(const key_type& k) const;
template<class K> constexpr mapped_type& at(const K& k);
template<class K> constexpr const mapped_type& at(const K& k) const;
constexpr size_type bucket_count() const noexcept;
constexpr size_type max_bucket_count() const noexcept;
constexpr size_type bucket_size(size_type n) const;
constexpr size_type bucket(const key_type& k) const;
template<class K> constexpr size_type bucket(const K& k) const;
constexpr local_iterator begin(size_type n);
constexpr const_local_iterator begin(size_type n) const;
constexpr local_iterator end(size_type n);
constexpr const_local_iterator end(size_type n) const;
constexpr const_local_iterator cbegin(size_type n) const;
constexpr const_local_iterator cend(size_type n) const;
constexpr float load_factor() const noexcept;
constexpr float max_load_factor() const noexcept;
constexpr void max_load_factor(float z);
constexpr void rehash(size_type n);
constexpr void reserve(size_type n);
};
template<class InputIterator,
class Hash = hash<iter-key-type<InputIterator>>,
class Pred = equal_to<iter-key-type<InputIterator>>,
class Allocator = allocator<iter-to-alloc-type<InputIterator>>>
unordered_map(InputIterator, InputIterator, typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Hash, Pred,
Allocator>;
template<ranges::input_range R, class Hash = hash<range-key-type<R>>,
class Pred = equal_to<range-key-type<R>>,
class Allocator = allocator<range-to-alloc-type<R>>>
unordered_map(from_range_t, R&&, typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_map<range-key-type<R>, range-mapped-type<R>, Hash, Pred, Allocator>;
template<class Key, class T, class Hash = hash<Key>,
class Pred = equal_to<Key>, class Allocator = allocator<pair<const Key, T>>>
unordered_map(initializer_list<pair<Key, T>>,
typename see below::size_type = see below, Hash = Hash(),
Pred = Pred(), Allocator = Allocator())
-> unordered_map<Key, T, Hash, Pred, Allocator>;
template<class InputIterator, class Allocator>
unordered_map(InputIterator, InputIterator, typename see below::size_type, Allocator)
-> unordered_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>,
hash<iter-key-type<InputIterator>>,
equal_to<iter-key-type<InputIterator>>, Allocator>;
template<class InputIterator, class Allocator>
unordered_map(InputIterator, InputIterator, Allocator)
-> unordered_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>,
hash<iter-key-type<InputIterator>>,
equal_to<iter-key-type<InputIterator>>, Allocator>;
template<class InputIterator, class Hash, class Allocator>
unordered_map(InputIterator, InputIterator, typename see below::size_type, Hash, Allocator)
-> unordered_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Hash,
equal_to<iter-key-type<InputIterator>>, Allocator>;
template<ranges::input_range R, class Allocator>
unordered_map(from_range_t, R&&, typename see below::size_type, Allocator)
-> unordered_map<range-key-type<R>, range-mapped-type<R>, hash<range-key-type<R>>,
equal_to<range-key-type<R>>, Allocator>;
template<ranges::input_range R, class Allocator>
unordered_map(from_range_t, R&&, Allocator)
-> unordered_map<range-key-type<R>, range-mapped-type<R>, hash<range-key-type<R>>,
equal_to<range-key-type<R>>, Allocator>;
template<ranges::input_range R, class Hash, class Allocator>
unordered_map(from_range_t, R&&, typename see below::size_type, Hash, Allocator)
-> unordered_map<range-key-type<R>, range-mapped-type<R>, Hash,
equal_to<range-key-type<R>>, Allocator>;
template<class Key, class T, class Allocator>
unordered_map(initializer_list<pair<Key, T>>, typename see below::size_type,
Allocator)
-> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
template<class Key, class T, class Allocator>
unordered_map(initializer_list<pair<Key, T>>, Allocator)
-> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
template<class Key, class T, class Hash, class Allocator>
unordered_map(initializer_list<pair<Key, T>>, typename see below::size_type, Hash,
Allocator)
-> unordered_map<Key, T, Hash, equal_to<Key>, Allocator>;
}
A
size_type parameter type in an
unordered_map deduction guide
refers to the
size_type member type of the type deduced by the deduction guide
.constexpr unordered_map() : unordered_map(size_type(see below)) { }
constexpr explicit unordered_map(size_type n,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
Effects: Constructs an empty
unordered_map using the
specified hash function, key equality predicate, and allocator, and
using at least
n buckets
. For the default constructor,
the number of buckets is
implementation-defined
. max_load_factor() returns
1.0. template<class InputIterator>
constexpr unordered_map(InputIterator f, InputIterator l,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
template<container-compatible-range<value_type> R>
constexpr unordered_map(from_range_t, R&& rg,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
constexpr unordered_map(initializer_list<value_type> il,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
Effects: Constructs an empty
unordered_map using the
specified hash function, key equality predicate, and allocator, and
using at least
n buckets
. If
n is not
provided, the number of buckets is
implementation-defined
. Then
inserts elements from the range [
f, l),
rg, or
il,
respectively
. max_load_factor() returns
1.0. Complexity: Average case linear, worst case quadratic
. constexpr mapped_type& operator[](const key_type& k);
Effects: Equivalent to: return try_emplace(k).first->second;
constexpr mapped_type& operator[](key_type&& k);
Effects: Equivalent to: return try_emplace(std::move(k)).first->second;
template<class K> constexpr mapped_type& operator[](K&& k);
Constraints: The
qualified-ids Hash::is_transparent and
Pred::is_transparent are valid and denote types
. Effects: Equivalent to: return try_emplace(std::forward<K>(k)).first->second;
constexpr mapped_type& at(const key_type& k);
constexpr const mapped_type& at(const key_type& k) const;
Returns: A reference to
x.second, where
x is the (unique) element whose key is equivalent to
k. Throws: An exception object of type
out_of_range if no such element is present
. template<class K> constexpr mapped_type& at(const K& k);
template<class K> constexpr const mapped_type& at(const K& k) const;
Constraints: The
qualified-ids Hash::is_transparent and
Pred::is_transparent are valid and denote types
. Preconditions: The expression
find(k) is well-formed and has well-defined behavior
. Returns: A reference to
find(k)->second. Throws: An exception object of type
out_of_range
if
find(k) == end() is
true. template<class P>
constexpr pair<iterator, bool> insert(P&& obj);
Constraints:
is_constructible_v<value_type, P&&> is
true. Effects: Equivalent to: return emplace(std::forward<P>(obj));
template<class P>
constexpr iterator insert(const_iterator hint, P&& obj);
Constraints:
is_constructible_v<value_type, P&&> is
true. Effects: Equivalent to:
return emplace_hint(hint, std::forward<P>(obj));
template<class... Args>
constexpr pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
template<class... Args>
constexpr iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);
Preconditions:
value_type is
Cpp17EmplaceConstructible into
unordered_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>
constexpr pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
template<class... Args>
constexpr iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);
Preconditions:
value_type is
Cpp17EmplaceConstructible into
unordered_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>
constexpr pair<iterator, bool> try_emplace(K&& k, Args&&... args);
template<class K, class... Args>
constexpr iterator try_emplace(const_iterator hint, K&& k, Args&&... args);
Constraints: The
qualified-ids Hash::is_transparent and
Pred::is_transparent are valid and denote types
. 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
unordered_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
h be
hash_function()(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
hash_function()(u.first) != h || contains(u.first) is
true,
the behavior is undefined
. 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>
constexpr pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);
template<class M>
constexpr 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
unordered_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>
constexpr pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);
template<class M>
constexpr 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
unordered_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>
constexpr pair<iterator, bool> insert_or_assign(K&& k, M&& obj);
template<class K, class M>
constexpr iterator insert_or_assign(const_iterator hint, K&& k, M&& obj);
Constraints: The
qualified-ids Hash::is_transparent and
Pred::is_transparent are valid and denote types
. Mandates:
is_assignable_v<mapped_type&, M&&> is
true. Preconditions:
value_type is
Cpp17EmplaceConstructible
into
unordered_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
h be
hash_function()(k). Constructs an object
u of type
value_type
with
std::forward<K>(k), std::forward<M>(obj). If
hash_function()(u.first) != h || contains(u.first) is
true,
the behavior is undefined
. 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 K, class T, class H, class P, class A, class Predicate>
constexpr typename unordered_map<K, T, H, P, A>::size_type
erase_if(unordered_map<K, T, H, P, A>& 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();
An
unordered_multimap is an unordered associative container
that supports equivalent keys (an instance of
unordered_multimap may contain
multiple copies of each key value) and that associates values of
another type
mapped_type with the keys
. The
unordered_multimap class
supports forward iterators
. It provides the operations described in the
preceding requirements table for equivalent keys; that is, an
unordered_multimap
supports the
a_eq operations in that table, not the
a_uniq operations
. For an
unordered_multimap<Key, T> the
key_type is
Key,
the
mapped_type is
T,
and the
value_type is
pair<const Key, T>. Subclause
[unord.multimap] only describes operations on
unordered_multimap
that are not described in one of the requirement tables, or for which
there is additional semantic information
.
namespace std {
template<class Key,
class T,
class Hash = hash<Key>,
class Pred = equal_to<Key>,
class Allocator = allocator<pair<const Key, T>>>
class unordered_multimap {
public:
using key_type = Key;
using mapped_type = T;
using value_type = pair<const Key, T>;
using hasher = Hash;
using key_equal = Pred;
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;
using difference_type = implementation-defined;
using iterator = implementation-defined;
using const_iterator = implementation-defined;
using local_iterator = implementation-defined;
using const_local_iterator = implementation-defined;
using node_type = unspecified;
constexpr unordered_multimap();
constexpr explicit unordered_multimap(size_type n,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
template<class InputIterator>
constexpr unordered_multimap(InputIterator f, InputIterator l,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
template<container-compatible-range<value_type> R>
constexpr unordered_multimap(from_range_t, R&& rg,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
constexpr unordered_multimap(const unordered_multimap&);
constexpr unordered_multimap(unordered_multimap&&);
constexpr explicit unordered_multimap(const Allocator&);
constexpr unordered_multimap(const unordered_multimap&, const type_identity_t<Allocator>&);
constexpr unordered_multimap(unordered_multimap&&, const type_identity_t<Allocator>&);
constexpr unordered_multimap(initializer_list<value_type> il,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
constexpr unordered_multimap(size_type n, const allocator_type& a)
: unordered_multimap(n, hasher(), key_equal(), a) { }
constexpr unordered_multimap(size_type n, const hasher& hf, const allocator_type& a)
: unordered_multimap(n, hf, key_equal(), a) { }
template<class InputIterator>
constexpr unordered_multimap(InputIterator f, InputIterator l, size_type n, const allocator_type& a)
: unordered_multimap(f, l, n, hasher(), key_equal(), a) { }
template<class InputIterator>
constexpr unordered_multimap(InputIterator f, InputIterator l, size_type n, const hasher& hf,
const allocator_type& a)
: unordered_multimap(f, l, n, hf, key_equal(), a) { }
template<container-compatible-range<value_type> R>
constexpr unordered_multimap(from_range_t, R&& rg, size_type n, const allocator_type& a)
: unordered_multimap(from_range, std::forward<R>(rg),
n, hasher(), key_equal(), a) { }
template<container-compatible-range<value_type> R>
constexpr unordered_multimap(from_range_t, R&& rg, size_type n, const hasher& hf,
const allocator_type& a)
: unordered_multimap(from_range, std::forward<R>(rg), n, hf, key_equal(), a) { }
constexpr unordered_multimap(initializer_list<value_type> il, size_type n, const allocator_type& a)
: unordered_multimap(il, n, hasher(), key_equal(), a) { }
constexpr unordered_multimap(initializer_list<value_type> il, size_type n, const hasher& hf,
const allocator_type& a)
: unordered_multimap(il, n, hf, key_equal(), a) { }
constexpr ~unordered_multimap();
constexpr unordered_multimap& operator=(const unordered_multimap&);
constexpr unordered_multimap& operator=(unordered_multimap&&)
noexcept(allocator_traits<Allocator>::is_always_equal::value &&
is_nothrow_move_assignable_v<Hash> &&
is_nothrow_move_assignable_v<Pred>);
constexpr unordered_multimap& operator=(initializer_list<value_type>);
constexpr allocator_type get_allocator() const noexcept;
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator cend() const noexcept;
constexpr bool empty() const noexcept;
constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;
template<class... Args> constexpr iterator emplace(Args&&... args);
template<class... Args> constexpr iterator emplace_hint(const_iterator position, Args&&... args);
constexpr iterator insert(const value_type& obj);
constexpr iterator insert(value_type&& obj);
template<class P> constexpr iterator insert(P&& obj);
constexpr iterator insert(const_iterator hint, const value_type& obj);
constexpr iterator insert(const_iterator hint, value_type&& obj);
template<class P> constexpr iterator insert(const_iterator hint, P&& obj);
template<class InputIterator> constexpr void insert(InputIterator first, InputIterator last);
template<container-compatible-range<value_type> R>
constexpr void insert_range(R&& rg);
constexpr void insert(initializer_list<value_type>);
constexpr node_type extract(const_iterator position);
constexpr node_type extract(const key_type& x);
template<class K> constexpr node_type extract(K&& x);
constexpr iterator insert(node_type&& nh);
constexpr iterator insert(const_iterator hint, node_type&& nh);
constexpr iterator erase(iterator position);
constexpr iterator erase(const_iterator position);
constexpr size_type erase(const key_type& k);
template<class K> size_type erase(K&& x);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void swap(unordered_multimap&)
noexcept(allocator_traits<Allocator>::is_always_equal::value &&
is_nothrow_swappable_v<Hash> &&
is_nothrow_swappable_v<Pred>);
constexpr void clear() noexcept;
template<class H2, class P2>
constexpr void merge(unordered_multimap<Key, T, H2, P2, Allocator>& source);
template<class H2, class P2>
constexpr void merge(unordered_multimap<Key, T, H2, P2, Allocator>&& source);
template<class H2, class P2>
constexpr void merge(unordered_map<Key, T, H2, P2, Allocator>& source);
template<class H2, class P2>
constexpr void merge(unordered_map<Key, T, H2, P2, Allocator>&& source);
constexpr hasher hash_function() const;
constexpr key_equal key_eq() const;
constexpr iterator find(const key_type& k);
constexpr const_iterator find(const key_type& k) const;
template<class K>
constexpr iterator find(const K& k);
template<class K>
constexpr const_iterator find(const K& k) const;
constexpr size_type count(const key_type& k) const;
template<class K>
constexpr size_type count(const K& k) const;
constexpr bool contains(const key_type& k) const;
template<class K>
constexpr bool contains(const K& k) const;
constexpr pair<iterator, iterator> equal_range(const key_type& k);
constexpr pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
template<class K>
constexpr pair<iterator, iterator> equal_range(const K& k);
template<class K>
constexpr pair<const_iterator, const_iterator> equal_range(const K& k) const;
constexpr size_type bucket_count() const noexcept;
constexpr size_type max_bucket_count() const noexcept;
constexpr size_type bucket_size(size_type n) const;
constexpr size_type bucket(const key_type& k) const;
template<class K> constexpr size_type bucket(const K& k) const;
constexpr local_iterator begin(size_type n);
constexpr const_local_iterator begin(size_type n) const;
constexpr local_iterator end(size_type n);
constexpr const_local_iterator end(size_type n) const;
constexpr const_local_iterator cbegin(size_type n) const;
constexpr const_local_iterator cend(size_type n) const;
constexpr float load_factor() const noexcept;
constexpr float max_load_factor() const noexcept;
constexpr void max_load_factor(float z);
constexpr void rehash(size_type n);
constexpr void reserve(size_type n);
};
template<class InputIterator,
class Hash = hash<iter-key-type<InputIterator>>,
class Pred = equal_to<iter-key-type<InputIterator>>,
class Allocator = allocator<iter-to-alloc-type<InputIterator>>>
unordered_multimap(InputIterator, InputIterator,
typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>,
Hash, Pred, Allocator>;
template<ranges::input_range R,
class Hash = hash<range-key-type<R>>,
class Pred = equal_to<range-key-type<R>>,
class Allocator = allocator<range-to-alloc-type<R>>>
unordered_multimap(from_range_t, R&&, typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_multimap<range-key-type<R>, range-mapped-type<R>, Hash, Pred, Allocator>;
template<class Key, class T, class Hash = hash<Key>,
class Pred = equal_to<Key>, class Allocator = allocator<pair<const Key, T>>>
unordered_multimap(initializer_list<pair<Key, T>>,
typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_multimap<Key, T, Hash, Pred, Allocator>;
template<class InputIterator, class Allocator>
unordered_multimap(InputIterator, InputIterator, typename see below::size_type, Allocator)
-> unordered_multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>,
hash<iter-key-type<InputIterator>>,
equal_to<iter-key-type<InputIterator>>, Allocator>;
template<class InputIterator, class Allocator>
unordered_multimap(InputIterator, InputIterator, Allocator)
-> unordered_multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>,
hash<iter-key-type<InputIterator>>,
equal_to<iter-key-type<InputIterator>>, Allocator>;
template<class InputIterator, class Hash, class Allocator>
unordered_multimap(InputIterator, InputIterator, typename see below::size_type, Hash,
Allocator)
-> unordered_multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Hash,
equal_to<iter-key-type<InputIterator>>, Allocator>;
template<ranges::input_range R, class Allocator>
unordered_multimap(from_range_t, R&&, typename see below::size_type, Allocator)
-> unordered_multimap<range-key-type<R>, range-mapped-type<R>, hash<range-key-type<R>>,
equal_to<range-key-type<R>>, Allocator>;
template<ranges::input_range R, class Allocator>
unordered_multimap(from_range_t, R&&, Allocator)
-> unordered_multimap<range-key-type<R>, range-mapped-type<R>, hash<range-key-type<R>>,
equal_to<range-key-type<R>>, Allocator>;
template<ranges::input_range R, class Hash, class Allocator>
unordered_multimap(from_range_t, R&&, typename see below::size_type, Hash, Allocator)
-> unordered_multimap<range-key-type<R>, range-mapped-type<R>, Hash,
equal_to<range-key-type<R>>, Allocator>;
template<class Key, class T, class Allocator>
unordered_multimap(initializer_list<pair<Key, T>>, typename see below::size_type,
Allocator)
-> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>;
template<class Key, class T, class Allocator>
unordered_multimap(initializer_list<pair<Key, T>>, Allocator)
-> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>;
template<class Key, class T, class Hash, class Allocator>
unordered_multimap(initializer_list<pair<Key, T>>, typename see below::size_type,
Hash, Allocator)
-> unordered_multimap<Key, T, Hash, equal_to<Key>, Allocator>;
}
A
size_type parameter type in an
unordered_multimap deduction guide
refers to the
size_type member type of the type deduced by the deduction guide
.constexpr unordered_multimap() : unordered_multimap(size_type(see below)) { }
constexpr explicit unordered_multimap(size_type n,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
Effects: Constructs an empty
unordered_multimap using the
specified hash function, key equality predicate, and allocator, and
using at least
n buckets
. For the default constructor,
the number of buckets is
implementation-defined
. max_load_factor() returns
1.0. template<class InputIterator>
constexpr unordered_multimap(InputIterator f, InputIterator l,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
template<container-compatible-range<value_type> R>
constexpr unordered_multimap(from_range_t, R&& rg,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
constexpr unordered_multimap(initializer_list<value_type> il,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
Effects: Constructs an empty
unordered_multimap using the
specified hash function, key equality predicate, and allocator, and
using at least
n buckets
. If
n is not
provided, the number of buckets is
implementation-defined
. Then
inserts elements from the range [
f, l),
rg, or
il,
respectively
. max_load_factor() returns
1.0. Complexity: Average case linear, worst case quadratic
. template<class P>
constexpr iterator insert(P&& obj);
Constraints:
is_constructible_v<value_type, P&&> is
true. Effects: Equivalent to: return emplace(std::forward<P>(obj));
template<class P>
constexpr iterator insert(const_iterator hint, P&& obj);
Constraints:
is_constructible_v<value_type, P&&> is
true. Effects: Equivalent to:
return emplace_hint(hint, std::forward<P>(obj));
template<class K, class T, class H, class P, class A, class Predicate>
constexpr typename unordered_multimap<K, T, H, P, A>::size_type
erase_if(unordered_multimap<K, T, H, P, A>& 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();
An
unordered_set is an unordered associative container that
supports unique keys (an
unordered_set contains at most one of each
key value) and in which the elements' keys are the elements
themselves
. The
unordered_set class
supports forward iterators
. It provides the operations described in the preceding requirements table for unique keys;
that is, an
unordered_set supports the
a_uniq operations in that table,
not the
a_eq operations
. For an
unordered_set<Key> the
key_type
and the
value_type are both
Key. The
iterator and
const_iterator types are both constant iterator types
. It is unspecified whether they are the same type
. Subclause
[unord.set] only describes operations on
unordered_set that
are not described in one of the requirement tables, or for which there
is additional semantic information
.
namespace std {
template<class Key,
class Hash = hash<Key>,
class Pred = equal_to<Key>,
class Allocator = allocator<Key>>
class unordered_set {
public:
using key_type = Key;
using value_type = Key;
using hasher = Hash;
using key_equal = Pred;
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;
using difference_type = implementation-defined;
using iterator = implementation-defined;
using const_iterator = implementation-defined;
using local_iterator = implementation-defined;
using const_local_iterator = implementation-defined;
using node_type = unspecified;
using insert_return_type = insert-return-type<iterator, node_type>;
constexpr unordered_set();
constexpr explicit unordered_set(size_type n,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
template<class InputIterator>
constexpr unordered_set(InputIterator f, InputIterator l,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
template<container-compatible-range<value_type> R>
constexpr unordered_set(from_range_t, R&& rg,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
constexpr unordered_set(const unordered_set&);
constexpr unordered_set(unordered_set&&);
constexpr explicit unordered_set(const Allocator&);
constexpr unordered_set(const unordered_set&, const type_identity_t<Allocator>&);
constexpr unordered_set(unordered_set&&, const type_identity_t<Allocator>&);
constexpr unordered_set(initializer_list<value_type> il,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
constexpr unordered_set(size_type n, const allocator_type& a)
: unordered_set(n, hasher(), key_equal(), a) { }
constexpr unordered_set(size_type n, const hasher& hf, const allocator_type& a)
: unordered_set(n, hf, key_equal(), a) { }
template<class InputIterator>
constexpr unordered_set(InputIterator f, InputIterator l, size_type n, const allocator_type& a)
: unordered_set(f, l, n, hasher(), key_equal(), a) { }
template<class InputIterator>
constexpr unordered_set(InputIterator f, InputIterator l, size_type n, const hasher& hf,
const allocator_type& a)
: unordered_set(f, l, n, hf, key_equal(), a) { }
constexpr unordered_set(initializer_list<value_type> il, size_type n, const allocator_type& a)
: unordered_set(il, n, hasher(), key_equal(), a) { }
template<container-compatible-range<value_type> R>
constexpr unordered_set(from_range_t, R&& rg, size_type n, const allocator_type& a)
: unordered_set(from_range, std::forward<R>(rg), n, hasher(), key_equal(), a) { }
template<container-compatible-range<value_type> R>
constexpr unordered_set(from_range_t, R&& rg, size_type n, const hasher& hf, const allocator_type& a)
: unordered_set(from_range, std::forward<R>(rg), n, hf, key_equal(), a) { }
constexpr unordered_set(initializer_list<value_type> il, size_type n, const hasher& hf,
const allocator_type& a)
: unordered_set(il, n, hf, key_equal(), a) { }
constexpr ~unordered_set();
constexpr unordered_set& operator=(const unordered_set&);
constexpr unordered_set& operator=(unordered_set&&)
noexcept(allocator_traits<Allocator>::is_always_equal::value &&
is_nothrow_move_assignable_v<Hash> &&
is_nothrow_move_assignable_v<Pred>);
constexpr unordered_set& operator=(initializer_list<value_type>);
constexpr allocator_type get_allocator() const noexcept;
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator cend() const noexcept;
constexpr bool empty() const noexcept;
constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;
template<class... Args> constexpr pair<iterator, bool> emplace(Args&&... args);
template<class... Args> constexpr iterator emplace_hint(const_iterator position, Args&&... args);
constexpr pair<iterator, bool> insert(const value_type& obj);
constexpr pair<iterator, bool> insert(value_type&& obj);
template<class K> constexpr pair<iterator, bool> insert(K&& obj);
constexpr iterator insert(const_iterator hint, const value_type& obj);
constexpr iterator insert(const_iterator hint, value_type&& obj);
template<class K> constexpr iterator insert(const_iterator hint, K&& obj);
template<class InputIterator> constexpr void insert(InputIterator first, InputIterator last);
template<container-compatible-range<value_type> R>
constexpr void insert_range(R&& rg);
constexpr void insert(initializer_list<value_type>);
constexpr node_type extract(const_iterator position);
constexpr node_type extract(const key_type& x);
template<class K> constexpr node_type extract(K&& x);
constexpr insert_return_type insert(node_type&& nh);
constexpr iterator insert(const_iterator hint, node_type&& nh);
constexpr iterator erase(iterator position)
requires (!same_as<iterator, const_iterator>);
constexpr iterator erase(const_iterator position);
constexpr size_type erase(const key_type& k);
template<class K> constexpr size_type erase(K&& x);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void swap(unordered_set&)
noexcept(allocator_traits<Allocator>::is_always_equal::value &&
is_nothrow_swappable_v<Hash> &&
is_nothrow_swappable_v<Pred>);
constexpr void clear() noexcept;
template<class H2, class P2>
constexpr void merge(unordered_set<Key, H2, P2, Allocator>& source);
template<class H2, class P2>
constexpr void merge(unordered_set<Key, H2, P2, Allocator>&& source);
template<class H2, class P2>
constexpr void merge(unordered_multiset<Key, H2, P2, Allocator>& source);
template<class H2, class P2>
constexpr void merge(unordered_multiset<Key, H2, P2, Allocator>&& source);
constexpr hasher hash_function() const;
constexpr key_equal key_eq() const;
constexpr iterator find(const key_type& k);
constexpr const_iterator find(const key_type& k) const;
template<class K>
constexpr iterator find(const K& k);
template<class K>
constexpr const_iterator find(const K& k) const;
constexpr size_type count(const key_type& k) const;
template<class K>
constexpr size_type count(const K& k) const;
constexpr bool contains(const key_type& k) const;
template<class K>
constexpr bool contains(const K& k) const;
constexpr pair<iterator, iterator> equal_range(const key_type& k);
constexpr pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
template<class K>
constexpr pair<iterator, iterator> equal_range(const K& k);
template<class K>
constexpr pair<const_iterator, const_iterator> equal_range(const K& k) const;
constexpr size_type bucket_count() const noexcept;
constexpr size_type max_bucket_count() const noexcept;
constexpr size_type bucket_size(size_type n) const;
constexpr size_type bucket(const key_type& k) const;
template<class K> constexpr size_type bucket(const K& k) const;
constexpr local_iterator begin(size_type n);
constexpr const_local_iterator begin(size_type n) const;
constexpr local_iterator end(size_type n);
constexpr const_local_iterator end(size_type n) const;
constexpr const_local_iterator cbegin(size_type n) const;
constexpr const_local_iterator cend(size_type n) const;
constexpr float load_factor() const noexcept;
constexpr float max_load_factor() const noexcept;
constexpr void max_load_factor(float z);
constexpr void rehash(size_type n);
constexpr void reserve(size_type n);
};
template<class InputIterator,
class Hash = hash<iter-value-type<InputIterator>>,
class Pred = equal_to<iter-value-type<InputIterator>>,
class Allocator = allocator<iter-value-type<InputIterator>>>
unordered_set(InputIterator, InputIterator, typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_set<iter-value-type<InputIterator>,
Hash, Pred, Allocator>;
template<ranges::input_range R,
class Hash = hash<ranges::range_value_t<R>>,
class Pred = equal_to<ranges::range_value_t<R>>,
class Allocator = allocator<ranges::range_value_t<R>>>
unordered_set(from_range_t, R&&, typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_set<ranges::range_value_t<R>, Hash, Pred, Allocator>;
template<class T, class Hash = hash<T>,
class Pred = equal_to<T>, class Allocator = allocator<T>>
unordered_set(initializer_list<T>, typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_set<T, Hash, Pred, Allocator>;
template<class InputIterator, class Allocator>
unordered_set(InputIterator, InputIterator, typename see below::size_type, Allocator)
-> unordered_set<iter-value-type<InputIterator>,
hash<iter-value-type<InputIterator>>,
equal_to<iter-value-type<InputIterator>>,
Allocator>;
template<class InputIterator, class Hash, class Allocator>
unordered_set(InputIterator, InputIterator, typename see below::size_type,
Hash, Allocator)
-> unordered_set<iter-value-type<InputIterator>, Hash,
equal_to<iter-value-type<InputIterator>>,
Allocator>;
template<ranges::input_range R, class Allocator>
unordered_set(from_range_t, R&&, typename see below::size_type, Allocator)
-> unordered_set<ranges::range_value_t<R>, hash<ranges::range_value_t<R>>,
equal_to<ranges::range_value_t<R>>, Allocator>;
template<ranges::input_range R, class Allocator>
unordered_set(from_range_t, R&&, Allocator)
-> unordered_set<ranges::range_value_t<R>, hash<ranges::range_value_t<R>>,
equal_to<ranges::range_value_t<R>>, Allocator>;
template<ranges::input_range R, class Hash, class Allocator>
unordered_set(from_range_t, R&&, typename see below::size_type, Hash, Allocator)
-> unordered_set<ranges::range_value_t<R>, Hash,
equal_to<ranges::range_value_t<R>>, Allocator>;
template<class T, class Allocator>
unordered_set(initializer_list<T>, typename see below::size_type, Allocator)
-> unordered_set<T, hash<T>, equal_to<T>, Allocator>;
template<class T, class Hash, class Allocator>
unordered_set(initializer_list<T>, typename see below::size_type, Hash, Allocator)
-> unordered_set<T, Hash, equal_to<T>, Allocator>;
}
A
size_type parameter type in an
unordered_set deduction guide
refers to the
size_type member type of
the type deduced by the deduction guide
.constexpr unordered_set() : unordered_set(size_type(see below)) { }
constexpr explicit unordered_set(size_type n,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
Effects: Constructs an empty
unordered_set using the
specified hash function, key equality predicate, and allocator, and
using at least
n buckets
. For the default constructor,
the number of buckets is
implementation-defined
. max_load_factor() returns
1.0. template<class InputIterator>
constexpr unordered_set(InputIterator f, InputIterator l,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
template<container-compatible-range<value_type> R>
constexpr unordered_multiset(from_range_t, R&& rg,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
constexpr unordered_set(initializer_list<value_type> il,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
Effects: Constructs an empty
unordered_set using the
specified hash function, key equality predicate, and allocator, and
using at least
n buckets
. If
n is not
provided, the number of buckets is
implementation-defined
. Then
inserts elements from the range [
f, l),
rg, or
il,
respectively
. max_load_factor() returns
1.0. Complexity: Average case linear, worst case quadratic
. template<class K, class H, class P, class A, class Predicate>
constexpr typename unordered_set<K, H, P, A>::size_type
erase_if(unordered_set<K, H, P, A>& 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();
template<class K> constexpr pair<iterator, bool> insert(K&& obj);
template<class K> constexpr iterator insert(const_iterator hint, K&& obj);
Constraints: The
qualified-ids Hash::is_transparent and
Pred::is_transparent are valid and denote types
. 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
unordered_set from
std::forward<K>
(obj). Effects: If the set already contains an element that is equivalent to
obj,
there is no effect
. Otherwise, let
h be
hash_function()(obj). Constructs an object
u of type
value_type
with
std::forward<K>(obj). If
hash_function()(u) != h || contains(u) is
true,
the behavior is undefined
. 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
obj.Complexity: Average case constant, worst case linear
. An
unordered_multiset is an unordered associative container
that supports equivalent keys (an instance of
unordered_multiset may contain
multiple copies of the same key value) and in which each element's key
is the element itself
. The
unordered_multiset class
supports forward iterators
. It provides the operations described in the
preceding requirements table for equivalent keys; that is, an
unordered_multiset
supports the
a_eq operations in that table, not the
a_uniq operations
. For an
unordered_multiset<Key> the
key_type and the
value_type are
both
Key. The
iterator and
const_iterator types are both
constant iterator types
. It is unspecified whether they are the same type
. Subclause
[unord.multiset] only describes operations on
unordered_multiset that
are not described in one of the requirement tables, or for which there
is additional semantic information
.
namespace std {
template<class Key,
class Hash = hash<Key>,
class Pred = equal_to<Key>,
class Allocator = allocator<Key>>
class unordered_multiset {
public:
using key_type = Key;
using value_type = Key;
using hasher = Hash;
using key_equal = Pred;
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;
using difference_type = implementation-defined;
using iterator = implementation-defined;
using const_iterator = implementation-defined;
using local_iterator = implementation-defined;
using const_local_iterator = implementation-defined;
using node_type = unspecified;
constexpr unordered_multiset();
constexpr explicit unordered_multiset(size_type n,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
template<class InputIterator>
constexpr unordered_multiset(InputIterator f, InputIterator l,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
template<container-compatible-range<value_type> R>
constexpr unordered_multiset(from_range_t, R&& rg,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
constexpr unordered_multiset(const unordered_multiset&);
constexpr unordered_multiset(unordered_multiset&&);
constexpr explicit unordered_multiset(const Allocator&);
constexpr unordered_multiset(const unordered_multiset&, const type_identity_t<Allocator>&);
constexpr unordered_multiset(unordered_multiset&&, const type_identity_t<Allocator>&);
constexpr unordered_multiset(initializer_list<value_type> il,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
constexpr unordered_multiset(size_type n, const allocator_type& a)
: unordered_multiset(n, hasher(), key_equal(), a) { }
constexpr unordered_multiset(size_type n, const hasher& hf, const allocator_type& a)
: unordered_multiset(n, hf, key_equal(), a) { }
template<class InputIterator>
constexpr unordered_multiset(InputIterator f, InputIterator l, size_type n, const allocator_type& a)
: unordered_multiset(f, l, n, hasher(), key_equal(), a) { }
template<class InputIterator>
constexpr unordered_multiset(InputIterator f, InputIterator l, size_type n, const hasher& hf,
const allocator_type& a)
: unordered_multiset(f, l, n, hf, key_equal(), a) { }
template<container-compatible-range<value_type> R>
constexpr unordered_multiset(from_range_t, R&& rg, size_type n, const allocator_type& a)
: unordered_multiset(from_range, std::forward<R>(rg),
n, hasher(), key_equal(), a) { }
template<container-compatible-range<value_type> R>
constexpr unordered_multiset(from_range_t, R&& rg, size_type n, const hasher& hf,
const allocator_type& a)
: unordered_multiset(from_range, std::forward<R>(rg), n, hf, key_equal(), a) { }
constexpr unordered_multiset(initializer_list<value_type> il, size_type n, const allocator_type& a)
: unordered_multiset(il, n, hasher(), key_equal(), a) { }
constexpr unordered_multiset(initializer_list<value_type> il, size_type n, const hasher& hf,
const allocator_type& a)
: unordered_multiset(il, n, hf, key_equal(), a) { }
constexpr ~unordered_multiset();
constexpr unordered_multiset& operator=(const unordered_multiset&);
constexpr unordered_multiset& operator=(unordered_multiset&&)
noexcept(allocator_traits<Allocator>::is_always_equal::value &&
is_nothrow_move_assignable_v<Hash> &&
is_nothrow_move_assignable_v<Pred>);
constexpr unordered_multiset& operator=(initializer_list<value_type>);
constexpr allocator_type get_allocator() const noexcept;
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator cend() const noexcept;
constexpr bool empty() const noexcept;
constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;
template<class... Args> constexpr iterator emplace(Args&&... args);
template<class... Args> constexpr iterator emplace_hint(const_iterator position, Args&&... args);
constexpr iterator insert(const value_type& obj);
constexpr iterator insert(value_type&& obj);
constexpr iterator insert(const_iterator hint, const value_type& obj);
constexpr iterator insert(const_iterator hint, value_type&& obj);
template<class InputIterator> constexpr void insert(InputIterator first, InputIterator last);
template<container-compatible-range<value_type> R>
constexpr void insert_range(R&& rg);
constexpr void insert(initializer_list<value_type>);
constexpr node_type extract(const_iterator position);
constexpr node_type extract(const key_type& x);
template<class K> constexpr node_type extract(K&& x);
constexpr iterator insert(node_type&& nh);
constexpr iterator insert(const_iterator hint, node_type&& nh);
constexpr iterator erase(iterator position)
requires (!same_as<iterator, const_iterator>);
constexpr iterator erase(const_iterator position);
constexpr size_type erase(const key_type& k);
template<class K> constexpr size_type erase(K&& x);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void swap(unordered_multiset&)
noexcept(allocator_traits<Allocator>::is_always_equal::value &&
is_nothrow_swappable_v<Hash> &&
is_nothrow_swappable_v<Pred>);
constexpr void clear() noexcept;
template<class H2, class P2>
constexpr void merge(unordered_multiset<Key, H2, P2, Allocator>& source);
template<class H2, class P2>
constexpr void merge(unordered_multiset<Key, H2, P2, Allocator>&& source);
template<class H2, class P2>
constexpr void merge(unordered_set<Key, H2, P2, Allocator>& source);
template<class H2, class P2>
constexpr void merge(unordered_set<Key, H2, P2, Allocator>&& source);
constexpr hasher hash_function() const;
constexpr key_equal key_eq() const;
constexpr iterator find(const key_type& k);
constexpr const_iterator find(const key_type& k) const;
template<class K>
constexpr iterator find(const K& k);
template<class K>
constexpr const_iterator find(const K& k) const;
constexpr size_type count(const key_type& k) const;
template<class K>
constexpr size_type count(const K& k) const;
constexpr bool contains(const key_type& k) const;
template<class K>
constexpr bool contains(const K& k) const;
constexpr pair<iterator, iterator> equal_range(const key_type& k);
constexpr pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
template<class K>
constexpr pair<iterator, iterator> equal_range(const K& k);
template<class K>
constexpr pair<const_iterator, const_iterator> equal_range(const K& k) const;
constexpr size_type bucket_count() const noexcept;
constexpr size_type max_bucket_count() const noexcept;
constexpr size_type bucket_size(size_type n) const;
constexpr size_type bucket(const key_type& k) const;
template<class K> constexpr size_type bucket(const K& k) const;
constexpr local_iterator begin(size_type n);
constexpr const_local_iterator begin(size_type n) const;
constexpr local_iterator end(size_type n);
constexpr const_local_iterator end(size_type n) const;
constexpr const_local_iterator cbegin(size_type n) const;
constexpr const_local_iterator cend(size_type n) const;
constexpr float load_factor() const noexcept;
constexpr float max_load_factor() const noexcept;
constexpr void max_load_factor(float z);
constexpr void rehash(size_type n);
constexpr void reserve(size_type n);
};
template<class InputIterator,
class Hash = hash<iter-value-type<InputIterator>>,
class Pred = equal_to<iter-value-type<InputIterator>>,
class Allocator = allocator<iter-value-type<InputIterator>>>
unordered_multiset(InputIterator, InputIterator, see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_multiset<iter-value-type<InputIterator>,
Hash, Pred, Allocator>;
template<ranges::input_range R,
class Hash = hash<ranges::range_value_t<R>>,
class Pred = equal_to<ranges::range_value_t<R>>,
class Allocator = allocator<ranges::range_value_t<R>>>
unordered_multiset(from_range_t, R&&, typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_multiset<ranges::range_value_t<R>, Hash, Pred, Allocator>;
template<class T, class Hash = hash<T>,
class Pred = equal_to<T>, class Allocator = allocator<T>>
unordered_multiset(initializer_list<T>, typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_multiset<T, Hash, Pred, Allocator>;
template<class InputIterator, class Allocator>
unordered_multiset(InputIterator, InputIterator, typename see below::size_type, Allocator)
-> unordered_multiset<iter-value-type<InputIterator>,
hash<iter-value-type<InputIterator>>,
equal_to<iter-value-type<InputIterator>>,
Allocator>;
template<class InputIterator, class Hash, class Allocator>
unordered_multiset(InputIterator, InputIterator, typename see below::size_type,
Hash, Allocator)
-> unordered_multiset<iter-value-type<InputIterator>, Hash,
equal_to<iter-value-type<InputIterator>>,
Allocator>;
template<ranges::input_range R, class Allocator>
unordered_multiset(from_range_t, R&&, typename see below::size_type, Allocator)
-> unordered_multiset<ranges::range_value_t<R>, hash<ranges::range_value_t<R>>,
equal_to<ranges::range_value_t<R>>, Allocator>;
template<ranges::input_range R, class Allocator>
unordered_multiset(from_range_t, R&&, Allocator)
-> unordered_multiset<ranges::range_value_t<R>, hash<ranges::range_value_t<R>>,
equal_to<ranges::range_value_t<R>>, Allocator>;
template<ranges::input_range R, class Hash, class Allocator>
unordered_multiset(from_range_t, R&&, typename see below::size_type, Hash, Allocator)
-> unordered_multiset<ranges::range_value_t<R>, Hash, equal_to<ranges::range_value_t<R>>,
Allocator>;
template<class T, class Allocator>
unordered_multiset(initializer_list<T>, typename see below::size_type, Allocator)
-> unordered_multiset<T, hash<T>, equal_to<T>, Allocator>;
template<class T, class Hash, class Allocator>
unordered_multiset(initializer_list<T>, typename see below::size_type, Hash, Allocator)
-> unordered_multiset<T, Hash, equal_to<T>, Allocator>;
}
A
size_type parameter type in an
unordered_multiset deduction guide
refers to the
size_type member type of
the type deduced by the deduction guide
.constexpr unordered_multiset() : unordered_multiset(size_type(see below)) { }
constexpr explicit unordered_multiset(size_type n,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
Effects: Constructs an empty
unordered_multiset using the
specified hash function, key equality predicate, and allocator, and
using at least
n buckets
. For the default constructor,
the number of buckets is
implementation-defined
. max_load_factor() returns
1.0. template<class InputIterator>
constexpr unordered_multiset(InputIterator f, InputIterator l,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
template<container-compatible-range<value_type> R>
constexpr unordered_multiset(from_range_t, R&& rg,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
constexpr unordered_multiset(initializer_list<value_type> il,
size_type n = see below,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& a = allocator_type());
Effects: Constructs an empty
unordered_multiset using the
specified hash function, key equality predicate, and allocator, and
using at least
n buckets
. If
n is not
provided, the number of buckets is
implementation-defined
. Then
inserts elements from the range [
f, l),
rg, or
il,
respectively
. max_load_factor() returns
1.0. Complexity: Average case linear, worst case quadratic
. template<class K, class H, class P, class A, class Predicate>
constexpr typename unordered_multiset<K, H, P, A>::size_type
erase_if(unordered_multiset<K, H, P, A>& 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();
The headers
,
,
,
and
define the container adaptors
queue and
priority_queue,
stack,
flat_map and
flat_multimap,
and
flat_set and
flat_multiset,
respectively
.Each container adaptor takes
one or more template parameters
named
Container,
KeyContainer, or
MappedContainer
that denote the types of containers that the container adaptor adapts
. Each container adaptor has at least one constructor
that takes a reference argument to one or more such template parameters
. For each constructor reference argument to a container
C,
the constructor copies the container into the container adaptor
. If
C takes an allocator, then a compatible allocator may be passed in
to the adaptor's constructor
. Otherwise, normal copy or move construction is used for the container
argument
. For the container adaptors
that take a single container template parameter
Container,
the first template parameter
T of the container adaptor
shall denote the same type as
Container::value_type.For container adaptors, no
swap function throws an exception unless that
exception is thrown by the swap of the adaptor's
Container,
KeyContainer,
MappedContainer, or
Compare object (if any)
.A constructor template of a container adaptor
shall not participate in overload resolution
if it has an
InputIterator template parameter and
a type that does not qualify as an input iterator is deduced for that parameter
.For container adaptors that have them,
the
insert,
emplace, and
erase members
affect the validity of iterators, references, and pointers
to the adaptor's container(s) in the same way that
the containers' respective
insert,
emplace, and
erase members do
. [
Example 1:
A call to
flat_map<Key, T>::insert
can invalidate all iterators to the
flat_map. —
end example]
A deduction guide for a container adaptor shall not participate in overload resolution if any of the following are true:
It has an
InputIterator template parameter and a type that does not qualify as an input iterator is deduced for that parameter
.It has a
Compare template parameter and a type that qualifies as an allocator is deduced for that parameter
.It has a
Container,
KeyContainer, or
MappedContainer template parameter and a type that qualifies as an allocator is deduced for that parameter
.It has no
Container,
KeyContainer, or
MappedContainer template parameter, and it has an
Allocator template parameter, and a type that does not qualify as an allocator is deduced for that parameter
.It has both
Container and
Allocator template parameters, and
uses_allocator_v<Container, Allocator> is
false.It has both
KeyContainer and
Allocator template parameters, and
uses_allocator_v<KeyContainer, Allocator> is
false.It has both
KeyContainer and
Compare template parameters, and
is_invocable_v<const Compare&,
const typename KeyContainer::value_type&,
const typename KeyContainer::value_type&>
is not a valid expression or is
false.It has both
MappedContainer and
Allocator template parameters, and
uses_allocator_v<MappedContainer, Allocator> is
false.
The exposition-only alias template
iter-value-type
defined in
[sequences.general] and
the exposition-only alias templates
iter-key-type,
iter-mapped-type,
range-key-type, and
range-mapped-type
defined in
[associative.general]
may appear in deduction guides for container adaptors
.The following exposition-only alias template
may appear in deduction guides for container adaptors:
template<class Allocator, class T>
using alloc-rebind =
typename allocator_traits<Allocator>::template rebind_alloc<T>;
#include <compare>
#include <initializer_list>
namespace std {
template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>>
class flat_set;
struct sorted_unique_t { explicit sorted_unique_t() = default; };
inline constexpr sorted_unique_t sorted_unique{};
template<class Key, class Compare, class KeyContainer, class Allocator>
struct uses_allocator<flat_set<Key, Compare, KeyContainer>, Allocator>;
template<class Key, class Compare, class KeyContainer, class Predicate>
constexpr typename flat_set<Key, Compare, KeyContainer>::size_type
erase_if(flat_set<Key, Compare, KeyContainer>& c, Predicate pred);
template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>>
class flat_multiset;
struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; };
inline constexpr sorted_equivalent_t sorted_equivalent{};
template<class Key, class Compare, class KeyContainer, class Allocator>
struct uses_allocator<flat_multiset<Key, Compare, KeyContainer>, Allocator>;
template<class Key, class Compare, class KeyContainer, class Predicate>
constexpr typename flat_multiset<Key, Compare, KeyContainer>::size_type
erase_if(flat_multiset<Key, Compare, KeyContainer>& c, Predicate pred);
}
Any sequence container supporting operations
front(),
back(),
push_back()
and
pop_front()
can be used to instantiate
queue. namespace std {
template<class T, class Container = deque<T>>
class queue {
public:
using value_type = typename Container::value_type;
using reference = typename Container::reference;
using const_reference = typename Container::const_reference;
using size_type = typename Container::size_type;
using container_type = Container;
protected:
Container c;
public:
constexpr queue() : queue(Container()) {}
constexpr explicit queue(const Container&);
constexpr explicit queue(Container&&);
template<class InputIterator> constexpr queue(InputIterator first, InputIterator last);
template<container-compatible-range<T> R> constexpr queue(from_range_t, R&& rg);
template<class Alloc> explicit constexpr queue(const Alloc&);
template<class Alloc> constexpr queue(const Container&, const Alloc&);
template<class Alloc> constexpr queue(Container&&, const Alloc&);
template<class Alloc> constexpr queue(const queue&, const Alloc&);
template<class Alloc> constexpr queue(queue&&, const Alloc&);
template<class InputIterator, class Alloc>
constexpr queue(InputIterator first, InputIterator last, const Alloc&);
template<container-compatible-range<T> R, class Alloc>
constexpr queue(from_range_t, R&& rg, const Alloc&);
constexpr bool empty() const { return c.empty(); }
constexpr size_type size() const { return c.size(); }
constexpr reference front() { return c.front(); }
constexpr const_reference front() const { return c.front(); }
constexpr reference back() { return c.back(); }
constexpr const_reference back() const { return c.back(); }
constexpr void push(const value_type& x) { c.push_back(x); }
constexpr void push(value_type&& x) { c.push_back(std::move(x)); }
template<container-compatible-range<T> R> constexpr void push_range(R&& rg);
template<class... Args>
constexpr decltype(auto) emplace(Args&&... args)
{ return c.emplace_back(std::forward<Args>(args)...); }
constexpr void pop() { c.pop_front(); }
constexpr void swap(queue& q) noexcept(is_nothrow_swappable_v<Container>)
{ using std::swap; swap(c, q.c); }
};
template<class Container>
queue(Container) -> queue<typename Container::value_type, Container>;
template<class InputIterator>
queue(InputIterator, InputIterator) -> queue<iter-value-type<InputIterator>>;
template<ranges::input_range R>
queue(from_range_t, R&&) -> queue<ranges::range_value_t<R>>;
template<class Container, class Allocator>
queue(Container, Allocator) -> queue<typename Container::value_type, Container>;
template<class InputIterator, class Allocator>
queue(InputIterator, InputIterator, Allocator)
-> queue<iter-value-type<InputIterator>, deque<iter-value-type<InputIterator>,
Allocator>>;
template<ranges::input_range R, class Allocator>
queue(from_range_t, R&&, Allocator)
-> queue<ranges::range_value_t<R>, deque<ranges::range_value_t<R>, Allocator>>;
template<class T, class Container, class Alloc>
struct uses_allocator<queue<T, Container>, Alloc>
: uses_allocator<Container, Alloc>::type { };
}
constexpr explicit queue(const Container& cont);
Effects: Initializes
c with
cont. constexpr explicit queue(Container&& cont);
Effects: Initializes
c with
std::move(cont). template<class InputIterator>
constexpr queue(InputIterator first, InputIterator last);
Effects: Initializes
c with
first as the first argument and
last as the second argument
. Effects: Initializes
c with
ranges::to<Container>(std::forward<R>(rg)). If
uses_allocator_v<container_type, Alloc> is
false
the constructors in this subclause shall not participate in overload resolution
.template<class Alloc> constexpr explicit queue(const Alloc& a);
Effects: Initializes
c with
a. template<class Alloc> constexpr queue(const container_type& cont, const Alloc& a);
Effects: Initializes
c with
cont as the first argument and
a
as the second argument
. template<class Alloc> constexpr queue(container_type&& cont, const Alloc& a);
Effects: Initializes
c with
std::move(cont) as the first argument and
a
as the second argument
. template<class Alloc> constexpr queue(const queue& q, const Alloc& a);
Effects: Initializes
c with
q.c as the first argument and
a as the
second argument
. template<class Alloc> constexpr queue(queue&& q, const Alloc& a);
Effects: Initializes
c with
std::move(q.c) as the first argument and
a
as the second argument
. template<class InputIterator, class Alloc>
constexpr queue(InputIterator first, InputIterator last, const Alloc& alloc);
Effects: Initializes
c with
first as the first argument,
last as the second argument, and
alloc as the third argument
. Effects: Initializes
c with
ranges::to<Container>(std::forward<R>(rg), a). Effects: Equivalent to
c.append_range(std::forward<R>(rg))
if that is a valid expression,
otherwise
ranges::copy(rg, back_inserter(c)). template<class T, class Container>
constexpr bool operator==(const queue<T, Container>& x, const queue<T, Container>& y);
template<class T, class Container>
constexpr bool operator!=(const queue<T, Container>& x, const queue<T, Container>& y);
template<class T, class Container>
constexpr bool operator< (const queue<T, Container>& x, const queue<T, Container>& y);
template<class T, class Container>
constexpr bool operator> (const queue<T, Container>& x, const queue<T, Container>& y);
template<class T, class Container>
constexpr bool operator<=(const queue<T, Container>& x, const queue<T, Container>& y);
template<class T, class Container>
constexpr bool operator>=(const queue<T, Container>& x,
const queue<T, Container>& y);
template<class T, three_way_comparable Container>
constexpr compare_three_way_result_t<Container>
operator<=>(const queue<T, Container>& x, const queue<T, Container>& y);
template<class T, class Container>
constexpr void swap(queue<T, Container>& x, queue<T, Container>& y) noexcept(noexcept(x.swap(y)));
Constraints:
is_swappable_v<Container> is
true. Effects: As if by
x.swap(y). Any sequence container with random access iterator and supporting operations
front(),
push_back()
and
pop_back()
can be used to instantiate
priority_queue. Instantiating
priority_queue
also involves supplying a function or function object for making
priority comparisons; the library assumes that the function or function
object defines a
strict weak ordering.namespace std {
template<class T, class Container = vector<T>,
class Compare = less<typename Container::value_type>>
class priority_queue {
public:
using value_type = typename Container::value_type;
using reference = typename Container::reference;
using const_reference = typename Container::const_reference;
using size_type = typename Container::size_type;
using container_type = Container;
using value_compare = Compare;
protected:
Container c;
Compare comp;
public:
constexpr priority_queue() : priority_queue(Compare()) {}
constexpr explicit priority_queue(const Compare& x) : priority_queue(x, Container()) {}
constexpr priority_queue(const Compare& x, const Container&);
constexpr priority_queue(const Compare& x, Container&&);
template<class InputIterator>
constexpr priority_queue(InputIterator first, InputIterator last, const Compare& x = Compare());
template<class InputIterator>
constexpr priority_queue(InputIterator first, InputIterator last, const Compare& x,
const Container&);
template<class InputIterator>
constexpr priority_queue(InputIterator first, InputIterator last, const Compare& x,
Container&&);
template<container-compatible-range<T> R>
constexpr priority_queue(from_range_t, R&& rg, const Compare& x = Compare());
template<class Alloc> constexpr explicit priority_queue(const Alloc&);
template<class Alloc> constexpr priority_queue(const Compare&, const Alloc&);
template<class Alloc> constexpr priority_queue(const Compare&, const Container&, const Alloc&);
template<class Alloc> constexpr priority_queue(const Compare&, Container&&, const Alloc&);
template<class Alloc> constexpr priority_queue(const priority_queue&, const Alloc&);
template<class Alloc> constexpr priority_queue(priority_queue&&, const Alloc&);
template<class InputIterator, class Alloc>
constexpr priority_queue(InputIterator, InputIterator, const Alloc&);
template<class InputIterator, class Alloc>
constexpr priority_queue(InputIterator, InputIterator, const Compare&, const Alloc&);
template<class InputIterator, class Alloc>
constexpr priority_queue(InputIterator, InputIterator, const Compare&, const Container&,
const Alloc&);
template<class InputIterator, class Alloc>
constexpr priority_queue(InputIterator, InputIterator, const Compare&, Container&&, const Alloc&);
template<container-compatible-range<T> R, class Alloc>
constexpr priority_queue(from_range_t, R&& rg, const Compare&, const Alloc&);
template<container-compatible-range<T> R, class Alloc>
constexpr priority_queue(from_range_t, R&& rg, const Alloc&);
constexpr bool empty() const { return c.empty(); }
constexpr size_type size() const { return c.size(); }
constexpr const_reference top() const { return c.front(); }
constexpr void push(const value_type& x);
constexpr void push(value_type&& x);
template<container-compatible-range<T> R>
constexpr void push_range(R&& rg);
template<class... Args> constexpr void emplace(Args&&... args);
constexpr void pop();
constexpr void swap(priority_queue& q) noexcept(is_nothrow_swappable_v<Container> &&
is_nothrow_swappable_v<Compare>)
{ using std::swap; swap(c, q.c); swap(comp, q.comp); }
};
template<class Compare, class Container>
priority_queue(Compare, Container)
-> priority_queue<typename Container::value_type, Container, Compare>;
template<class InputIterator,
class Compare = less<iter-value-type<InputIterator>>,
class Container = vector<iter-value-type<InputIterator>>>
priority_queue(InputIterator, InputIterator, Compare = Compare(), Container = Container())
-> priority_queue<iter-value-type<InputIterator>, Container, Compare>;
template<ranges::input_range R, class Compare = less<ranges::range_value_t<R>>>
priority_queue(from_range_t, R&&, Compare = Compare())
-> priority_queue<ranges::range_value_t<R>, vector<ranges::range_value_t<R>>, Compare>;
template<class Compare, class Container, class Allocator>
priority_queue(Compare, Container, Allocator)
-> priority_queue<typename Container::value_type, Container, Compare>;
template<class InputIterator, class Allocator>
priority_queue(InputIterator, InputIterator, Allocator)
-> priority_queue<iter-value-type<InputIterator>,
vector<iter-value-type<InputIterator>, Allocator>,
less<iter-value-type<InputIterator>>>;
template<class InputIterator, class Compare, class Allocator>
priority_queue(InputIterator, InputIterator, Compare, Allocator)
-> priority_queue<iter-value-type<InputIterator>,
vector<iter-value-type<InputIterator>, Allocator>, Compare>;
template<class InputIterator, class Compare, class Container, class Allocator>
priority_queue(InputIterator, InputIterator, Compare, Container, Allocator)
-> priority_queue<typename Container::value_type, Container, Compare>;
template<ranges::input_range R, class Compare, class Allocator>
priority_queue(from_range_t, R&&, Compare, Allocator)
-> priority_queue<ranges::range_value_t<R>, vector<ranges::range_value_t<R>, Allocator>,
Compare>;
template<ranges::input_range R, class Allocator>
priority_queue(from_range_t, R&&, Allocator)
-> priority_queue<ranges::range_value_t<R>, vector<ranges::range_value_t<R>, Allocator>>;
template<class T, class Container, class Compare, class Alloc>
struct uses_allocator<priority_queue<T, Container, Compare>, Alloc>
: uses_allocator<Container, Alloc>::type { };
}
constexpr priority_queue(const Compare& x, const Container& y);
constexpr priority_queue(const Compare& x, Container&& y);
Effects: Initializes
comp with
x and
c with
y (copy constructing or move constructing as appropriate);
calls
make_heap(c.begin(), c.end(), comp). template<class InputIterator>
constexpr priority_queue(InputIterator first, InputIterator last, const Compare& x = Compare());
Effects: Initializes
c with
first as the first argument and
last as the second argument, and
initializes
comp with
x;
then calls
make_heap(c.begin(), c.end(), comp). template<class InputIterator>
constexpr priority_queue(InputIterator first, InputIterator last, const Compare& x, const Container& y);
template<class InputIterator>
constexpr priority_queue(InputIterator first, InputIterator last, const Compare& x, Container&& y);
Effects: Initializes
comp with
x and
c with
y (copy constructing or move constructing as appropriate);
calls
c.insert(c.end(), first, last);
and finally calls
make_heap(c.begin(), c.end(), comp). Effects: Initializes
comp with
x and
c with
ranges::to<Container>(std::forward<R>(rg)) and
finally calls
make_heap(c.begin(), c.end(), comp). If
uses_allocator_v<container_type, Alloc> is
false
the constructors in this subclause shall not participate in overload resolution
.template<class Alloc> constexpr explicit priority_queue(const Alloc& a);
Effects: Initializes
c with
a and value-initializes
comp. template<class Alloc> constexpr priority_queue(const Compare& compare, const Alloc& a);
Effects: Initializes
c with
a and initializes
comp with
compare. template<class Alloc>
constexpr priority_queue(const Compare& compare, const Container& cont, const Alloc& a);
Effects: Initializes
c with
cont as the first argument and
a as the second
argument, and initializes
comp with
compare;
calls
make_heap(c.begin(), c.end(), comp). template<class Alloc>
constexpr priority_queue(const Compare& compare, Container&& cont, const Alloc& a);
Effects: Initializes
c with
std::move(cont) as the first argument and
a
as the second argument, and initializes
comp with
compare;
calls
make_heap(c.begin(), c.end(), comp). template<class Alloc> constexpr priority_queue(const priority_queue& q, const Alloc& a);
Effects: Initializes
c with
q.c as the first argument and
a as
the second argument, and initializes
comp with
q.comp. template<class Alloc> constexpr priority_queue(priority_queue&& q, const Alloc& a);
Effects: Initializes
c with
std::move(q.c) as the first argument and
a
as the second argument, and initializes
comp with
std::move(q.comp). template<class InputIterator, class Alloc>
constexpr priority_queue(InputIterator first, InputIterator last, const Alloc& a);
Effects: Initializes
c with
first as the first argument,
last as the second argument, and
a as the third argument, and
value-initializes
comp;
calls
make_heap(c.begin(), c.end(), comp). template<class InputIterator, class Alloc>
constexpr priority_queue(InputIterator first, InputIterator last, const Compare& compare, const Alloc& a);
Effects: Initializes
c with
first as the first argument,
last as the second argument, and
a as the third argument, and
initializes
comp with
compare;
calls
make_heap(c.begin(), c.end(), comp). template<class InputIterator, class Alloc>
constexpr priority_queue(InputIterator first, InputIterator last, const Compare& compare,
const Container& cont, const Alloc& a);
Effects: Initializes
c with
cont as the first argument and
a as the second argument, and
initializes
comp with
compare;
calls
c.insert(c.end(), first, last); and
finally calls
make_heap(c.begin(), c.end(), comp). template<class InputIterator, class Alloc>
constexpr priority_queue(InputIterator first, InputIterator last, const Compare& compare, Container&& cont,
const Alloc& a);
Effects: Initializes
c with
std::move(cont) as the first argument and
a as the second argument, and
initializes
comp with
compare;
calls
c.insert(c.end(), first, last); and
finally calls
make_heap(c.begin(), c.end(), comp). template<container-compatible-range<T> R, class Alloc>
constexpr priority_queue(from_range_t, R&& rg, const Compare& compare, const Alloc& a);
Effects: Initializes
comp with
compare and
c with
ranges::to<Container>(std::forward<R>(rg), a);
calls
make_heap(c.begin(), c.end(), comp). Effects: Initializes
c with
ranges::to<Container>(std::forward<R>(rg), a);
calls
make_heap(c.begin(), c.end(), comp). constexpr void push(const value_type& x);
Effects: As if by:
c.push_back(x);
push_heap(c.begin(), c.end(), comp);
constexpr void push(value_type&& x);
Effects: As if by:
c.push_back(std::move(x));
push_heap(c.begin(), c.end(), comp);
Effects: Inserts all elements of
rg in
c via
c.append_range(std::forward<R>(rg)) if that is a valid expression, or
ranges::copy(rg, back_inserter(c)) otherwise
. Then restores the heap property as if by
make_heap(c.begin(), c.end(), comp).Postconditions:
is_heap(c.begin(), c.end(), comp) is
true. template<class... Args> constexpr void emplace(Args&&... args);
Effects: As if by:
c.emplace_back(std::forward<Args>(args)...);
push_heap(c.begin(), c.end(), comp);
Effects: As if by:
pop_heap(c.begin(), c.end(), comp);
c.pop_back();
template<class T, class Container, class Compare>
constexpr void swap(priority_queue<T, Container, Compare>& x,
priority_queue<T, Container, Compare>& y) noexcept(noexcept(x.swap(y)));
Constraints:
is_swappable_v<Container> is
true and
is_swappable_v<Compare> is
true. Effects: As if by
x.swap(y). Any sequence container supporting operations
back(),
push_back()
and
pop_back()
can be used to instantiate
stack. namespace std {
template<class T, class Container = deque<T>>
class stack {
public:
using value_type = typename Container::value_type;
using reference = typename Container::reference;
using const_reference = typename Container::const_reference;
using size_type = typename Container::size_type;
using container_type = Container;
protected:
Container c;
public:
constexpr stack() : stack(Container()) {}
constexpr explicit stack(const Container&);
constexpr explicit stack(Container&&);
template<class InputIterator> constexpr stack(InputIterator first, InputIterator last);
template<container-compatible-range<T> R> constexpr stack(from_range_t, R&& rg);
template<class Alloc> constexpr explicit stack(const Alloc&);
template<class Alloc> constexpr stack(const Container&, const Alloc&);
template<class Alloc> constexpr stack(Container&&, const Alloc&);
template<class Alloc> constexpr stack(const stack&, const Alloc&);
template<class Alloc> constexpr stack(stack&&, const Alloc&);
template<class InputIterator, class Alloc>
constexpr stack(InputIterator first, InputIterator last, const Alloc&);
template<container-compatible-range<T> R, class Alloc>
constexpr stack(from_range_t, R&& rg, const Alloc&);
constexpr bool empty() const { return c.empty(); }
constexpr size_type size() const { return c.size(); }
constexpr reference top() { return c.back(); }
constexpr const_reference top() const { return c.back(); }
constexpr void push(const value_type& x) { c.push_back(x); }
constexpr void push(value_type&& x) { c.push_back(std::move(x)); }
template<container-compatible-range<T> R>
constexpr void push_range(R&& rg);
template<class... Args>
constexpr decltype(auto) emplace(Args&&... args)
{ return c.emplace_back(std::forward<Args>(args)...); }
constexpr void pop() { c.pop_back(); }
constexpr void swap(stack& s) noexcept(is_nothrow_swappable_v<Container>)
{ using std::swap; swap(c, s.c); }
};
template<class Container>
stack(Container) -> stack<typename Container::value_type, Container>;
template<class InputIterator>
stack(InputIterator, InputIterator) -> stack<iter-value-type<InputIterator>>;
template<ranges::input_range R>
stack(from_range_t, R&&) -> stack<ranges::range_value_t<R>>;
template<class Container, class Allocator>
stack(Container, Allocator) -> stack<typename Container::value_type, Container>;
template<class InputIterator, class Allocator>
stack(InputIterator, InputIterator, Allocator)
-> stack<iter-value-type<InputIterator>, deque<iter-value-type<InputIterator>,
Allocator>>;
template<ranges::input_range R, class Allocator>
stack(from_range_t, R&&, Allocator)
-> stack<ranges::range_value_t<R>, deque<ranges::range_value_t<R>, Allocator>>;
template<class T, class Container, class Alloc>
struct uses_allocator<stack<T, Container>, Alloc>
: uses_allocator<Container, Alloc>::type { };
}
constexpr explicit stack(const Container& cont);
Effects: Initializes
c with
cont. constexpr explicit stack(Container&& cont);
Effects: Initializes
c with
std::move(cont). constexpr template<class InputIterator>
stack(InputIterator first, InputIterator last);
Effects: Initializes
c with
first as the first argument and
last as the second argument
. Effects: Initializes
c with
ranges::to<Container>(std::forward<R>(rg)). If
uses_allocator_v<container_type, Alloc> is
false
the constructors in this subclause shall not participate in overload resolution
.template<class Alloc> constexpr explicit stack(const Alloc& a);
Effects: Initializes
c with
a. template<class Alloc> constexpr stack(const container_type& cont, const Alloc& a);
Effects: Initializes
c with
cont as the first argument and
a as the
second argument
. template<class Alloc> constexpr stack(container_type&& cont, const Alloc& a);
Effects: Initializes
c with
std::move(cont) as the first argument and
a
as the second argument
. template<class Alloc> constexpr stack(const stack& s, const Alloc& a);
Effects: Initializes
c with
s.c as the first argument and
a
as the second argument
. template<class Alloc> constexpr stack(stack&& s, const Alloc& a);
Effects: Initializes
c with
std::move(s.c) as the first argument and
a
as the second argument
. template<class InputIterator, class Alloc>
constexpr stack(InputIterator first, InputIterator last, const Alloc& alloc);
Effects: Initializes
c with
first as the first argument,
last as the second argument, and
alloc as the third argument
. Effects: Initializes
c with
ranges::to<Container>(std::forward<R>(rg), a). Effects: Equivalent to
c.append_range(std::forward<R>(rg))
if that is a valid expression,
otherwise
ranges::copy(rg, back_inserter(c)). template<class T, class Container>
constexpr bool operator==(const stack<T, Container>& x, const stack<T, Container>& y);
template<class T, class Container>
constexpr bool operator!=(const stack<T, Container>& x, const stack<T, Container>& y);
template<class T, class Container>
constexpr bool operator< (const stack<T, Container>& x, const stack<T, Container>& y);
template<class T, class Container>
constexpr bool operator> (const stack<T, Container>& x, const stack<T, Container>& y);
template<class T, class Container>
constexpr bool operator<=(const stack<T, Container>& x, const stack<T, Container>& y);
template<class T, class Container>
constexpr bool operator>=(const stack<T, Container>& x, const stack<T, Container>& y);
template<class T, three_way_comparable Container>
constexpr compare_three_way_result_t<Container>
operator<=>(const stack<T, Container>& x, const stack<T, Container>& y);
template<class T, class Container>
constexpr void swap(stack<T, Container>& x, stack<T, Container>& y) noexcept(noexcept(x.swap(y)));
Constraints:
is_swappable_v<Container> is
true. Effects: As if by
x.swap(y). 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 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.
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
. [
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
.namespace std {
template<class Key, class T, class Compare = less<Key>,
class KeyContainer = vector<Key>, class MappedContainer = vector<T>>
class flat_map {
public:
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;
using const_iterator = implementation-defined;
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;
constexpr value_compare(key_compare c) : comp(c) { }
public:
constexpr 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;
};
constexpr flat_map() : flat_map(key_compare()) { }
constexpr explicit flat_map(const key_compare& comp)
: c(), compare(comp) { }
constexpr flat_map(key_container_type key_cont, mapped_container_type mapped_cont,
const key_compare& comp = key_compare());
constexpr flat_map(sorted_unique_t, key_container_type key_cont, mapped_container_type mapped_cont,
const key_compare& comp = key_compare());
template<class InputIterator>
constexpr flat_map(InputIterator first, InputIterator last, const key_compare& comp = key_compare())
: c(), compare(comp) { insert(first, last); }
template<class InputIterator>
constexpr flat_map(sorted_unique_t s, InputIterator first, InputIterator last,
const key_compare& comp = key_compare())
: c(), compare(comp) { insert(s, first, last); }
template<container-compatible-range<value_type> R>
constexpr flat_map(from_range_t fr, R&& rg)
: flat_map(fr, std::forward<R>(rg), key_compare()) { }
template<container-compatible-range<value_type> R>
constexpr flat_map(from_range_t, R&& rg, const key_compare& comp)
: flat_map(comp) { insert_range(std::forward<R>(rg)); }
constexpr flat_map(initializer_list<value_type> il, const key_compare& comp = key_compare())
: flat_map(il.begin(), il.end(), comp) { }
constexpr 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 Alloc>
constexpr explicit flat_map(const Alloc& a);
template<class Alloc>
constexpr flat_map(const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont,
const Alloc& a);
template<class Alloc>
constexpr flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont,
const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_map(sorted_unique_t, const key_container_type& key_cont,
const mapped_container_type& mapped_cont, const Alloc& a);
template<class Alloc>
constexpr flat_map(sorted_unique_t, const key_container_type& key_cont,
const mapped_container_type& mapped_cont,
const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_map(const flat_map&, const Alloc& a);
template<class Alloc>
constexpr flat_map(flat_map&&, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_map(InputIterator first, InputIterator last, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_map(InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_map(from_range_t, R&& rg, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_map(from_range_t, R&& rg, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_map(initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_map(initializer_list<value_type> il, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_map(sorted_unique_t, initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_map(sorted_unique_t, initializer_list<value_type> il,
const key_compare& comp, const Alloc& a);
constexpr flat_map& operator=(initializer_list<value_type>);
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
constexpr reverse_iterator rbegin() noexcept;
constexpr const_reverse_iterator rbegin() const noexcept;
constexpr reverse_iterator rend() noexcept;
constexpr const_reverse_iterator rend() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator cend() const noexcept;
constexpr const_reverse_iterator crbegin() const noexcept;
constexpr const_reverse_iterator crend() const noexcept;
[[nodiscard]] constexpr bool empty() const noexcept;
constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;
constexpr mapped_type& operator[](const key_type& x);
constexpr mapped_type& operator[](key_type&& x);
template<class K> constexpr mapped_type& operator[](K&& x);
constexpr mapped_type& at(const key_type& x);
constexpr const mapped_type& at(const key_type& x) const;
template<class K> constexpr mapped_type& at(const K& x);
template<class K> constexpr const mapped_type& at(const K& x) const;
template<class... Args> constexpr pair<iterator, bool> emplace(Args&&... args);
template<class... Args>
constexpr iterator emplace_hint(const_iterator position, Args&&... args);
constexpr pair<iterator, bool> insert(const value_type& x)
{ return emplace(x); }
constexpr pair<iterator, bool> insert(value_type&& x)
{ return emplace(std::move(x)); }
constexpr iterator insert(const_iterator position, const value_type& x)
{ return emplace_hint(position, x); }
constexpr iterator insert(const_iterator position, value_type&& x)
{ return emplace_hint(position, std::move(x)); }
template<class P> constexpr pair<iterator, bool> insert(P&& x);
template<class P>
constexpr iterator insert(const_iterator position, P&&);
template<class InputIterator>
constexpr void insert(InputIterator first, InputIterator last);
template<class InputIterator>
constexpr void insert(sorted_unique_t, InputIterator first, InputIterator last);
template<container-compatible-range<value_type> R>
constexpr void insert_range(R&& rg);
constexpr void insert(initializer_list<value_type> il)
{ insert(il.begin(), il.end()); }
constexpr void insert(sorted_unique_t s, initializer_list<value_type> il)
{ insert(s, il.begin(), il.end()); }
constexpr containers extract() &&;
constexpr void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont);
template<class... Args>
constexpr pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
template<class... Args>
constexpr pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
template<class K, class... Args>
constexpr pair<iterator, bool> try_emplace(K&& k, Args&&... args);
template<class... Args>
constexpr iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);
template<class... Args>
constexpr iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);
template<class K, class... Args>
constexpr iterator try_emplace(const_iterator hint, K&& k, Args&&... args);
template<class M>
constexpr pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);
template<class M>
constexpr pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);
template<class K, class M>
constexpr pair<iterator, bool> insert_or_assign(K&& k, M&& obj);
template<class M>
constexpr iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);
template<class M>
constexpr iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);
template<class K, class M>
constexpr iterator insert_or_assign(const_iterator hint, K&& k, M&& obj);
constexpr iterator erase(iterator position);
constexpr iterator erase(const_iterator position);
constexpr size_type erase(const key_type& x);
template<class K> constexpr size_type erase(K&& x);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void swap(flat_map& y) noexcept;
constexpr void clear() noexcept;
constexpr key_compare key_comp() const;
constexpr value_compare value_comp() const;
constexpr const key_container_type& keys() const noexcept { return c.keys; }
constexpr const mapped_container_type& values() const noexcept { return c.values; }
constexpr iterator find(const key_type& x);
constexpr const_iterator find(const key_type& x) const;
template<class K> constexpr iterator find(const K& x);
template<class K> constexpr const_iterator find(const K& x) const;
constexpr size_type count(const key_type& x) const;
template<class K> constexpr size_type count(const K& x) const;
constexpr bool contains(const key_type& x) const;
template<class K> constexpr bool contains(const K& x) const;
constexpr iterator lower_bound(const key_type& x);
constexpr const_iterator lower_bound(const key_type& x) const;
template<class K> constexpr iterator lower_bound(const K& x);
template<class K> constexpr const_iterator lower_bound(const K& x) const;
constexpr iterator upper_bound(const key_type& x);
constexpr const_iterator upper_bound(const key_type& x) const;
template<class K> constexpr iterator upper_bound(const K& x);
template<class K> constexpr const_iterator upper_bound(const K& x) const;
constexpr pair<iterator, iterator> equal_range(const key_type& x);
constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
template<class K> constexpr pair<iterator, iterator> equal_range(const K& x);
template<class K> constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const;
constexpr friend bool operator==(const flat_map& x, const flat_map& y);
constexpr friend synth-three-way-result<value_type>
operator<=>(const flat_map& x, const flat_map& y);
constexpr friend void swap(flat_map& x, flat_map& y) noexcept
{ x.swap(y); }
private:
containers c;
key_compare compare;
struct key_equiv {
constexpr key_equiv(key_compare c) : comp(c) { }
constexpr 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
.constexpr 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
NlogN,
where
N is the value of
key_cont.size() before this call
. constexpr 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. The constructors in this subclause shall not participate in overload resolution
unless
uses_allocator_v<key_container_type, Alloc> is
true
and
uses_allocator_v<mapped_container_type, Alloc> is
true.template<class Alloc>
constexpr flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont,
const Alloc& a);
template<class Alloc>
constexpr flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont,
const key_compare& comp, const Alloc& a);
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
. template<class Alloc>
constexpr flat_map(sorted_unique_t s, const key_container_type& key_cont,
const mapped_container_type& mapped_cont, const Alloc& a);
template<class Alloc>
constexpr flat_map(sorted_unique_t s, const key_container_type& key_cont,
const mapped_container_type& mapped_cont, const key_compare& comp,
const Alloc& a);
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])
. template<class Alloc>
constexpr explicit flat_map(const Alloc& a);
template<class Alloc>
constexpr flat_map(const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_map(const flat_map&, const Alloc& a);
template<class Alloc>
constexpr flat_map(flat_map&&, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_map(InputIterator first, InputIterator last, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_map(InputIterator first, InputIterator last, const key_compare& comp, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_map(from_range_t, R&& rg, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_map(from_range_t, R&& rg, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_map(initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_map(initializer_list<value_type> il, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_map(sorted_unique_t, initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_map(sorted_unique_t, initializer_list<value_type> il,
const key_compare& comp, const Alloc& a);
Effects: Equivalent to the corresponding non-allocator constructors
except that
c.keys and
c.values are constructed
with uses-allocator construction (
[allocator.uses.construction])
. constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;
Returns:
min<size_type>(c.keys.max_size(), c.values.max_size()). constexpr mapped_type& operator[](const key_type& x);
Effects: Equivalent to: return try_emplace(x).first->second;
constexpr mapped_type& operator[](key_type&& x);
Effects: Equivalent to: return try_emplace(std::move(x)).first->second;
template<class K> constexpr 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;
constexpr mapped_type& at(const key_type& x);
constexpr 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
. template<class K> constexpr mapped_type& at(const K& x);
template<class K> constexpr 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
. template<class... Args> constexpr 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> constexpr pair<iterator, bool> insert(P&& x);
template<class P> constexpr 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>
constexpr 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 +
MlogM,
where
N is
size() before the operation and
M is
distance(first, last). Remarks: Since this operation performs an in-place merge, it may allocate memory
. template<class InputIterator>
constexpr void insert(sorted_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
. 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 +
MlogM,
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>
constexpr pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
template<class... Args>
constexpr pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
template<class... Args>
constexpr iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);
template<class... Args>
constexpr 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>
constexpr pair<iterator, bool> try_emplace(K&& k, Args&&... args);
template<class K, class... Args>
constexpr 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>
constexpr pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);
template<class M>
constexpr pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);
template<class M>
constexpr iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);
template<class M>
constexpr 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>
constexpr pair<iterator, bool> insert_or_assign(K&& k, M&& obj);
template<class K, class M>
constexpr 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
. constexpr 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);
Postconditions:
*this is emptied, even if the function exits via an exception
. constexpr 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);
template<class Key, class T, class Compare, class KeyContainer, class MappedContainer,
class Predicate>
constexpr 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
. 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]
A
flat_multimap is a container adaptor
that provides an associative container interface
that supports equivalent keys
(i.e., possibly containing multiple copies of the same key value) and
provides for fast retrieval of values of another type
T
based on the keys
. flat_multimap 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.
This means that a
flat_multimap supports
the
a_eq operations in
[associative.reqmts]
but not the
a_uniq operations
. For a
flat_multimap<Key, T>
the
key_type is
Key and
the
value_type is
pair<Key, T>. Except as otherwise noted,
operations on
flat_multimap are equivalent to those of
flat_map,
except that
flat_multimap operations
do not remove or replace elements with equal keys
. [
Example 1:
flat_multimap constructors and emplace do not erase
non-unique elements after sorting them
. —
end example]
A
flat_multimap 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.
[
Note 2:
This can result in the
flat_multimap being emptied
. —
end note]
Any type
C
that meets the sequence container requirements (
[sequence.reqmts])
can be used to instantiate
flat_multimap,
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
. [
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_equivalent_t argument
with a container, containers, or range
that are not sorted with respect to
key_comp() is undefined
.namespace std {
template<class Key, class T, class Compare = less<Key>,
class KeyContainer = vector<Key>, class MappedContainer = vector<T>>
class flat_multimap {
public:
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;
using const_iterator = implementation-defined;
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;
constexpr value_compare(key_compare c) : comp(c) { }
public:
constexpr 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;
};
constexpr flat_multimap() : flat_multimap(key_compare()) { }
constexpr explicit flat_multimap(const key_compare& comp)
: c(), compare(comp) { }
constexpr flat_multimap(key_container_type key_cont, mapped_container_type mapped_cont,
const key_compare& comp = key_compare());
constexpr flat_multimap(sorted_equivalent_t,
key_container_type key_cont, mapped_container_type mapped_cont,
const key_compare& comp = key_compare());
template<class InputIterator>
constexpr flat_multimap(InputIterator first, InputIterator last,
const key_compare& comp = key_compare())
: c(), compare(comp)
{ insert(first, last); }
template<class InputIterator>
constexpr flat_multimap(sorted_equivalent_t s, InputIterator first, InputIterator last,
const key_compare& comp = key_compare())
: c(), compare(comp) { insert(s, first, last); }
template<container-compatible-range<value_type> R>
constexpr flat_multimap(from_range_t fr, R&& rg)
: flat_multimap(fr, std::forward<R>(rg), key_compare()) { }
template<container-compatible-range<value_type> R>
constexpr flat_multimap(from_range_t, R&& rg, const key_compare& comp)
: flat_multimap(comp) { insert_range(std::forward<R>(rg)); }
constexpr flat_multimap(initializer_list<value_type> il, const key_compare& comp = key_compare())
: flat_multimap(il.begin(), il.end(), comp) { }
constexpr flat_multimap(sorted_equivalent_t s, initializer_list<value_type> il,
const key_compare& comp = key_compare())
: flat_multimap(s, il.begin(), il.end(), comp) { }
template<class Alloc>
constexpr explicit flat_multimap(const Alloc& a);
template<class Alloc>
constexpr flat_multimap(const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(const key_container_type& key_cont, const mapped_container_type& mapped_cont,
const Alloc& a);
template<class Alloc>
constexpr flat_multimap(const key_container_type& key_cont, const mapped_container_type& mapped_cont,
const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(sorted_equivalent_t, const key_container_type& key_cont,
const mapped_container_type& mapped_cont, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(sorted_equivalent_t, const key_container_type& key_cont,
const mapped_container_type& mapped_cont,
const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(const flat_multimap&, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(flat_multimap&&, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multimap(InputIterator first, InputIterator last, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multimap(InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last,
const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_multimap(from_range_t, R&& rg, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_multimap(from_range_t, R&& rg, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(initializer_list<value_type> il, const key_compare& comp,
const Alloc& a);
template<class Alloc>
constexpr flat_multimap(sorted_equivalent_t, initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(sorted_equivalent_t, initializer_list<value_type> il,
const key_compare& comp, const Alloc& a);
constexpr flat_multimap& operator=(initializer_list<value_type>);
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
constexpr reverse_iterator rbegin() noexcept;
constexpr const_reverse_iterator rbegin() const noexcept;
constexpr reverse_iterator rend() noexcept;
constexpr const_reverse_iterator rend() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator cend() const noexcept;
constexpr const_reverse_iterator crbegin() const noexcept;
constexpr const_reverse_iterator crend() const noexcept;
[[nodiscard]] constexpr bool empty() const noexcept;
constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;
template<class... Args> constexpr iterator emplace(Args&&... args);
template<class... Args>
constexpr iterator emplace_hint(const_iterator position, Args&&... args);
constexpr iterator insert(const value_type& x)
{ return emplace(x); }
constexpr iterator insert(value_type&& x)
{ return emplace(std::move(x)); }
constexpr iterator insert(const_iterator position, const value_type& x)
{ return emplace_hint(position, x); }
constexpr iterator insert(const_iterator position, value_type&& x)
{ return emplace_hint(position, std::move(x)); }
template<class P> constexpr iterator insert(P&& x);
template<class P>
constexpr iterator insert(const_iterator position, P&&);
template<class InputIterator>
constexpr void insert(InputIterator first, InputIterator last);
template<class InputIterator>
constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last);
template<container-compatible-range<value_type> R>
constexpr void insert_range(R&& rg);
constexpr void insert(initializer_list<value_type> il)
{ insert(il.begin(), il.end()); }
constexpr void insert(sorted_equivalent_t s, initializer_list<value_type> il)
{ insert(s, il.begin(), il.end()); }
constexpr containers extract() &&;
constexpr void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont);
constexpr iterator erase(iterator position);
constexpr iterator erase(const_iterator position);
constexpr size_type erase(const key_type& x);
template<class K> constexpr size_type erase(K&& x);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void swap(flat_multimap&) noexcept;
constexpr void clear() noexcept;
constexpr key_compare key_comp() const;
constexpr value_compare value_comp() const;
constexpr const key_container_type& keys() const noexcept { return c.keys; }
constexpr const mapped_container_type& values() const noexcept { return c.values; }
constexpr iterator find(const key_type& x);
constexpr const_iterator find(const key_type& x) const;
template<class K> constexpr iterator find(const K& x);
template<class K> constexpr const_iterator find(const K& x) const;
constexpr size_type count(const key_type& x) const;
template<class K> constexpr size_type count(const K& x) const;
constexpr bool contains(const key_type& x) const;
template<class K> constexpr bool contains(const K& x) const;
constexpr iterator lower_bound(const key_type& x);
constexpr const_iterator lower_bound(const key_type& x) const;
template<class K> constexpr iterator lower_bound(const K& x);
template<class K> constexpr const_iterator lower_bound(const K& x) const;
constexpr iterator upper_bound(const key_type& x);
constexpr const_iterator upper_bound(const key_type& x) const;
template<class K> constexpr iterator upper_bound(const K& x);
template<class K> constexpr const_iterator upper_bound(const K& x) const;
constexpr pair<iterator, iterator> equal_range(const key_type& x);
constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
template<class K>
constexpr pair<iterator, iterator> equal_range(const K& x);
template<class K>
constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const;
constexpr friend bool operator==(const flat_multimap& x, const flat_multimap& y);
constexpr friend synth-three-way-result<value_type>
operator<=>(const flat_multimap& x, const flat_multimap& y);
constexpr friend void swap(flat_multimap& x, flat_multimap& y) noexcept
{ x.swap(y); }
private:
containers c;
key_compare compare;
};
template<class KeyContainer, class MappedContainer,
class Compare = less<typename KeyContainer::value_type>>
flat_multimap(KeyContainer, MappedContainer, Compare = Compare())
-> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
Compare, KeyContainer, MappedContainer>;
template<class KeyContainer, class MappedContainer, class Allocator>
flat_multimap(KeyContainer, MappedContainer, Allocator)
-> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>;
template<class KeyContainer, class MappedContainer, class Compare, class Allocator>
flat_multimap(KeyContainer, MappedContainer, Compare, Allocator)
-> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
Compare, KeyContainer, MappedContainer>;
template<class KeyContainer, class MappedContainer,
class Compare = less<typename KeyContainer::value_type>>
flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Compare = Compare())
-> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
Compare, KeyContainer, MappedContainer>;
template<class KeyContainer, class MappedContainer, class Allocator>
flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Allocator)
-> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>;
template<class KeyContainer, class MappedContainer, class Compare, class Allocator>
flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Compare, Allocator)
-> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
Compare, KeyContainer, MappedContainer>;
template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>>
flat_multimap(InputIterator, InputIterator, Compare = Compare())
-> flat_multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Compare>;
template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>>
flat_multimap(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare())
-> flat_multimap<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_multimap(from_range_t, R&&, Compare = Compare(), Allocator = Allocator())
-> flat_multimap<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_multimap(from_range_t, R&&, Allocator)
-> flat_multimap<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_multimap(initializer_list<pair<Key, T>>, Compare = Compare())
-> flat_multimap<Key, T, Compare>;
template<class Key, class T, class Compare = less<Key>>
flat_multimap(sorted_equivalent_t, initializer_list<pair<Key, T>>, Compare = Compare())
-> flat_multimap<Key, T, Compare>;
template<class Key, class T, class Compare, class KeyContainer, class MappedContainer,
class Allocator>
struct uses_allocator<flat_multimap<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
.constexpr flat_multimap(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(). Complexity: Linear in
N if the container arguments are already sorted
with respect to
value_comp() and otherwise
NlogN,
where
N is the value of
key_cont.size() before this call
. constexpr flat_multimap(sorted_equivalent_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. The constructors in this subclause shall not participate in overload resolution
unless
uses_allocator_v<key_container_type, Alloc> is
true
and
uses_allocator_v<mapped_container_type, Alloc> is
true.constexpr template<class Alloc>
flat_multimap(const key_container_type& key_cont, const mapped_container_type& mapped_cont,
const Alloc& a);
template<class Alloc>
constexpr flat_multimap(const key_container_type& key_cont, const mapped_container_type& mapped_cont,
const key_compare& comp, const Alloc& a);
Effects: Equivalent to
flat_multimap(key_cont, mapped_cont) and
flat_multimap(key_cont, mapped_cont, comp), respectively,
except that
c.keys and
c.values are constructed
with uses-allocator construction (
[allocator.uses.construction])
. Complexity: Same as
flat_multimap(key_cont, mapped_cont) and
flat_multimap(key_cont, mapped_cont, comp), respectively
. template<class Alloc>
constexpr flat_multimap(sorted_equivalent_t s, const key_container_type& key_cont,
const mapped_container_type& mapped_cont, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(sorted_equivalent_t s, const key_container_type& key_cont,
const mapped_container_type& mapped_cont, const key_compare& comp,
const Alloc& a);
Effects: Equivalent to
flat_multimap(s, key_cont, mapped_cont) and
flat_multimap(s, key_cont, mapped_cont, comp), respectively,
except that
c.keys and
c.values are constructed
with uses-allocator construction (
[allocator.uses.construction])
. template<class Alloc>
constexpr explicit flat_multimap(const Alloc& a);
template<class Alloc>
constexpr flat_multimap(const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(const flat_multimap&, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(flat_multimap&&, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multimap(InputIterator first, InputIterator last, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multimap(InputIterator first, InputIterator last, const key_compare& comp,
const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last,
const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_multimap(from_range_t, R&& rg, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_multimap(from_range_t, R&& rg, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(initializer_list<value_type> il, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(sorted_equivalent_t, initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_multimap(sorted_equivalent_t, initializer_list<value_type> il,
const key_compare& comp, const Alloc& a);
Effects: Equivalent to the corresponding non-allocator constructors
except that
c.keys and
c.values are constructed
with uses-allocator construction (
[allocator.uses.construction])
. template<class Key, class T, class Compare, class KeyContainer, class MappedContainer,
class Predicate>
constexpr typename flat_multimap<Key, T, Compare, KeyContainer, MappedContainer>::size_type
erase_if(flat_multimap<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
. 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]
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 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]
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. [
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
.namespace std {
template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>>
class flat_set {
public:
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;
using const_iterator = implementation-defined;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using container_type = KeyContainer;
constexpr flat_set() : flat_set(key_compare()) { }
constexpr explicit flat_set(const key_compare& comp)
: c(), compare(comp) { }
constexpr explicit flat_set(container_type cont, const key_compare& comp = key_compare());
constexpr flat_set(sorted_unique_t, container_type cont, const key_compare& comp = key_compare())
: c(std::move(cont)), compare(comp) { }
template<class InputIterator>
constexpr flat_set(InputIterator first, InputIterator last, const key_compare& comp = key_compare())
: c(), compare(comp)
{ insert(first, last); }
template<class InputIterator>
constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last,
const key_compare& comp = key_compare())
: c(first, last), compare(comp) { }
template<container-compatible-range<value_type> R>
constexpr flat_set(from_range_t fr, R&& rg)
: flat_set(fr, std::forward<R>(rg), key_compare()) { }
template<container-compatible-range<value_type> R>
constexpr flat_set(from_range_t, R&& rg, const key_compare& comp)
: flat_set(comp)
{ insert_range(std::forward<R>(rg)); }
constexpr flat_set(initializer_list<value_type> il, const key_compare& comp = key_compare())
: flat_set(il.begin(), il.end(), comp) { }
constexpr 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 Alloc>
constexpr explicit flat_set(const Alloc& a);
template<class Alloc>
constexpr flat_set(const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_set(const container_type& cont, const Alloc& a);
template<class Alloc>
constexpr flat_set(const container_type& cont, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_set(sorted_unique_t, const container_type& cont, const Alloc& a);
template<class Alloc>
constexpr flat_set(sorted_unique_t, const container_type& cont,
const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_set(const flat_set&, const Alloc& a);
template<class Alloc>
constexpr flat_set(flat_set&&, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_set(InputIterator first, InputIterator last, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_set(InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_set(from_range_t, R&& rg, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_set(from_range_t, R&& rg, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_set(initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_set(initializer_list<value_type> il, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_set(sorted_unique_t, initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_set(sorted_unique_t, initializer_list<value_type> il,
const key_compare& comp, const Alloc& a);
constexpr flat_set& operator=(initializer_list<value_type>);
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
constexpr reverse_iterator rbegin() noexcept;
constexpr const_reverse_iterator rbegin() const noexcept;
constexpr reverse_iterator rend() noexcept;
constexpr const_reverse_iterator rend() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator cend() const noexcept;
constexpr const_reverse_iterator crbegin() const noexcept;
constexpr const_reverse_iterator crend() const noexcept;
[[nodiscard]] constexpr bool empty() const noexcept;
constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;
template<class... Args> constexpr pair<iterator, bool> emplace(Args&&... args);
template<class... Args>
constexpr iterator emplace_hint(const_iterator position, Args&&... args);
constexpr pair<iterator, bool> insert(const value_type& x)
{ return emplace(x); }
constexpr pair<iterator, bool> insert(value_type&& x)
{ return emplace(std::move(x)); }
template<class K> pair<iterator, bool> insert(K&& x);
constexpr iterator insert(const_iterator position, const value_type& x)
{ return emplace_hint(position, x); }
constexpr iterator insert(const_iterator position, value_type&& x)
{ return emplace_hint(position, std::move(x)); }
template<class K> constexpr iterator insert(const_iterator hint, K&& x);
template<class InputIterator>
constexpr void insert(InputIterator first, InputIterator last);
template<class InputIterator>
constexpr void insert(sorted_unique_t, InputIterator first, InputIterator last);
template<container-compatible-range<value_type> R>
constexpr void insert_range(R&& rg);
constexpr void insert(initializer_list<value_type> il)
{ insert(il.begin(), il.end()); }
constexpr void insert(sorted_unique_t s, initializer_list<value_type> il)
{ insert(s, il.begin(), il.end()); }
constexpr container_type extract() &&;
constexpr void replace(container_type&&);
constexpr iterator erase(iterator position);
constexpr iterator erase(const_iterator position);
constexpr size_type erase(const key_type& x);
template<class K> constexpr size_type erase(K&& x);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void swap(flat_set& y) noexcept;
constexpr void clear() noexcept;
constexpr key_compare key_comp() const;
constexpr value_compare value_comp() const;
constexpr iterator find(const key_type& x);
constexpr const_iterator find(const key_type& x) const;
template<class K> constexpr iterator find(const K& x);
template<class K> constexpr const_iterator find(const K& x) const;
constexpr size_type count(const key_type& x) const;
template<class K> constexpr size_type count(const K& x) const;
constexpr bool contains(const key_type& x) const;
template<class K> constexpr bool contains(const K& x) const;
constexpr iterator lower_bound(const key_type& x);
constexpr const_iterator lower_bound(const key_type& x) const;
template<class K> constexpr iterator lower_bound(const K& x);
template<class K> constexpr const_iterator lower_bound(const K& x) const;
constexpr iterator upper_bound(const key_type& x);
constexpr const_iterator upper_bound(const key_type& x) const;
template<class K> constexpr iterator upper_bound(const K& x);
template<class K> constexpr const_iterator upper_bound(const K& x) const;
constexpr pair<iterator, iterator> equal_range(const key_type& x);
constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
template<class K>
constexpr pair<iterator, iterator> equal_range(const K& x);
template<class K>
constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const;
constexpr friend bool operator==(const flat_set& x, const flat_set& y);
constexpr friend synth-three-way-result<value_type>
operator<=>(const flat_set& x, const flat_set& y);
constexpr friend void swap(flat_set& x, flat_set& y) noexcept { x.swap(y); }
private:
container_type c;
key_compare compare;
};
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>> { };
}
constexpr 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 already sorted with respect to
compare and
otherwise
NlogN, where
N is the value of
cont.size() before this call
. The constructors in this subclause shall not participate in overload resolution
unless
uses_allocator_v<container_type, Alloc> is
true.template<class Alloc>
constexpr flat_set(const container_type& cont, const Alloc& a);
template<class Alloc>
constexpr flat_set(const container_type& cont, const key_compare& comp, const Alloc& a);
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 Alloc>
constexpr flat_set(sorted_unique_t s, const container_type& cont, const Alloc& a);
template<class Alloc>
constexpr flat_set(sorted_unique_t s, const container_type& cont,
const key_compare& comp, const Alloc& a);
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])
. template<class Alloc>
constexpr explicit flat_set(const Alloc& a);
template<class Alloc>
constexpr flat_set(const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_set(const flat_set&, const Alloc& a);
template<class Alloc>
constexpr flat_set(flat_set&&, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_set(InputIterator first, InputIterator last, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_set(InputIterator first, InputIterator last, const key_compare& comp, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_set(from_range_t, R&& rg, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_set(from_range_t, R&& rg, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_set(initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_set(initializer_list<value_type> il, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_set(sorted_unique_t, initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_set(sorted_unique_t, initializer_list<value_type> il,
const key_compare& comp, const Alloc& a);
Effects: Equivalent to the corresponding non-allocator constructors
except that
c is constructed with
uses-allocator construction (
[allocator.uses.construction])
. template<class K> constexpr pair<iterator, bool> insert(K&& x);
template<class K> constexpr 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>
constexpr void insert(InputIterator first, InputIterator last);
Effects: Adds elements to c as if by:
c.insert(c.end(), first, last);
Then,
sorts the range of newly inserted elements with respect to
compare;
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 +
MlogM, where
N is
size() before the operation and
M is
distance(first, last). Remarks: Since this operation performs an in-place merge, it may allocate memory
. template<class InputIterator>
constexpr void insert(sorted_unique_t, InputIterator first, InputIterator last);
Effects: Equivalent to
insert(first, last). 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 +
MlogM, 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
. constexpr void swap(flat_set& y) noexcept;
Effects: Equivalent to:
ranges::swap(compare, y.compare);
ranges::swap(c, y.c);
Postconditions:
*this is emptied, even if the function exits via an exception
. constexpr 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);
template<class Key, class Compare, class KeyContainer, class Predicate>
constexpr 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
. 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]
A
flat_multiset is a container adaptor
that provides an associative container interface
that supports equivalent keys
(i.e., possibly containing multiple copies of the same key value) and
provides for fast retrieval of the keys themselves
. flat_multiset meets the requirements of
an associative container (
[associative.reqmts]), except that:
- it does not meet the requirements
related to node handles ([container.node.overview]),
- it does not meet the requirements related to iterator invalidation, and
- the time complexity of the operations
that insert or erase a single element from the
set is linear,
including the ones that take an insertion position iterator.
[
Note 1:
A
flat_multiset does not meet
the additional requirements of an allocator-aware container,
as described in
[container.alloc.reqmts]. —
end note]
This means that a
flat_multiset supports
the
a_eq operations in
[associative.reqmts]
but not the
a_uniq operations
. For a
flat_multiset<Key>,
both the
key_type and
value_type are
Key. Descriptions are provided here only for operations on
flat_multiset
that are not described in one of the general sections or
for operations where there is additional semantic information
.A
flat_multiset maintains the invariant
that the keys are sorted with respect to the comparison object
. [
Note 2:
This can result in the
flat_multiset's being emptied
. —
end note]
Any sequence container (
[sequence.reqmts])
supporting
Cpp17RandomAccessIterator
can be used to instantiate
flat_multiset. [
Note 3:
vector<bool> is not a sequence container
. —
end note]
The program is ill-formed if
Key is not the same type
as
KeyContainer::value_type.The effect of calling a constructor or member function
that takes a
sorted_equivalent_t argument with a range
that is not sorted with respect to
key_comp() is undefined
.namespace std {
template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>>
class flat_multiset {
public:
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;
using const_iterator = implementation-defined;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using container_type = KeyContainer;
constexpr flat_multiset() : flat_multiset(key_compare()) { }
constexpr explicit flat_multiset(const key_compare& comp)
: c(), compare(comp) { }
constexpr explicit flat_multiset(container_type cont, const key_compare& comp = key_compare());
constexpr flat_multiset(sorted_equivalent_t, container_type cont,
const key_compare& comp = key_compare())
: c(std::move(cont)), compare(comp) { }
template<class InputIterator>
constexpr flat_multiset(InputIterator first, InputIterator last,
const key_compare& comp = key_compare())
: c(), compare(comp)
{ insert(first, last); }
template<class InputIterator>
constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last,
const key_compare& comp = key_compare())
: c(first, last), compare(comp) { }
template<container-compatible-range<value_type> R>
constexpr flat_multiset(from_range_t fr, R&& rg)
: flat_multiset(fr, std::forward<R>(rg), key_compare()) { }
template<container-compatible-range<value_type> R>
constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp)
: flat_multiset(comp)
{ insert_range(std::forward<R>(rg)); }
constexpr flat_multiset(initializer_list<value_type> il, const key_compare& comp = key_compare())
: flat_multiset(il.begin(), il.end(), comp) { }
constexpr flat_multiset(sorted_equivalent_t s, initializer_list<value_type> il,
const key_compare& comp = key_compare())
: flat_multiset(s, il.begin(), il.end(), comp) { }
template<class Alloc>
constexpr explicit flat_multiset(const Alloc& a);
template<class Alloc>
constexpr flat_multiset(const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(const container_type& cont, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(const container_type& cont, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(sorted_equivalent_t, const container_type& cont, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(sorted_equivalent_t, const container_type& cont,
const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(const flat_multiset&, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(flat_multiset&&, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multiset(InputIterator first, InputIterator last, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multiset(InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last,
const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_multiset(from_range_t, R&& rg, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(initializer_list<value_type> il, const key_compare& comp,
const Alloc& a);
template<class Alloc>
constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il,
const key_compare& comp, const Alloc& a);
constexpr flat_multiset& operator=(initializer_list<value_type>);
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
constexpr reverse_iterator rbegin() noexcept;
constexpr const_reverse_iterator rbegin() const noexcept;
constexpr reverse_iterator rend() noexcept;
constexpr const_reverse_iterator rend() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator cend() const noexcept;
constexpr const_reverse_iterator crbegin() const noexcept;
constexpr const_reverse_iterator crend() const noexcept;
[[nodiscard]] constexpr bool empty() const noexcept;
constexpr size_type size() const noexcept;
constexpr size_type max_size() const noexcept;
template<class... Args> constexpr iterator emplace(Args&&... args);
template<class... Args>
constexpr iterator emplace_hint(const_iterator position, Args&&... args);
constexpr iterator insert(const value_type& x)
{ return emplace(x); }
constexpr iterator insert(value_type&& x)
{ return emplace(std::move(x)); }
constexpr iterator insert(const_iterator position, const value_type& x)
{ return emplace_hint(position, x); }
constexpr iterator insert(const_iterator position, value_type&& x)
{ return emplace_hint(position, std::move(x)); }
template<class InputIterator>
constexpr void insert(InputIterator first, InputIterator last);
template<class InputIterator>
constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last);
template<container-compatible-range<value_type> R>
constexpr void insert_range(R&& rg);
constexpr void insert(initializer_list<value_type> il)
{ insert(il.begin(), il.end()); }
constexpr void insert(sorted_equivalent_t s, initializer_list<value_type> il)
{ insert(s, il.begin(), il.end()); }
constexpr container_type extract() &&;
constexpr void replace(container_type&&);
constexpr iterator erase(iterator position);
constexpr iterator erase(const_iterator position);
constexpr size_type erase(const key_type& x);
template<class K> constexpr size_type erase(K&& x);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void swap(flat_multiset& y) noexcept;
constexpr void clear() noexcept;
constexpr key_compare key_comp() const;
constexpr value_compare value_comp() const;
constexpr iterator find(const key_type& x);
constexpr const_iterator find(const key_type& x) const;
template<class K> constexpr iterator find(const K& x);
template<class K> constexpr const_iterator find(const K& x) const;
constexpr size_type count(const key_type& x) const;
template<class K> constexpr size_type count(const K& x) const;
constexpr bool contains(const key_type& x) const;
template<class K> constexpr bool contains(const K& x) const;
constexpr iterator lower_bound(const key_type& x);
constexpr const_iterator lower_bound(const key_type& x) const;
template<class K> constexpr iterator lower_bound(const K& x);
template<class K> constexpr const_iterator lower_bound(const K& x) const;
constexpr iterator upper_bound(const key_type& x);
constexpr const_iterator upper_bound(const key_type& x) const;
template<class K> constexpr iterator upper_bound(const K& x);
template<class K> constexpr const_iterator upper_bound(const K& x) const;
constexpr pair<iterator, iterator> equal_range(const key_type& x);
constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
template<class K>
constexpr pair<iterator, iterator> equal_range(const K& x);
template<class K>
constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const;
constexpr friend bool operator==(const flat_multiset& x, const flat_multiset& y);
constexpr friend synth-three-way-result<value_type>
operator<=>(const flat_multiset& x, const flat_multiset& y);
constexpr friend void swap(flat_multiset& x, flat_multiset& y) noexcept
{ x.swap(y); }
private:
container_type c;
key_compare compare;
};
template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>>
flat_multiset(KeyContainer, Compare = Compare())
-> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>;
template<class KeyContainer, class Allocator>
flat_multiset(KeyContainer, Allocator)
-> flat_multiset<typename KeyContainer::value_type,
less<typename KeyContainer::value_type>, KeyContainer>;
template<class KeyContainer, class Compare, class Allocator>
flat_multiset(KeyContainer, Compare, Allocator)
-> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>;
template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>>
flat_multiset(sorted_equivalent_t, KeyContainer, Compare = Compare())
-> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>;
template<class KeyContainer, class Allocator>
flat_multiset(sorted_equivalent_t, KeyContainer, Allocator)
-> flat_multiset<typename KeyContainer::value_type,
less<typename KeyContainer::value_type>, KeyContainer>;
template<class KeyContainer, class Compare, class Allocator>
flat_multiset(sorted_equivalent_t, KeyContainer, Compare, Allocator)
-> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>;
template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>>
flat_multiset(InputIterator, InputIterator, Compare = Compare())
-> flat_multiset<iter-value-type<InputIterator>, Compare>;
template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>>
flat_multiset(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare())
-> flat_multiset<iter-value-type<InputIterator>, Compare>;
template<ranges::input_range R, class Compare = less<ranges::range_value_t<R>>,
class Allocator = allocator<ranges::range_value_t<R>>>
flat_multiset(from_range_t, R&&, Compare = Compare(), Allocator = Allocator())
-> flat_multiset<ranges::range_value_t<R>, Compare,
vector<ranges::range_value_t<R>,
alloc-rebind<Allocator, ranges::range_value_t<R>>>>;
template<ranges::input_range R, class Allocator>
flat_multiset(from_range_t, R&&, Allocator)
-> flat_multiset<ranges::range_value_t<R>, less<ranges::range_value_t<R>>,
vector<ranges::range_value_t<R>,
alloc-rebind<Allocator, ranges::range_value_t<R>>>>;
template<class Key, class Compare = less<Key>>
flat_multiset(initializer_list<Key>, Compare = Compare())
-> flat_multiset<Key, Compare>;
template<class Key, class Compare = less<Key>>
flat_multiset(sorted_equivalent_t, initializer_list<Key>, Compare = Compare())
-> flat_multiset<Key, Compare>;
template<class Key, class Compare, class KeyContainer, class Allocator>
struct uses_allocator<flat_multiset<Key, Compare, KeyContainer>, Allocator>
: bool_constant<uses_allocator_v<KeyContainer, Allocator>> { };
}
constexpr explicit flat_multiset(container_type cont, const key_compare& comp = key_compare());
Effects: Initializes
c with
std::move(cont) and
compare with
comp, and
sorts the range [
begin(), end()) with respect to
compare. Complexity: Linear in
N if
cont is already sorted with respect to
compare and
otherwise
NlogN, where
N is the value of
cont.size() before this call
. The constructors in this subclause shall not participate in overload resolution
unless
uses_allocator_v<container_type, Alloc> is
true.template<class Alloc>
constexpr flat_multiset(const container_type& cont, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(const container_type& cont, const key_compare& comp, const Alloc& a);
Effects: Equivalent to
flat_multiset(cont) and
flat_multiset(cont, comp), respectively,
except that
c is constructed with
uses-allocator construction (
[allocator.uses.construction])
. Complexity: Same as
flat_multiset(cont) and
flat_multiset(cont, comp), respectively
. template<class Alloc>
constexpr flat_multiset(sorted_equivalent_t s, const container_type& cont, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(sorted_equivalent_t s, const container_type& cont,
const key_compare& comp, const Alloc& a);
Effects: Equivalent to
flat_multiset(s, cont) and
flat_multiset(s, cont, comp), respectively,
except that
c is constructed with
uses-allocator construction (
[allocator.uses.construction])
. template<class Alloc>
constexpr explicit flat_multiset(const Alloc& a);
template<class Alloc>
constexpr flat_multiset(const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(const flat_multiset&, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(flat_multiset&&, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multiset(InputIterator first, InputIterator last, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multiset(InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, const Alloc& a);
template<class InputIterator, class Alloc>
constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last,
const key_compare& comp, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_multiset(from_range_t, R&& rg, const Alloc& a);
template<container-compatible-range<value_type> R, class Alloc>
constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(initializer_list<value_type> il, const key_compare& comp, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il, const Alloc& a);
template<class Alloc>
constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il,
const key_compare& comp, const Alloc& a);
Effects: Equivalent to the corresponding non-allocator constructors
except that
c is constructed with
uses-allocator construction (
[allocator.uses.construction])
. template<class... Args> constexpr iterator emplace(Args&&... args);
Constraints:
is_constructible_v<value_type, Args...> is
true. Effects: First, initializes an object t of type value_type
with std::forward<Args>(args)...,
then inserts t as if by:
auto it = ranges::upper_bound(c, t, compare);
c.insert(it, std::move(t));
Returns: An iterator that points to the inserted element
. template<class InputIterator>
constexpr void insert(InputIterator first, InputIterator last);
Effects: Adds elements to c as if by:
c.insert(c.end(), first, last);
Then, sorts the range of newly inserted elements with respect to
compare,
and merges the resulting sorted range and
the sorted range of pre-existing elements into a single sorted range
.Complexity:
N +
MlogM, where
N is
size() before the operation and
M
is
distance(first, last). Remarks: Since this operation performs an in-place merge, it may allocate memory
. template<class InputIterator>
constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last);
Effects: Equivalent to
insert(first, last). constexpr void swap(flat_multiset& y) noexcept;
Effects: Equivalent to:
ranges::swap(compare, y.compare);
ranges::swap(c, y.c);
Postconditions:
*this is emptied, even if the function exits via an exception
. constexpr void replace(container_type&& cont);
Preconditions: The elements of
cont are sorted with respect to
compare. Effects: Equivalent to: c = std::move(cont);
template<class Key, class Compare, class KeyContainer, class Predicate>
constexpr typename flat_multiset<Key, Compare, KeyContainer>::size_type
erase_if(flat_multiset<Key, Compare, KeyContainer>& c, Predicate pred);
Preconditions:
Key meets the
Cpp17MoveAssignable requirements
. Effects: Let
E be
bool(pred(as_const(e))). Erases all elements
e in
c for which
E holds
.Returns: The number of elements erased
. Complexity: Exactly
c.size() applications of the predicate
. 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]
Feature test macro
#define __cpp_lib_constexpr_constainers 2024??L