23.3.14.1 Partial class template specialization vector<bool, Allocator> [vector.bool.pspc]
23.5 Unordered associative containers [unord]
This Clause describes components that C++ programs may use to
organize collections of information
.The following subclauses describe
container requirements,
and components for
sequence containers and
associative containers,
as summarized in
Table 
74.Table 
74 — Containers library summary 
[tab:containers.summary]|  |  |  | 
|  |  |  | 
|  |  | <array>, <deque>, <forward_list>,
  <hive>, | 
|  |  | <inplace_vector>, <list>, <vector> | 
|  |  |  | 
|  | Unordered associative containers | <unordered_map>, <unordered_set> | 
|  |  | <queue>, <stack>, <flat_map>, <flat_set> | 
|  |  |  | 
Containers are objects that store other objects
.They control allocation and deallocation of these objects
through constructors, destructors, insert and erase operations
.All of the complexity requirements in this Clause are stated solely
in terms of the number of operations on the contained objects
.[
Example 1: 
The copy constructor of type
vector<vector<int>>
has linear complexity,
even though the complexity of copying each contained
vector<int>
is itself linear
. — 
end example]
Allocator-aware containers (
[container.alloc.reqmts])
other than 
basic_string construct elements using the function
allocator_traits<allocator_type>::rebind_traits<U>::construct
and destroy elements using the function
allocator_traits<allocator_type>::rebind_traits<U>::destroy (
[allocator.traits.members]),
where 
U is either 
allocator_type::value_type or
an internal type used by the container
.These functions are called only for the
container's element type, not for internal types used by the container
.[
Note 1: 
This
means, for example, that a node-based container would need to construct nodes containing
aligned buffers and call 
construct to place the element into the buffer
. — 
end note]
In 
[container.requirements.general],
- X denotes a container class containing objects of type T,
- a denotes a value of type X,
- b and c denote values of type (possibly const) X,
- i and j denote values of type (possibly const) X::iterator,
- u denotes an identifier,
- v denotes an lvalue of type (possibly const) X or
an rvalue of type const X,
- s and t denote non-const lvalues of type X, and
- rv denotes a non-const rvalue of type X.
A type 
X meets the 
container requirements
if the following types, statements, and expressions are well-formed and
have the specified semantics
.typename X::const_reference
Result: A type that meets the forward iterator requirements (
[forward.iterators])
with value type 
T.  The type 
X::iterator is convertible to 
X::const_iterator.typename X::const_iterator
Result: A type that meets the requirements of a constant iterator and
those of a forward iterator with value type 
T. typename X::difference_type
Result: A signed integer type,
identical to the difference type of
X::iterator and 
X::const_iterator. Result: An unsigned integer type
that can represent any non-negative value of 
X::difference_type. Postconditions: u.empty()
Preconditions: 
T is 
Cpp17CopyInsertable into 
X (see below)
. Postconditions: 
u is equal to the value that 
rv had before this construction
. Complexity: Linear for 
array and 
inplace_vector and constant for all other standard containers
. Effects: All existing elements of 
t are either move assigned to or destroyed
. Postconditions: If 
t and 
rv do not refer to the same object,
t is equal to the value that 
rv had before this assignment
. Effects: Destroys every element of 
a; any memory obtained is deallocated
. Result: 
iterator;
const_iterator for constant 
b. Returns: An iterator referring to the first element in the container
. Result: 
iterator;
const_iterator for constant 
b. Returns: An iterator which is the past-the-end value for the container
. Returns: const_cast<X const&>(b).begin()
Returns: const_cast<X const&>(b).end()
Constraints: 
X::iterator meets the random access iterator requirements
. Preconditions: 
T meets the 
Cpp17EqualityComparable requirements
. Returns: equal(c.begin(), c.end(), b.begin(), b.end())
Complexity: Constant if 
c.size() != b.size(), linear otherwise
. Remarks: 
== is an equivalence relation
. Effects: Equivalent to 
!(c == b). Effects: Exchanges the contents of 
t and 
s. Complexity: Linear for 
array and 
inplace_vector, and
constant for all other standard containers
. Effects: Equivalent to 
t.swap(s). Returns: 
distance(c.begin(), c.end()),
i.e., the number of elements in the container
. Remarks: The number of elements is defined by the rules of
constructors, inserts, and erases
. Returns: 
distance(begin(), end()) for the largest possible container
. Returns: c.begin() == c.end()
Remarks: If the container is empty, then 
c.empty() is 
true. In the expressions
i == j
i != j
i < j
i <= j
i >= j
i > j
i <=> j
i - j
where 
i and 
j denote objects of a container's 
iterator
type, either or both may be replaced by an object of the container's
const_iterator type referring to the same element with no change in semantics
.Unless otherwise specified, all containers defined in this Clause obtain memory
using an allocator (see 
[allocator.requirements])
.[
Note 2: 
In particular, containers and iterators do not store references
to allocated elements other than through the allocator's pointer type,
i.e., as objects of type 
P or
pointer_traits<P>::template rebind<unspecified>,
where 
P is 
allocator_traits<allocator_type>::pointer. — 
end note]
Copy constructors for these container types obtain an allocator by calling
allocator_traits<allocator_type>::select_on_container_copy_construction
on the allocator belonging to the container being copied
.Move constructors obtain an allocator by move construction from the allocator belonging to
the container being moved
.Such move construction of the allocator shall not exit via an
exception
.All other constructors for these container types take a
const allocator_type& argument
.[
Note 3: 
If an invocation of a constructor uses the default value of an optional
allocator argument, then the allocator type must support value-initialization
. — 
end note]
A copy of this allocator is used for any memory allocation and element construction
performed, by these constructors and by all member functions,
during the lifetime of each container object
or until the allocator is replaced
.The allocator may be replaced only via assignment or
swap().Allocator replacement is performed by
copy assignment, move assignment, or swapping of the allocator only if
- allocator_traits<allocator_type>::propagate_on_container_copy_assignment::value,
- allocator_traits<allocator_type>::propagate_on_container_move_assignment::value,
or
- allocator_traits<allocator_type>::propagate_on_container_swap::value
is 
true
within the implementation of the corresponding container operation
.In all container types defined in this Clause, the member 
get_allocator()
returns a copy of the allocator used to construct the container or, if that allocator
has been replaced, a copy of the most recent replacement
.The expression 
a.swap(b), for containers 
a and 
b of a standard
container type other than 
array and 
inplace_vector,
shall exchange the values of 
a and
b without invoking any move, copy, or swap operations on the individual
container elements
.Any 
Compare, 
Pred, or 
Hash types
belonging to 
a and 
b shall meet the 
Cpp17Swappable requirements
and shall be exchanged by calling 
swap
as described in 
[swappable.requirements].If
allocator_traits<allocator_type>::propagate_on_container_swap::value is
true, then
allocator_type shall meet the 
Cpp17Swappable requirements and
the allocators of 
a and 
b shall also be exchanged
by calling 
swap as described in 
[swappable.requirements].Otherwise, the allocators shall not be swapped, and the behavior is
undefined unless 
a.get_allocator() == b.get_allocator().Every iterator
referring to an element in one container before the swap shall refer to the same
element in the other container after the swap
.It is unspecified whether an iterator
with value 
a.end() before the swap will have value 
b.end() after the
swap
.Unless otherwise specified (see 
[associative.reqmts.except], 
[unord.req.except], 
[deque.modifiers], 
[inplace.vector.modifiers], and
[vector.modifiers])
all container types defined in this Clause meet
the following additional requirements:
- If an exception is thrown by an
 insert()-  or  emplace()- 
function while inserting a single element, that
function has no effects .
- If an exception is thrown by a
 push_back()- ,
 push_front()- ,
 emplace_back()- , or  emplace_front()- 
function, that function has no effects .
- No
 erase()- ,
 clear()- ,
 pop_back()- 
or
 pop_front()- 
function throws an exception .
- No copy constructor or assignment operator of a returned iterator
throws an exception .
- No
 swap()- 
function throws an exception .
- No
 swap()- 
function invalidates any references,
pointers, or iterators referring to the elements
of the containers being swapped .
- [ Note 4- :  - The  end()-  iterator does not refer to any element, so it can be invalidated .
-  —  end note- ] 
Unless otherwise specified (either explicitly or by defining a
function in terms of other functions), invoking a container member
function or passing a container as an argument to a library function
shall not invalidate iterators to, or change the values of, objects
within that container
.The behavior of certain container member functions and deduction guides
depends on whether types qualify as input iterators or allocators
.The extent to which an implementation determines that a type cannot be an input
iterator is unspecified, except that as a minimum integral types shall not qualify
as input iterators
.Likewise, the extent to which an implementation determines that a type cannot be
an allocator is unspecified, except that as a minimum a type 
A shall not qualify
as an allocator unless it meets both of the following conditions:
- The expression  declval<A&>().allocate(size_t{})- 
is well-formed when treated as an unevaluated operand .
A type 
X meets the 
reversible container requirements if
X meets the container requirements,
the iterator type of 
X belongs to the
bidirectional or random access iterator categories (
[iterator.requirements]),
and
the following types and expressions are well-formed and have
the specified semantics
.typename X::reverse_iterator
Result: The type 
reverse_iterator<X::iterator>,
an iterator type whose value type is 
T. typename X::const_reverse_iterator
Result: The type 
reverse_iterator<X::const_iterator>,
a constant iterator type whose value type is 
T. Result: 
reverse_iterator;
const_reverse_iterator for constant 
a. Returns: reverse_iterator(end())
Result: 
reverse_iterator;
const_reverse_iterator for constant 
a. Returns: reverse_iterator(begin())
Result: 
const_reverse_iterator. Returns: const_cast<X const&>(a).rbegin()
Result: 
const_reverse_iterator. Returns: const_cast<X const&>(a).rend()
The following operations are provided
for some types of containers but not others
.Those containers for which the
listed operations are provided shall implement the semantics as described
unless otherwise stated
.If the iterators passed to 
lexicographical_compare_three_way
meet the constexpr iterator requirements (
[iterator.requirements.general])
then the operations described below
are implemented by constexpr functions
.Result: 
synth-three-way-result<X::value_type>. Preconditions: Either 
T models 
three_way_comparable,
or 
< is defined for values of type (possibly const) 
T and
< is a total ordering relationship
. Returns: 
lexicographical_compare_three_way(a.begin(), a.end(),
b.begin(), b.end(),
synth-three-way)
[
Note 1: 
The algorithm 
lexicographical_compare_three_way
is defined in 
[algorithms]. — 
end note]
 Given an allocator type 
A
and given a container type 
X having a 
value_type identical to 
T
and an 
allocator_type identical to 
allocator_traits<A>::rebind_alloc<T>
and given an lvalue 
m of type 
A,
a pointer 
p of type 
T*,
an expression 
v that denotes
an lvalue of type 
T or 
const T or
an rvalue of type 
const T,
and an rvalue 
rv of type 
T,
the following terms are defined
.If 
X
is not allocator-aware or is a specialization of 
basic_string,
the terms below are defined as if 
A were
allocator<T> — no allocator object needs to be created
and user specializations of 
allocator<T> are not instantiated:
- T is Cpp17DefaultInsertable into X
means that the following expression is well-formed:
allocator_traits<A>::construct(m, p)
- An element of X is default-inserted if it is initialized
by evaluation of the expression
allocator_traits<A>::construct(m, p)
where p is the address of the uninitialized storage for the element
allocated within X.
- T is Cpp17MoveInsertable into X
means that the following expression
is well-formed:
allocator_traits<A>::construct(m, p, rv)
and its evaluation causes the following postcondition to hold: The value
of *p is equivalent to the value of rv before the evaluation. [ Note 1:  rv remains a valid object .
 Its state is unspecified .
 —  end note] 
- T is Cpp17CopyInsertable into X
means that, in addition to T being Cpp17MoveInsertable into
X, the following expression is well-formed:
allocator_traits<A>::construct(m, p, v)
and its evaluation causes the following postcondition to hold:
The value of v is unchanged and is equivalent to *p.
- T is
Cpp17EmplaceConstructible into X from args,
for zero
or more arguments args, means that the following expression is well-formed:
allocator_traits<A>::construct(m, p, args)
- T is
Cpp17Erasable from X
means that the following expression is well-formed:
allocator_traits<A>::destroy(m, p)
[
Note 2: 
A container calls 
allocator_traits<A>::construct(m, p, args)
to construct an element at 
p using 
args,
with 
m == get_allocator().The default 
construct in 
allocator will
call 
::new((void*)p) T(args),
but specialized allocators can choose a different definition
. — 
end note]
In this subclause,
- X denotes an allocator-aware container class
with a value_type of T using an allocator of type A,
- u denotes a variable,
- a and b denote non-const lvalues of type X,
- c denotes an lvalue of type const X,
- t denotes an lvalue or a const rvalue of type X,
- rv denotes a non-const rvalue of type X, and
- m is a value of type A.
A type 
X meets the allocator-aware container requirements
if 
X meets the container requirements and
the following types, statements, and expressions are well-formed and have
the specified semantics
.typename X::allocator_type
Mandates: 
allocator_type::value_type is the same as 
X::value_type. Preconditions: 
A meets the 
Cpp17DefaultConstructible requirements
. Postconditions: 
u.empty() returns 
true, 
u.get_allocator() == A(). Postconditions: 
u.empty() returns 
true, 
u.get_allocator() == m. Preconditions: 
T is 
Cpp17CopyInsertable into 
X. Postconditions: 
u == t, 
u.get_allocator() == m. Postconditions: 
u has the same elements as 
rv had before this construction;
the value of 
u.get_allocator() is the same as
the value of 
rv.get_allocator() before this construction
. Preconditions: 
T is 
Cpp17MoveInsertable into 
X. Postconditions: 
u has the same elements, or copies of the elements,
that 
rv had before this construction,
u.get_allocator() == m. Complexity: Constant if 
m == rv.get_allocator(), otherwise linear
. Preconditions: 
T is 
Cpp17CopyInsertable into 
X and
Cpp17CopyAssignable. Postconditions: 
a == t is 
true. Preconditions: If
allocator_traits<allocator_type>::propagate_on_container_move_assignment::value
is 
false,
T is 
Cpp17MoveInsertable into 
X and
Cpp17MoveAssignable. Effects: All existing elements of 
a are either move assigned to or destroyed
. Postconditions: If 
a and 
rv do not refer to the same object,
a is equal to the value that 
rv had before this assignment
. Effects: Exchanges the contents of 
a and 
b. For purposes of avoiding data races (
[res.on.data.races]), implementations shall
consider the following functions to be 
const: 
begin, 
end,
rbegin, 
rend, 
front, 
back, 
data, 
find,
lower_bound, 
upper_bound, 
equal_range, 
at and, except in
associative or unordered associative containers, 
operator[].Notwithstanding 
[res.on.data.races], implementations are required to avoid data
races when the contents of the contained object in different elements in the same
container, excepting 
vector<bool>, are modified concurrently
.[
Note 1: 
For a 
vector<int> x with a size greater than one, 
x[1] = 5
and 
*x.begin() = 10 can be executed concurrently without a data race, but
x[0] = 5 and 
*x.begin() = 10 executed concurrently can result in a data
race
.As an exception to the general rule, for a 
vector<bool> y, 
y[0] = true
can race with 
y[1] = true. — 
end note]
A sequence container organizes a finite set of objects, all of the same type, into a strictly
linear arrangement
.The library provides the following basic kinds of sequence containers:
vector, 
inplace_vector,
forward_list, 
list, and 
deque.In addition,
array and 
hive are provided as sequence containers
which provide limited sequence operations,
in 
array's case because it has a fixed number of elements, and
in 
hive's case because insertion order is unspecified
.The library also provides container adaptors that
make it easy to construct abstract data types,
such as 
stacks,
queues,
flat_maps,
flat_multimaps,
flat_sets, or
flat_multisets, out of
the basic sequence container kinds (or out of other program-defined sequence containers)
.In this subclause,
- X denotes a sequence container class, 
- a denotes a value of type X containing elements of type T, 
- u denotes the name of a variable being declared, 
- A-  denotes  X::allocator_type-  if
the  qualified-id X::allocator_type-  is valid and denotes a
type ( [temp.deduct]- ) and
 allocator<T>-  if it doesn't, 
 
- i and j
denote iterators that meet the Cpp17InputIterator requirements
and refer to elements implicitly convertible to value_type, 
- [i, j) denotes a valid range, 
- il designates an object of type initializer_list<value_type>, 
- n denotes a value of type X::size_type, 
- p denotes a valid constant iterator to a, 
- q denotes a valid dereferenceable constant iterator to a, 
- [q1, q2) denotes a valid range of constant iterators in a, 
- t denotes an lvalue or a const rvalue of X::value_type, and 
- rv-  denotes a non-const rvalue of  X::value_type.
 
- Args denotes a template parameter pack; 
- args-  denotes a function parameter pack with the pattern  Args&&.
 
The complexities of the expressions are sequence dependent
.A type 
X meets the 
sequence container requirements
if 
X meets the container requirements and
the following statements and expressions are well-formed and have
the specified semantics
.Preconditions: 
T is 
Cpp17CopyInsertable into 
X. Effects: Constructs a sequence container with 
n copies of 
t. Postconditions: 
distance(u.begin(), u.end()) == n is 
true. Preconditions: 
T is 
Cpp17EmplaceConstructible into 
X from 
*i.  For 
vector,
if the iterator does not meet
the 
Cpp17ForwardIterator requirements (
[forward.iterators]),
T is also 
Cpp17MoveInsertable into 
X.Effects: Constructs a sequence container equal to the range [
i, j)
.  Each iterator in the range [
i, j) is dereferenced exactly once
.Postconditions: 
distance(u.begin(), u.end()) == distance(i, j) is 
true. Preconditions: 
T is 
Cpp17EmplaceConstructible into 
X
from 
*ranges::begin(rg).  Effects: Constructs a sequence container equal to the range 
rg.  Each iterator in the range 
rg is dereferenced exactly once
.Recommended practice: If 
R models 
ranges::approximately_sized_range and
ranges::distance(rg) <= ranges::reserve_hint(rg) is 
true,
an implementation should not perform more than a single reallocation
. Postconditions: 
distance(begin(), end()) == ranges::distance(rg) is 
true. Effects: Equivalent to 
X(il.begin(), il.end()). Preconditions: 
T is 
Cpp17CopyInsertable into 
X and
Cpp17CopyAssignable. Effects: Assigns the range [
il.begin(), il.end()) into 
a.  All existing elements of 
a are either assigned to or destroyed
.Preconditions: 
T is 
Cpp17EmplaceConstructible into 
X from 
args.  For 
vector, 
inplace_vector, and 
deque,
T is also 
Cpp17MoveInsertable into 
X and
Cpp17MoveAssignable.Effects: Inserts an object of type 
T
constructed with 
std::forward<Args>(args)...
before 
p.  [
Note 1: 
args can directly or indirectly refer to a value in 
a.  — 
end note]
Returns: An iterator that points to the new element
. Preconditions: 
T is 
Cpp17CopyInsertable into 
X.  For 
vector, 
inplace_vector, and 
deque,
T is also 
Cpp17CopyAssignable.Effects: Inserts a copy of 
t before 
p. Returns: An iterator that points to the copy of 
t inserted into 
a. Preconditions: 
T is 
Cpp17MoveInsertable into 
X.  For 
vector, 
inplace_vector, and 
deque,
T is also 
Cpp17MoveAssignable.Effects: Inserts a copy of 
rv before 
p. Returns: An iterator that points to the copy of 
rv inserted into 
a. Preconditions: 
T is 
Cpp17CopyInsertable into 
X
and 
Cpp17CopyAssignable. Effects: Inserts 
n copies of 
t before 
p. Returns: An iterator
that points to the copy of the first element inserted into 
a, or
p if 
n == 0. Preconditions: 
T is 
Cpp17EmplaceConstructible into 
X from 
*i.  For 
vector, 
inplace_vector, and 
deque,
T is also
Cpp17MoveInsertable into 
X,
and 
T meets the
Cpp17MoveConstructible,
Cpp17MoveAssignable, and
Cpp17Swappable (
[swappable.requirements]) requirements
.Neither 
i nor 
j are iterators into 
a.Effects: Inserts copies of elements in [
i, j) before 
p.  Each iterator in the range [
i, j) shall be dereferenced exactly once
.Returns: An iterator
that points to the copy of the first element inserted into 
a, or
p if 
i == j. Preconditions: 
T is 
Cpp17EmplaceConstructible into 
X
from 
*ranges::begin(rg).  For 
vector, 
inplace_vector, and 
deque,
T is also
Cpp17MoveInsertable into 
X,
and 
T meets the
Cpp17MoveConstructible,
Cpp17MoveAssignable, and
Cpp17Swappable (
[swappable.requirements]) requirements
.Effects: Inserts copies of elements in 
rg before 
p.  Each iterator in the range 
rg is dereferenced exactly once
.Returns: An iterator
that points to the copy of the first element inserted into 
a, or
p if 
rg is empty
. Effects: Equivalent to 
a.insert(p, il.begin(), il.end()). Preconditions: For 
vector, 
inplace_vector, and 
deque,
T is 
Cpp17MoveAssignable. Effects: Erases the element pointed to by 
q. Returns: An iterator that points to the element immediately following 
q
prior to the element being erased
.  If no such element exists, 
a.end() is returned
.Preconditions: For 
vector, 
inplace_vector, and 
deque,
T is 
Cpp17MoveAssignable. Effects: Erases the elements in the range [
q1, q2)
. Returns: An iterator that points to the element pointed to by 
q2
prior to any elements being erased
.  If no such element exists, 
a.end() is returned
.Effects: Destroys all elements in 
a.  Invalidates all references, pointers, and iterators
referring to the elements of 
a and
may invalidate the past-the-end iterator
.Postconditions: 
a.empty() is 
true. Preconditions: 
T is 
Cpp17EmplaceConstructible into 
X from 
*i
and assignable from 
*i.  For 
vector,
if the iterator does not meet
the forward iterator requirements (
[forward.iterators]),
T is also 
Cpp17MoveInsertable into 
X.Neither 
i nor 
j are iterators into 
a.Effects: Replaces elements in 
a with a copy of [
i, j)
.  Invalidates all references, pointers and iterators
referring to the elements of 
a.For 
vector and 
deque,
also invalidates the past-the-end iterator
.Each iterator in the range [
i, j) is dereferenced exactly once
.Preconditions: 
T is 
Cpp17EmplaceConstructible into 
X
from 
*ranges::begin(rg).   Effects: Replaces elements in 
a with a copy of each element in 
rg.  Invalidates all references, pointers, and iterators
referring to the elements of 
a.For 
vector and 
deque,
also invalidates the past-the-end iterator
.Each iterator in the range 
rg is dereferenced exactly once
.Recommended practice: If 
R models 
ranges::approximately_sized_range and
ranges::distance(rg) <= ranges::reserve_hint(rg) is 
true,
an implementation should not perform any reallocation
. Effects: Equivalent to 
a.assign(il.begin(), il.end()). Preconditions: 
T is 
Cpp17CopyInsertable into 
X
and 
Cpp17CopyAssignable.  t is not a reference into 
a. Effects: Replaces elements in 
a with 
n copies of 
t.  Invalidates all references, pointers and iterators
referring to the elements of 
a.For 
vector and 
deque,
also invalidates the past-the-end iterator
.For every sequence container defined in this Clause and in 
[strings]:
- If the constructor
template<class InputIterator>
  X(InputIterator first, InputIterator last,
    const allocator_type& alloc = allocator_type());
is called with a type InputIterator that does not qualify as an input
iterator, then the constructor
shall not participate in overload resolution.
- If the member functions of the forms:
template<class InputIterator>
  return-type F(const_iterator p,
                InputIterator first, InputIterator last);       
template<class InputIterator>
  return-type F(InputIterator first, InputIterator last);       
template<class InputIterator>
  return-type F(const_iterator i1, const_iterator i2,
                InputIterator first, InputIterator last);       
are called with a type InputIterator that does not qualify as an input
iterator, then these functions
shall not participate in overload resolution.
- A deduction guide for a sequence container 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,
or if it has an Allocator template parameter and a type that does not
qualify as an allocator is deduced for that parameter.
The following operations are provided for
some types of sequence containers but not others
.Operations other than 
prepend_range and 
append_range
are implemented so as to take amortized constant time
.Result: 
reference; const_reference for constant 
a. Hardened preconditions: 
a.empty() is 
false. Remarks: Required for
basic_string,
array,
deque,
forward_list,
inplace_vector,
list, and
vector. Result: 
reference; const_reference for constant 
a. Hardened preconditions: 
a.empty() is 
false. Effects: Equivalent to:
auto tmp = a.end();
--tmp;
return *tmp;
Remarks: Required for
basic_string,
array,
deque,
inplace_vector,
list, and
vector. Preconditions: 
T is 
Cpp17EmplaceConstructible into 
X from 
args. Effects: Prepends an object of type 
T
constructed with 
std::forward<Args>(args).... Remarks: Required for
deque,
forward_list, and
list. Preconditions: 
T is 
Cpp17EmplaceConstructible into 
X from 
args.  For 
vector,
T is also 
Cpp17MoveInsertable into 
X.Effects: Appends an object of type 
T
constructed with 
std::forward<Args>(args).... Remarks: Required for
deque,
inplace_vector,
list, and
vector. Preconditions: 
T is 
Cpp17CopyInsertable into 
X. Effects: Prepends a copy of 
t. Remarks: Required for
deque,
forward_list, and
list. Preconditions: 
T is 
Cpp17MoveInsertable into 
X. Effects: Prepends a copy of 
rv. Remarks: Required for
deque,
forward_list, and
list. Preconditions: 
T is 
Cpp17EmplaceConstructible into 
X
from 
*ranges::begin(rg).  For 
deque,
T is also 
Cpp17MoveInsertable into 
X, and
T meets the
Cpp17MoveConstructible,
Cpp17MoveAssignable, and
Cpp17Swappable (
[swappable.requirements]) requirements
.Effects: Inserts copies of elements in 
rg before 
begin().  Each iterator in the range 
rg is dereferenced exactly once
.[
Note 2: 
The order of elements in 
rg is not reversed
. — 
end note]
Remarks: Required for
deque,
forward_list, and
list. Preconditions: 
T is 
Cpp17CopyInsertable into 
X. Effects: Appends a copy of 
t. Remarks: Required for
basic_string,
deque,
inplace_vector,
list, and
vector. Preconditions: 
T is 
Cpp17MoveInsertable into 
X. Effects: Appends a copy of 
rv. Remarks: Required for
basic_string,
deque,
inplace_vector,
list, and
vector. Preconditions: 
T is 
Cpp17EmplaceConstructible into 
X
from 
*ranges::begin(rg).  For 
vector,
T is also
Cpp17MoveInsertable into 
X.Effects: Inserts copies of elements in 
rg before 
end().  Each iterator in the range 
rg is dereferenced exactly once
.Remarks: Required for
deque,
inplace_vector,
list, and
vector. Hardened preconditions: 
a.empty() is 
false. Effects: Destroys the first element
. Remarks: Required for
deque,
forward_list, and
list. Hardened preconditions: 
a.empty() is 
false. Effects: Destroys the last element
. Remarks: Required for
basic_string,
deque,
inplace_vector,
list, and
vector. Result: 
reference; const_reference for constant 
a. Hardened preconditions: 
n < a.size() is 
true. Effects: Equivalent to: return *(a.begin() + n);
Remarks: Required for
basic_string,
array,
deque,
inplace_vector, and
vector. Result: 
reference; const_reference for constant 
a. Returns: *(a.begin() + n)
Throws: 
out_of_range if 
n >= a.size(). Remarks: Required for
basic_string,
array,
deque,
inplace_vector, and
vector.  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 
75. Table 
75 — 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;          
  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);
  friend constexpr 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_. 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_).The associative containers with unique keys and the unordered containers with unique keys
have a member function 
insert that returns a nested type 
insert_return_type.That return type is a specialization of the template specified in this subclause
.template<class Iterator, class NodeType>
struct insert-return-type
{
  Iterator position;
  bool     inserted;
  NodeType node;
};
The name 
insert-return-type is for exposition only
.insert-return-type has the template parameters,
data members, and special members specified above
.  It has no base classes or members other than those specified
.Associative containers provide fast retrieval of data based on keys
.The library provides four basic kinds of associative containers:
set,
multiset,
map
and
multimap.The library also provides container adaptors
that make it easy to construct abstract data types,
such as 
flat_maps, 
flat_multimaps,
flat_sets, or 
flat_multisets,
out of the basic sequence container kinds
(or out of other program-defined sequence containers)
.Each associative container is parameterized on
Key
and an ordering relation
Compare
that induces a strict weak ordering (
[alg.sorting]) on
elements of
Key.In addition,
map
and
multimap
associate an arbitrary 
mapped type
T
with the
Key.The phrase “equivalence of keys” means the equivalence relation imposed by the
comparison object
.That is, two keys
k1
and
k2
are considered to be equivalent if for the
comparison object
comp,
comp(k1, k2) == false && comp(k2, k1) == false.[
Note 1: 
This is not necessarily the same as the result of 
k1 == k2. — 
end note]
For any two keys
k1
and
k2
in the same container, calling
comp(k1, k2)
shall always return the same value
.An associative container supports 
unique keys if it may contain at
most one element for each key
.The 
set and 
map classes support unique keys; the 
multiset
and 
multimap classes support equivalent keys
.For 
multiset and 
multimap,
insert, 
emplace, and 
erase preserve the relative ordering
of equivalent elements
.For 
set and 
multiset the value type is the same as the key type
.For 
map and 
multimap it is equal to 
pair<const Key, T>.iterator
of an associative container is of the bidirectional iterator category
.  For associative containers where the value type is the same as the key type, both
iterator
and
const_iterator
are constant iterators
.It is unspecified whether or not
iterator
and
const_iterator
are the same type
.[
Note 2: 
iterator and 
const_iterator have identical semantics in this case, and 
iterator is convertible to 
const_iterator.  Users can avoid violating the one-definition rule by always using 
const_iterator in their function parameter lists
. — 
end note]
In this subclause,
- X denotes an associative container class,
- a denotes a value of type X,
- a2 denotes a value of a type with nodes compatible with type
X (Table 75),
- b denotes a value of type X or const X,
- u denotes the name of a variable being declared,
- a_uniq denotes a value of type X
when X supports unique keys,
- a_eq denotes a value of type X
when X supports equivalent keys,
- a_tran denotes a value of type X or const X
when the qualified-id
X::key_compare::is_transparent is valid
and denotes a type ([temp.deduct]),
- i and j
meet the Cpp17InputIterator requirements and refer to elements
implicitly convertible to
value_type,
- [i, j) denotes a valid range,
- rg denotes a value of a type R
that models container-compatible-range<value_type>,
- p denotes a valid constant iterator to a,
- q denotes a valid dereferenceable constant iterator to a,
- r denotes a valid dereferenceable iterator to a,
- [q1, q2) denotes a valid range of constant iterators in a,
- il designates an object of type initializer_list<value_type>,
- t denotes a value of type X::value_type,
- k denotes a value of type X::key_type, and
- c denotes a value of type X::key_compare or const X::key_compare;
- kl is a value such that a is partitioned ([alg.sorting])
with respect to c(x, kl),
with x the key value of e and e in a;
- ku is a value such that a is partitioned with respect to
!c(ku, x),
with x the key value of e and e in a;
- ke is a value such that a is partitioned with respect to
c(x, ke) and !c(ke, x), with c(x, ke) implying
!c(ke, x) and
with x the key value of e and e in a;
- kx is a value such that
- a is partitioned with respect to c(x, kx) and !c(kx, x),
with c(x, kx) implying !c(kx, x) and
with x the key value of e and e in a, and
- kx is not convertible to
either iterator or const_iterator; and
 
- A denotes the storage allocator used by X, if any, or allocator<X::value_type> otherwise,
- m denotes an allocator of a type convertible to A,
and nh denotes a non-const rvalue of type X::node_type.
A type 
X meets the 
associative container requirements
if 
X meets all the requirements of an allocator-aware
container (
[container.alloc.reqmts]) and
the following types, statements, and expressions are well-formed and
have the specified semantics,
except that for
map and 
multimap, the requirements placed on 
value_type
in 
[container.reqmts] apply instead to 
key_type
and 
mapped_type.[
Note 3: 
For example, in some cases 
key_type and 
mapped_type
need to be 
Cpp17CopyAssignable even though the associated
value_type, 
pair<const key_type, mapped_type>, is not
Cpp17CopyAssignable. — 
end note]
Remarks: For 
map and 
multimap only
. Result: 
Key for 
set and 
multiset only;
pair<const Key, T> for 
map and 
multimap only
. Preconditions: 
X::value_type is 
Cpp17Erasable from 
X. Preconditions: 
key_compare is 
Cpp17CopyConstructible. typename X::value_compare
Result: A binary predicate type
.  It is the same as 
key_compare for 
set and
multiset; is an ordering relation on pairs induced by the
first component (i.e., 
Key) for 
map and 
multimap.Result: A specialization of
the 
node-handle class template (
[container.node]),
such that the public nested types are
the same types as the corresponding types in 
X. Effects: Constructs an empty container
.  Uses a copy of 
c as a comparison object
.Preconditions: 
key_compare meets the 
Cpp17DefaultConstructible requirements
. Effects: Constructs an empty container
.  Uses 
Compare() as a comparison object
.Preconditions: 
value_type is
Cpp17EmplaceConstructible into 
X from 
*i. Effects: Constructs an empty container and
inserts elements from the range [
i, j) into it;
uses 
c as a comparison object
. Complexity: 
NlogN in general, where 
N has the value 
distance(i, j);
linear if [
i, j) is sorted with respect to 
value_comp(). Preconditions: 
key_compare meets the 
Cpp17DefaultConstructible requirements
.  value_type is
Cpp17EmplaceConstructible into 
X from 
*i. Effects: Constructs an empty container and
inserts elements from the range [
i, j) into it;
uses 
Compare() as a comparison object
. Complexity: 
NlogN in general, where 
N has the value 
distance(i, j);
linear if [
i, j) is sorted with respect to 
value_comp(). Preconditions: 
value_type is
Cpp17EmplaceConstructible into 
X
from 
*ranges::begin(rg). Effects: Constructs an empty container and
inserts each element from 
rg into it
.  Uses 
c as the comparison object
.Complexity: 
NlogN in general, where 
N has the value 
ranges::distance(rg);
linear if 
rg is sorted with respect to 
value_comp(). Preconditions: 
key_compare meets the 
Cpp17DefaultConstructible requirements
.  value_type is 
Cpp17EmplaceConstructible into 
X
from 
*ranges::begin(rg). Effects: Constructs an empty container and
inserts each element from 
rg into it
.  Uses 
Compare() as the comparison object
.Complexity: Same as 
X(from_range, rg, c). Effects: Equivalent to 
X(il.begin(), il.end(), c). Effects: Equivalent to 
X(il.begin(), il.end()). Preconditions: 
value_type is 
Cpp17CopyInsertable into 
X
and 
Cpp17CopyAssignable. Effects: Assigns the range [
il.begin(), il.end()) into 
a.  All existing elements of 
a are either assigned to or destroyed
.Complexity: 
NlogN in general, where 
N has the value 
il.size() + a.size();
linear if [
il.begin(), il.end()) is sorted with respect to 
value_comp(). Returns: The comparison object out of which 
b was constructed
. Result: X::value_compare
Returns: An object of 
value_compare constructed out of the comparison object
. Result: pair<iterator, bool>
Preconditions: 
value_type is
Cpp17EmplaceConstructible into 
X from 
args. Effects: Inserts a 
value_type object 
t
constructed with 
std::forward<Args>(args)...
if and only if there is no element in the container
with key equivalent to the key of 
t. Returns: The 
bool component of the returned pair is 
true
if and only if the insertion takes place, and
the iterator component of the pair points to
the element with key equivalent to the key of 
t. Preconditions: 
value_type is
Cpp17EmplaceConstructible into 
X from 
args. Effects: Inserts a 
value_type object 
t
constructed with 
std::forward<Args>(args)....  If a range containing elements equivalent to 
t exists in 
a_eq,
t is inserted at the end of that range
.Returns: An iterator pointing to the newly inserted element
. Effects: Equivalent to 
a.emplace(std::forward<Args>(args)...),
except that the element is inserted as close as possible to
the position just prior to 
p. Returns: The iterator returned by 
emplace. Complexity: Logarithmic in general, but
amortized constant if the element is inserted right before 
p. Result: pair<iterator, bool>
Preconditions: If 
t is a non-const rvalue,
value_type is 
Cpp17MoveInsertable into 
X;
otherwise, 
value_type is 
Cpp17CopyInsertable into 
X. Effects: Inserts 
t if and only if there is no element in the container
with key equivalent to the key of 
t. Returns: The 
bool component of the returned pair is 
true
if and only if the insertion takes place, and
the 
iterator component of the pair points to
the element with key equivalent to the key of 
t. Preconditions: If 
t is a non-const rvalue,
value_type is 
Cpp17MoveInsertable into 
X;
otherwise, 
value_type is 
Cpp17CopyInsertable into 
X. Effects: Inserts 
t and returns the iterator pointing to
the newly inserted element
.  If a range containing elements equivalent to 
t exists in 
a_eq,
t is inserted at the end of that range
.Preconditions: If 
t is a non-const rvalue,
value_type is 
Cpp17MoveInsertable into 
X;
otherwise, 
value_type is 
Cpp17CopyInsertable into 
X. Effects: Inserts 
t if and only if there is no element
with key equivalent to the key of 
t in containers with unique keys;
always inserts 
t in containers with equivalent keys
.  t is inserted as close as possible to
the position just prior to 
p. Returns: An iterator pointing to the element with key equivalent to the key of 
t. Complexity: Logarithmic in general, but
amortized constant if 
t is inserted right before 
p. Preconditions: 
value_type is
Cpp17EmplaceConstructible into 
X from 
*i.  Neither 
i nor 
j are iterators into 
a.Effects: Inserts each element from the range [
i, j)
if and only if there is no element
with key equivalent to the key of that element in containers with unique keys;
always inserts that element in containers with equivalent keys
. Complexity: 
Nlog(a.size()+N), where 
N has the value 
distance(i, j). Preconditions: 
value_type is
Cpp17EmplaceConstructible into 
X
from 
*ranges::begin(rg).  Effects: Inserts each element from 
rg if and only if
there is no element with key equivalent to the key of that element
in containers with unique keys;
always inserts that element in containers with equivalent keys
. Complexity: 
Nlog(a.size()+N),
where 
N has the value 
ranges::distance(rg). Effects: Equivalent to 
a.insert(il.begin(), il.end()). Result: insert_return_type
Preconditions: 
nh is empty or
a_uniq.get_allocator() == nh.get_allocator() is 
true. Effects: If 
nh is empty, has no effect
.  Otherwise, inserts the element owned by 
nh if and only if
there is no element in the container with a key equivalent to 
nh.key().Returns: If 
nh is empty, 
inserted is 
false,
position is 
end(), and 
node is empty
.  Otherwise if the insertion took place, 
inserted is 
true,
position points to the inserted element, and 
node is empty;
if the insertion failed, 
inserted is 
false,
node has the previous value of 
nh, and
position points to an element with a key equivalent to 
nh.key().Preconditions: 
nh is empty or
a_eq.get_allocator() == nh.get_allocator() is 
true. Effects: If 
nh is empty, has no effect and returns 
a_eq.end().  Otherwise, inserts the element owned by 
nh and
returns an iterator pointing to the newly inserted element
.If a range containing elements with keys equivalent to 
nh.key()
exists in 
a_eq,
the element is inserted at the end of that range
.Postconditions: 
nh is empty
. Preconditions: 
nh is empty or
a.get_allocator() == nh.get_allocator() is 
true. Effects: If 
nh is empty, has no effect and returns 
a.end().  Otherwise, inserts the element owned by 
nh if and only if
there is no element with key equivalent to 
nh.key()
in containers with unique keys;
always inserts the element owned by 
nh
in containers with equivalent keys
.The element is inserted as close as possible to
the position just prior to 
p.Postconditions: 
nh is empty if insertion succeeds, unchanged if insertion fails
. Returns: An iterator pointing to the element with key equivalent to 
nh.key(). Complexity: Logarithmic in general, but
amortized constant if the element is inserted right before 
p. Effects: Removes the first element in the container with key equivalent to 
k. Returns: A 
node_type owning the element if found,
otherwise an empty 
node_type. Complexity: log(a.size())
Effects: Removes the first element in the container with key 
r
such that 
!c(r, kx) && !c(kx, r) is 
true. Returns: A 
node_type owning the element if found,
otherwise an empty 
node_type. Complexity: log(a_tran.size())
Effects: Removes the element pointed to by 
q. Returns: A 
node_type owning that element
. Complexity: Amortized constant
. Preconditions: 
a.get_allocator() == a2.get_allocator() is 
true. Effects: Attempts to extract each element in 
a2 and insert it into 
a
using the comparison object of 
a.  In containers with unique keys,
if there is an element in 
a with key equivalent to
the key of an element from 
a2,
then that element is not extracted from 
a2.Postconditions: Pointers and references to the transferred elements of 
a2
refer to those same elements but as members of 
a.  If 
a.begin() and 
a2.begin() have the same type,
iterators referring to the transferred elements
will continue to refer to their elements,
but they now behave as iterators into 
a, not into 
a2.Throws: Nothing unless the comparison object throws
. Complexity: 
Nlog(a.size()+N), where 
N has the value 
a2.size(). Effects: Erases all elements in the container with key equivalent to 
k. Returns: The number of erased elements
. Complexity: log(a.size())+a.count(k)
Effects: Erases all elements in the container with key 
r
such that 
!c(r, kx) && !c(kx, r) is 
true. Returns: The number of erased elements
. Complexity: log(a_tran.size())+a_tran.count(kx)
Effects: Erases the element pointed to by 
q. Returns: An iterator pointing to the element immediately following 
q
prior to the element being erased
.  If no such element exists, returns 
a.end().Complexity: Amortized constant
. Effects: Erases the element pointed to by 
r. Returns: An iterator pointing to the element immediately following 
r
prior to the element being erased
.  If no such element exists, returns 
a.end().Complexity: Amortized constant
. Effects: Erases all the elements in the range [
q1, q2)
. Returns: An iterator pointing to the element pointed to by 
q2
prior to any elements being erased
.  If no such element exists, 
a.end() is returned
.Complexity: 
log(a.size())+N, where 
N has the value 
distance(q1, q2). Effects: Equivalent to 
a.erase(a.begin(), a.end()). Postconditions: 
a.empty() is 
true. Complexity: Linear in 
a.size(). Result: 
iterator; 
const_iterator for constant 
b. Returns: An iterator pointing to an element with the key equivalent to 
k, or
b.end() if such an element is not found
. Result: 
iterator; 
const_iterator for constant 
a_tran. Returns: An iterator pointing to an element with key 
r
such that 
!c(r, ke) && !c(ke, r) is 
true, or
a_tran.end() if such an element is not found
. Returns: The number of elements with key equivalent to 
k. Complexity: log(b.size())+b.count(k)
Returns: The number of elements with key 
r
such that 
!c(r, ke) && !c(ke, r). Complexity: log(a_tran.size())+a_tran.count(ke)
Effects: Equivalent to: return b.find(k) != b.end();
Effects: Equivalent to: return a_tran.find(ke) != a_tran.end();
Result: 
iterator; 
const_iterator for constant 
b. Returns: An iterator pointing to the first element with key not less than 
k,
or 
b.end() if such an element is not found
. Result: 
iterator; 
const_iterator for constant 
a_tran. Returns: An iterator pointing to the first element with key 
r
such that 
!c(r, kl),
or 
a_tran.end() if such an element is not found
. Result: 
iterator; 
const_iterator for constant 
b. Returns: An iterator pointing to the first element with key greater than 
k,
or 
b.end() if such an element is not found
. Result: 
iterator; 
const_iterator for constant 
a_tran. Returns: An iterator pointing to the first element with key 
r
such that 
c(ku, r),
or 
a_tran.end() if such an element is not found
. Result: 
pair<iterator, iterator>;
pair<const_iterator, const_iterator> for constant 
b. Effects: Equivalent to: return make_pair(b.lower_bound(k), b.upper_bound(k));
Result: 
pair<iterator, iterator>;
pair<const_iterator, const_iterator> for constant 
a_tran. Effects: Equivalent to:
return make_pair(a_tran.lower_bound(ke), a_tran.upper_bound(ke));
The 
insert, 
insert_range, and 
emplace members
shall not affect the validity of
iterators and references to the container,
and the 
erase members shall invalidate only iterators and
references to the erased elements
.The 
extract members invalidate only iterators to the removed element;
pointers and references to the removed element remain valid
.However, accessing
the element through such pointers and references while the element is owned by
a 
node_type is undefined behavior
.References and pointers to an element
obtained while it is owned by a 
node_type are invalidated if the element
is successfully inserted
.The fundamental property of iterators of associative containers is that they iterate through the containers
in the non-descending order of keys where non-descending is defined by the comparison that was used to
construct them
.For any two dereferenceable iterators
i
and
j
such that distance from
i
to
j
is positive, the following condition holds:
value_comp(*j, *i) == false
For associative containers with unique keys the stronger condition holds:
value_comp(*i, *j) != false
When an associative container is constructed by passing a comparison object the
container shall not store a pointer or reference to the passed object,
even if that object is passed by reference
.When an associative container is copied, through either a copy constructor
or an assignment operator,
the target container shall then use the comparison object from the container
being copied,
as if that comparison object had been passed to the target container in
its constructor
.The member function templates
find, 
count, 
contains,
lower_bound, 
upper_bound, 
equal_range,
erase, and 
extract
shall not participate in overload resolution unless
the 
qualified-id Compare::is_transparent is valid
and denotes a type (
[temp.deduct])
.Additionally, the member function templates 
extract and 
erase
shall not participate in overload resolution if
is_convertible_v<K&&, iterator> || is_convertible_v<K&&, const_iterator>
is 
true,
where 
K is the type substituted as the first template argument
.A deduction guide for an associative container 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 an  Allocator-  template parameter
and a type that does not qualify as an allocator is deduced for that parameter .
- It has a  Compare-  template parameter
and a type that qualifies as an allocator is deduced for that parameter .
For associative containers, no 
clear() function throws an exception
.erase(k) does not throw an exception unless that exception is thrown
by the container's 
Compare object (if any)
. For associative containers, if an exception is thrown by any operation from
within an 
insert or 
emplace function inserting a single element, the
insertion has no effect
.For associative containers, no 
swap function throws an exception unless
that exception is thrown by the
swap of the container's 
Compare object (if any)
.
Unordered associative containers provide an ability for fast retrieval
of data based on keys
.The worst-case complexity for most operations
is linear, but the average case is much faster
.The library provides
four unordered associative containers: 
unordered_set,
unordered_map, 
unordered_multiset, and
unordered_multimap.Unordered associative containers conform to the requirements for
Containers (
[container.requirements]), except that
the expressions
a == b and 
a != b have different semantics than for the other
container types
.Each unordered associative container is parameterized by 
Key,
by a function object type 
Hash that meets the 
Cpp17Hash
requirements (
[hash.requirements]) and acts as a hash function for
argument values of type 
Key, and by a binary predicate 
Pred
that induces an equivalence relation on values of type 
Key.Additionally, 
unordered_map and 
unordered_multimap associate
an arbitrary 
mapped type T with the 
Key.The container's object of type 
Hash — denoted by
hash — is called the 
hash function of the
container
.Two values 
k1 and 
k2 are
considered equivalent if the container's
key equality predicate
pred(k1, k2) is valid and returns
true when passed those values
.If 
k1 and
k2 are equivalent, the container's hash function shall
return the same value for both
.[
Note 1: 
Thus, when an unordered associative container is instantiated with
a non-default 
Pred parameter it usually needs a non-default 
Hash
parameter as well
. — 
end note]
For any two keys 
k1 and 
k2 in the same container,
calling 
pred(k1, k2) shall always return the same value
.For any key 
k in a container, calling 
hash(k)
shall always return the same value
.An unordered associative container supports 
unique keys if it
may contain at most one element for each key
.Otherwise, it supports
equivalent keys.unordered_set and 
unordered_map
support unique keys
.  unordered_multiset and 
unordered_multimap
support equivalent keys
.  In containers that support equivalent keys,
elements with equivalent keys are adjacent to each other
in the iteration order of the container
.Thus, although the absolute order
of elements in an unordered container is not specified, its elements are
grouped into 
equivalent-key groups such that all elements of each
group have equivalent keys
.Mutating operations on unordered containers shall
preserve the relative order of elements within each equivalent-key group
unless otherwise specified
.For 
unordered_set and 
unordered_multiset the value type is
the same as the key type
.For 
unordered_map and
unordered_multimap it is 
pair<const Key,
T>.For unordered containers where the value type is the same as the key
type, both 
iterator and 
const_iterator are constant
iterators
.It is unspecified whether or not 
iterator and
const_iterator are the same type
.[
Note 2: 
iterator and 
const_iterator have identical
semantics in this case, and 
iterator is convertible to
const_iterator.  Users can avoid violating the one-definition rule
by always using 
const_iterator in their function parameter lists
. — 
end note]
The elements of an unordered associative container are organized into
buckets.Keys with the same hash code appear in the same
bucket
.The number of buckets is automatically increased as elements
are added to an unordered associative container, so that the average
number of elements per bucket is kept below a bound
.Rehashing
invalidates iterators, changes ordering between elements, and changes
which buckets elements appear in, but does not invalidate pointers or
references to elements
.For 
unordered_multiset and
unordered_multimap, rehashing preserves the relative ordering of
equivalent elements
.In this subclause,
- X denotes an unordered associative container class,
- a denotes a value of type X,
- a2 denotes a value of a type with nodes compatible
  with type X (Table 75),
- b denotes a value of type X or const X,
- a_uniq denotes a value of type X
  when X supports unique keys,
- a_eq denotes a value of type X
  when X supports equivalent keys,
- a_tran denotes a value of type X or const X
  when the qualified-ids
  X::key_equal::is_transparent and
  X::hasher::is_transparent
  are both valid and denote types ([temp.deduct]),
- i and j denote input iterators
  that refer to value_type,
- [i, j) denotes a valid range,
- rg denotes a value of a type R
that models container-compatible-range<value_type>,
- p and q2 denote valid constant iterators to a,
- q and q1 denote
  valid dereferenceable constant iterators to a,
- r denotes a valid dereferenceable iterator to a,
- [q1, q2) denotes a valid range in a,
- il denotes a value of type initializer_list<value_type>,
- t denotes a value of type X::value_type,
- k denotes a value of type key_type,
- hf denotes a value of type hasher or const hasher,
- eq denotes a value of type key_equal or const key_equal,
- ke is a value such that
  - eq(r1, ke) == eq(ke, r1),
- hf(r1) == hf(ke) if eq(r1, ke) is true, and
- if any two of
    eq(r1, ke), eq(r2, ke), and eq(r1, r2)
    are true, then all three are true,
 where r1 and r2 are keys of elements in a_tran,
- kx is a value such that
  - eq(r1, kx) == eq(kx, r1),
- hf(r1) == hf(kx) if eq(r1, kx) is true,
- if any two of
    eq(r1, kx), eq(r2, kx), and eq(r1, r2)
    are true, then all three are true, and
- kx is not convertible to
    either iterator or const_iterator,
 where r1 and r2 are keys of elements in a_tran,
- n denotes a value of type size_type,
- z denotes a value of type float, and
- nh denotes an rvalue of type X::node_type.
A type 
X meets
the 
unordered associative container requirements
if 
X meets all the requirements of
an allocator-aware container (
[container.alloc.reqmts]) and
the following types, statements, and expressions are well-formed and
have the specified semantics,
except that for 
unordered_map and 
unordered_multimap,
the requirements placed on 
value_type in 
[container.reqmts]
apply instead to 
key_type and 
mapped_type.[
Note 3: 
For example, 
key_type and 
mapped_type
sometimes need to be 
Cpp17CopyAssignable
even though the associated 
value_type,
pair<const key_type, mapped_type>,
is not 
Cpp17CopyAssignable. — 
end note]
Remarks: For 
unordered_map and 
unordered_multimap only
. Result: 
Key for 
unordered_set and 
unordered_multiset only;
pair<const Key, T>
for 
unordered_map and 
unordered_multimap only
. Preconditions: 
value_type is 
Cpp17Erasable from 
X. Preconditions: 
Hash is a unary function object type
such that the expression 
hf(k) has type 
size_t. Preconditions: 
Pred meets the 
Cpp17CopyConstructible requirements
.  Pred is a binary predicate that takes two arguments of type 
Key.  Pred is an equivalence relation
. typename X::local_iterator
Result: An iterator type
whose category, value type, difference type, and pointer and reference types
are the same as 
X::iterator's
.  [
Note 4: 
A 
local_iterator object can be used to iterate through a single bucket,
but cannot be used to iterate across buckets
. — 
end note]
typename X::const_local_iterator
Result: An iterator type
whose category, value type, difference type, and pointer and reference types
are the same as 
X::const_iterator's
.  [
Note 5: 
A 
const_local_iterator object can be used to iterate
through a single bucket,
but cannot be used to iterate across buckets
. — 
end note]
Result: A specialization of a 
node-handle class template (
[container.node]),
such that the public nested types are the same types
as the corresponding types in 
X. Effects: Constructs an empty container with at least 
n buckets,
using 
hf as the hash function and
eq as the key equality predicate
. Preconditions: 
key_equal meets the 
Cpp17DefaultConstructible requirements
. Effects: Constructs an empty container with at least 
n buckets,
using 
hf as the hash function and
key_equal() as the key equality predicate
. Preconditions: 
hasher and 
key_equal
meet the 
Cpp17DefaultConstructible requirements
. Effects: Constructs an empty container with at least 
n buckets,
using 
hasher() as the hash function and
key_equal() as the key equality predicate
. Preconditions: 
hasher and 
key_equal meet
the 
Cpp17DefaultConstructible requirements
. Effects: Constructs an empty container with an unspecified number of buckets,
using 
hasher() as the hash function and
key_equal() as the key equality predicate
. Preconditions: 
value_type is
Cpp17EmplaceConstructible into 
X from 
*i. Effects: Constructs an empty container with at least 
n buckets,
using 
hf as the hash function and
eq as the key equality predicate, and
inserts elements from [
i, j) into it
. Complexity: Average case 
O(N) (
N is 
distance(i, j)), worst case 
O(N2). Preconditions: 
key_equal meets the 
Cpp17DefaultConstructible requirements
.  value_type is
Cpp17EmplaceConstructible into 
X from 
*i. Effects: Constructs an empty container with at least 
n buckets,
using 
hf as the hash function and
key_equal() as the key equality predicate, and
inserts elements from [
i, j) into it
. Complexity: Average case 
O(N) (
N is 
distance(i, j)), worst case 
O(N2). Preconditions: 
hasher and 
key_equal meet
the 
Cpp17DefaultConstructible requirements
.  value_type is
Cpp17EmplaceConstructible into 
X from 
*i. Effects: Constructs an empty container with at least 
n buckets,
using 
hasher() as the hash function and
key_equal() as the key equality predicate, and
inserts elements from [
i, j) into it
. Complexity: Average case 
O(N) (
N is 
distance(i, j)), worst case 
O(N2). Preconditions: 
hasher and 
key_equal meet
the 
Cpp17DefaultConstructible requirements
.  value_type is
Cpp17EmplaceConstructible into 
X from 
*i. Effects: Constructs an empty container with an unspecified number of buckets,
using 
hasher() as the hash function and
key_equal() as the key equality predicate, and
inserts elements from [
i, j) into it
. Complexity: Average case 
O(N) (
N is 
distance(i, j)), worst case 
O(N2). X(from_range, rg, n, hf, eq)
Preconditions: 
value_type is
Cpp17EmplaceConstructible into 
X
from 
*ranges::begin(rg). Effects: Constructs an empty container with at least 
n buckets,
using 
hf as the hash function and
eq as the key equality predicate, and
inserts elements from 
rg into it
. Complexity: Average case 
O(N) (
N is 
ranges::distance(rg)),
worst case 
O(N2). Preconditions: 
key_equal meets the 
Cpp17DefaultConstructible requirements
.  value_type is
Cpp17EmplaceConstructible into 
X
from 
*ranges::begin(rg). Effects: Constructs an empty container with at least 
n buckets,
using 
hf as the hash function and
key_equal() as the key equality predicate, and
inserts elements from 
rg into it
. Complexity: Average case 
O(N) (
N is 
ranges::distance(rg)),
worst case 
O(N2). Preconditions: 
hasher and 
key_equal meet
the 
Cpp17DefaultConstructible requirements
.  value_type is
Cpp17EmplaceConstructible into 
X
from 
*ranges::begin(rg). Effects: Constructs an empty container with at least 
n buckets,
using 
hasher() as the hash function and
key_equal() as the key equality predicate, and
inserts elements from 
rg into it
. Complexity: Average case 
O(N) (
N is 
ranges::distance(rg)),
worst case 
O(N2). Preconditions: 
hasher and 
key_equal meet
the 
Cpp17DefaultConstructible requirements
.  value_type is
Cpp17EmplaceConstructible into 
X
from 
*ranges::begin(rg). Effects: Constructs an empty container with an unspecified number of buckets,
using 
hasher() as the hash function and
key_equal() as the key equality predicate, and
inserts elements from 
rg into it
. Complexity: Average case 
O(N) (
N is 
ranges::distance(rg)),
worst case 
O(N2). Effects: Equivalent to 
X(il.begin(), il.end()). Effects: Equivalent to  
X(il.begin(), il.end(), n). Effects: Equivalent to 
X(il.begin(), il.end(), n, hf). Effects: Equivalent to 
X(il.begin(), il.end(), n, hf, eq). Effects: In addition to the container requirements (
[container.reqmts]),
copies the hash function, predicate, and maximum load factor
. Complexity: Average case linear in 
b.size(), worst case quadratic
. Effects: In addition to the container requirements,
copies the hash function, predicate, and maximum load factor
. Complexity: Average case linear in 
b.size(), worst case quadratic
. Preconditions: 
value_type is 
Cpp17CopyInsertable into 
X
and 
Cpp17CopyAssignable. Effects: Assigns the range [
il.begin(), il.end()) into 
a.  All existing elements of 
a are either assigned to or destroyed
.Complexity: Average case linear in 
il.size(), worst case quadratic
. Returns: 
b's hash function
. Returns: 
b's key equality predicate
. Result: pair<iterator, bool>
Preconditions: 
value_type is
Cpp17EmplaceConstructible into 
X from 
args. Effects: Inserts a 
value_type object 
t
constructed with 
std::forward<Args>(args)... if and only if
there is no element in the container
with key equivalent to the key of 
t. Returns: The 
bool component of the returned pair is 
true
if and only if the insertion takes place, and
the iterator component of the pair points to
the element with key equivalent to the key of 
t. Complexity: Average case 
O(1), worst case 
O(a_uniq.size()). Preconditions: 
value_type is
Cpp17EmplaceConstructible into 
X from 
args. Effects: Inserts a 
value_type object 
t
constructed with 
std::forward<Args>(args).... Returns: An iterator pointing to the newly inserted element
. Complexity: Average case 
O(1), worst case 
O(a_eq.size()). Effects: Equivalent to 
a.emplace(std::forward<Args>(args)...),
except that the 
const_iterator p is a hint
pointing to where the search should start
.  Implementations are permitted to ignore the hint
.Returns: The iterator returned by 
emplace. Result: pair<iterator, bool>
Preconditions: If 
t is a non-const rvalue,
value_type is 
Cpp17MoveInsertable into 
X;
otherwise, 
value_type is 
Cpp17CopyInsertable into 
X. Effects: Inserts 
t if and only if there is no element in the container
with key equivalent to the key of 
t. Returns: The 
bool component of the returned pair indicates
whether the insertion takes place, and
the 
iterator component points to
the element with key equivalent to the key of 
t. Complexity: Average case 
O(1), worst case 
O(a_uniq.size()). Preconditions: If 
t is a non-const rvalue,
value_type is 
Cpp17MoveInsertable into 
X;
otherwise, 
value_type is 
Cpp17CopyInsertable into 
X. Returns: An iterator pointing to the newly inserted element
. Complexity: Average case 
O(1), worst case 
O(a_eq.size()). Preconditions: If 
t is a non-const rvalue,
value_type is 
Cpp17MoveInsertable into 
X;
otherwise, 
value_type is 
Cpp17CopyInsertable into 
X. Effects: Equivalent to 
a.insert(t).  The iterator 
p is a hint pointing to where the search should start
.Implementations are permitted to ignore the hint
.Returns: An iterator pointing to
the element with the key equivalent to that of 
t. Complexity: Average case 
O(1), worst case 
O(a.size()). Preconditions: 
value_type is
Cpp17EmplaceConstructible into 
X from 
*i.  Neither 
i nor 
j are iterators into 
a.Effects: Equivalent to 
a.insert(t) for each element in [
i, j)
. Complexity: Average case 
O(N), where 
N is 
distance(i, j),
worst case 
O(N(a.size()+1)). Preconditions: 
value_type is
Cpp17EmplaceConstructible into 
X
from 
*ranges::begin(rg).  Effects: Equivalent to 
a.insert(t) for each element 
t in 
rg. Complexity: Average case 
O(N), where 
N is 
ranges::distance(rg),
worst case 
O(N(a.size()+1)). Effects: Equivalent to 
a.insert(il.begin(), il.end()). Result: insert_return_type
Preconditions: 
nh is empty or
a_uniq.get_allocator() == nh.get_allocator() is 
true. Effects: If 
nh is empty, has no effect
.  Otherwise, inserts the element owned by 
nh if and only if
there is no element in the container with a key equivalent to 
nh.key().Postconditions: If 
nh is empty, 
inserted is 
false,
position is 
end(), and 
node is empty
.  Otherwise if the insertion took place, 
inserted is 
true,
position points to the inserted element, and 
node is empty;
if the insertion failed, 
inserted is 
false,
node has the previous value of 
nh, and 
position
points to an element with a key equivalent to 
nh.key().Complexity: Average case 
O(1), worst case 
O(a_uniq.size()). Preconditions: 
nh is empty or
a_eq.get_allocator() == nh.get_allocator() is 
true. Effects: If 
nh is empty, has no effect and returns 
a_eq.end().  Otherwise, inserts the element owned by 
nh and
returns an iterator  pointing to the newly inserted element
.Postconditions: 
nh is empty
. Complexity: Average case 
O(1), worst case 
O(a_eq.size()). Preconditions: 
nh is empty or
a.get_allocator() == nh.get_allocator() is 
true. Effects: If 
nh is empty, has no effect and returns 
a.end().  Otherwise, inserts the element owned by 
nh if and only if
there is no element with key equivalent to 
nh.key()
in containers with unique keys;
always inserts the element owned by 
nh
in containers with equivalent keys
.The iterator 
q is a hint pointing to where the search should start
.Implementations are permitted to ignore the hint
.Postconditions: 
nh is empty if insertion succeeds, unchanged if insertion fails
. Returns: An iterator pointing to the element with key equivalent to 
nh.key(). Complexity: Average case 
O(1), worst case 
O(a.size()). Effects: Removes an element in the container with key equivalent to 
k. Returns: A 
node_type owning the element if found,
otherwise an empty 
node_type. Complexity: Average case 
O(1), worst case 
O(a.size()). Effects: Removes an element in the container with key equivalent to 
kx. Returns: A 
node_type owning the element if found,
otherwise an empty 
node_type. Complexity: Average case 
O(1), worst case 
O(a_tran.size()). Effects: Removes the element pointed to by 
q. Returns: A 
node_type owning that element
. Complexity: Average case 
O(1), worst case 
O(a.size()). Preconditions: 
a.get_allocator() == a2.get_allocator(). Effects: Attempts to extract each element in 
a2 and insert it into 
a
using the hash function and key equality predicate of 
a.  In containers with unique keys, if there is an element in 
a
with key equivalent to the key of an element from 
a2,
then that element is not extracted from 
a2.Postconditions: Pointers and references to the transferred elements of 
a2 refer to
those same elements but as members of 
a.  Iterators referring to the transferred elements and
all iterators referring to 
a will be invalidated,
but iterators to elements remaining in 
a2 will remain valid
.Complexity: Average case 
O(N), where 
N is 
a2.size(),
worst case 
O(N*a.size() + N). Effects: Erases all elements with key equivalent to 
k. Returns: The number of elements erased
. Complexity: Average case 
O(a.count(k)), worst case 
O(a.size()). Effects: Erases all elements with key equivalent to 
kx. Returns: The number of elements erased
. Complexity: Average case 
O(a_tran.count(kx)),
worst case 
O(a_tran.size()). Effects: Erases the element pointed to by 
q. Returns: The iterator immediately following 
q prior to the erasure
. Complexity: Average case 
O(1), worst case 
O(a.size()). Effects: Erases the element pointed to by 
r. Returns: The iterator immediately following 
r prior to the erasure
. Complexity: Average case 
O(1), worst case 
O(a.size()). Effects: Erases all elements in the range [
q1, q2)
. Returns: The iterator immediately following the erased elements prior to the erasure
. Complexity: Average case linear in 
distance(q1, q2),
worst case 
O(a.size()). Effects: Erases all elements in the container
. Postconditions: 
a.empty() is 
true. Complexity: Linear in 
a.size(). Result: 
iterator; 
const_iterator for constant 
b. Returns: An iterator pointing to an element with key equivalent to 
k, or
b.end() if no such element exists
. Complexity: Average case 
O(1), worst case 
O(b.size()). Result: 
iterator; 
const_iterator for constant 
a_tran. Returns: An iterator pointing to an element with key equivalent to 
ke, or
a_tran.end() if no such element exists
. Complexity: Average case 
O(1), worst case 
O(a_tran.size()). Returns: The number of elements with key equivalent to 
k. Complexity: Average case 
O(b.count(k)), worst case 
O(b.size()). Returns: The number of elements with key equivalent to 
ke. Complexity: Average case 
O(a_tran.count(ke)),
worst case 
O(a_tran.size()). Effects: Equivalent to 
b.find(k) != b.end(). Effects: Equivalent to 
a_tran.find(ke) != a_tran.end(). Result: 
pair<iterator, iterator>;
pair<const_iterator, const_iterator> for constant 
b. Returns: A range containing all elements with keys equivalent to 
k.  Returns 
make_pair(b.end(), b.end()) if no such elements exist
.Complexity: Average case 
O(b.count(k)), worst case 
O(b.size()). Result: 
pair<iterator, iterator>;
pair<const_iterator, const_iterator> for constant 
a_tran. Returns: A range containing all elements with keys equivalent to 
ke.  Returns 
make_pair(a_tran.end(), a_tran.end()) if no such elements exist
.Complexity: Average case 
O(a_tran.count(ke)),
worst case 
O(a_tran.size()). Returns: The number of buckets that 
b contains
. Returns: An upper bound on the number of buckets that 
b can ever contain
. Preconditions: 
b.bucket_count() > 0. Returns: The index of the bucket
in which elements with keys equivalent to 
k would be found,
if any such element existed
.  The return value is in the range [
0, b.bucket_count())
.Preconditions: 
a_tran.bucket_count() > 0. Postconditions: The return value is in the range [
0, a_tran.bucket_count())
. Returns: The index of the bucket
in which elements with keys equivalent to 
ke would be found,
if any such element existed
. Preconditions: 
n shall be in the range [
0, b.bucket_count())
. Returns: The number of elements in the 
nth bucket
. Complexity: O(b.bucket_size(n))
Result: 
local_iterator; 
const_local_iterator for constant 
b. Preconditions: 
n is in the range [
0, b.bucket_count())
. Returns: An iterator referring to the first element in the bucket
.  If the bucket is empty, then 
b.begin(n) == b.end(n).Result: 
local_iterator; 
const_local_iterator for constant 
b. Preconditions: 
n is in the range [
0, b.bucket_count())
. Returns: An iterator which is the past-the-end value for the bucket
. Result: const_local_iterator
Preconditions: 
n shall be in the range [
0, b.bucket_count())
. Returns: An iterator referring to the first element in the bucket
.  If the bucket is empty, then 
b.cbegin(n) == b.cend(n).Result: const_local_iterator
Preconditions: 
n is in the range [
0, b.bucket_count())
. Returns: An iterator which is the past-the-end value for the bucket
. Returns: The average number of elements per bucket
. Returns: A positive number
that the container attempts to keep the load factor less than or equal to
.  The container automatically increases the number of buckets as necessary
to keep the load factor below this number
.Preconditions: 
z is positive
.  May change the container's maximum load factor, using 
z as a hint
.Postconditions: 
a.bucket_count() >= a.size() / a.max_load_factor() and
a.bucket_count() >= n. Complexity: Average case linear in 
a.size(), worst case quadratic
. Effects: Equivalent to 
a.rehash(ceil(n / a.max_load_factor())). Two unordered containers 
a and 
b compare equal if
a.size() == b.size() and, for every equivalent-key group
[
Ea1, Ea2) obtained from 
a.equal_range(Ea1), there exists an
equivalent-key group [
Eb1, Eb2) obtained from 
b.equal_range(Ea1),
such that
is_permutation(Ea1, Ea2, Eb1, Eb2) returns 
true.For
unordered_set and 
unordered_map, the complexity of
operator== (i.e., the number of calls to the 
== operator
of the 
value_type, to the predicate returned by 
key_eq(),
and to the hasher returned by 
hash_function()) is proportional to
N in the average case and to 
N2 in the worst case, where 
N is
a.size().For 
unordered_multiset and 
unordered_multimap,
the complexity of 
operator== is proportional to 
∑E2i
in the average case and to 
N2 in the worst case, where 
N is 
a.size(),
and 
Ei is the size of the 
ith equivalent-key group in 
a.However, if the respective elements of each corresponding pair of
equivalent-key groups 
Eai and 
Ebi are arranged in the same order
(as is commonly the case, e.g., if 
a and 
b are unmodified copies
of the same container), then the average-case complexity for
unordered_multiset and 
unordered_multimap becomes
proportional to 
N (but worst-case complexity remains 
O(N2), e.g., for
a pathologically bad hash function)
.The behavior of a program that uses
operator== or 
operator!= on unordered containers is undefined
unless the 
Pred function object has
the same behavior for both containers and the equality comparison function
for 
Key is a refinement
of the partition into equivalent-key groups produced by 
Pred.The iterator types 
iterator and 
const_iterator of
an unordered associative container are of at least the forward iterator
category
.For unordered associative containers where the key type and
value type are the same, both 
iterator and
const_iterator are constant iterators
.The 
insert, 
insert_range, and 
emplace members
shall not affect the validity of references to
container elements, but may invalidate all iterators to the
container
.The 
erase members shall invalidate only iterators and
references to the erased elements, and preserve the relative order of the
elements that are not erased
.The 
insert, 
insert_range, and 
emplace members
shall not affect the validity of iterators if
(N + n) <= z * B, where 
N is the number of elements in
the container prior to the insert operation, 
n is the
number of elements inserted, 
B is the container's bucket count, and
z is the container's maximum load factor
.The 
extract members invalidate only iterators to the removed element,
and preserve the relative order of the elements that are not erased; pointers
and references to the removed element remain valid
.However, accessing the
element through such pointers and references while the element is owned by a
node_type is undefined behavior
.References and pointers to an element
obtained while it is owned by a 
node_type are invalidated if the
element is successfully inserted
.The member function templates
find, 
count, 
equal_range, 
contains,
extract, 
erase, and 
bucket
shall not participate in overload resolution unless
the 
qualified-ids
Pred::is_transparent and
Hash::is_transparent
are both valid and denote types (
[temp.deduct])
.Additionally, the member function templates 
extract and 
erase
shall not participate in overload resolution if
is_convertible_v<K&&, iterator> || is_convertible_v<K&&, const_iterator>
is 
true,
where 
K is the type substituted as the first template argument
.A deduction guide for an unordered associative container 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 an  Allocator-  template parameter
and a type that does not qualify as an allocator is deduced for that parameter .
- It has a  Hash-  template parameter
and an integral type or a type that qualifies as an allocator is deduced for that parameter .
- It has a  Pred-  template parameter
and a type that qualifies as an allocator is deduced for that parameter .
For unordered associative containers, no 
clear() function
throws an exception
.erase(k) does not throw an
exception unless that exception is thrown by the container's 
Hash or
Pred object (if any)
. For unordered associative containers, if an exception is thrown by any
operation other than the container's hash function from within an
insert or 
emplace function inserting a single element,
the insertion has no effect
.For unordered associative containers, no 
swap function throws
an exception unless that exception is thrown by the swap of the container's
Hash or 
Pred object (if any)
.For unordered associative containers, if an exception is thrown
from within a 
rehash() function other than by the container's hash
function or comparison function, the 
rehash() function has no effect
.The headers
,
,
,
,
,
, and
define class templates that meet the requirements for sequence containers
.The following exposition-only alias template may appear in deduction guides for sequence containers:
template<class InputIterator>
  using iter-value-type = typename iterator_traits<InputIterator>::value_type;  
The header 
 defines a class template for storing fixed-size
sequences of objects
.An instance of 
array<T, N> stores 
N elements of type 
T,
so that 
size() == N is an invariant
.An 
array is an 
aggregate that can be
list-initialized with up
to 
N elements whose types are convertible to 
T.  Descriptions are provided here
only for operations on 
array that are not described in
one of these tables and
for operations where there is additional semantic information
. array<T, N> is a structural type (
[temp.param]) if
T is a structural type
.  Two values 
a1 and 
a2 of type 
array<T, N>
are 
template-argument-equivalent if and only if
each pair of corresponding elements in 
a1 and 
a2
are template-argument-equivalent
.namespace std {
  template<class T, size_t N>
  struct array {
    
    using value_type             = T;
    using pointer                = T*;
    using const_pointer          = const T*;
    using reference              = T&;
    using const_reference        = const T&;
    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>;
    
    constexpr void fill(const T& u);
    constexpr void swap(array&) noexcept(is_nothrow_swappable_v<T>);
    
    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 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;
    constexpr T*       data() noexcept;
    constexpr const T* data() const noexcept;
  };
  template<class T, class... U>
    array(T, U...) -> array<T, 1 + sizeof...(U)>;
}
  In addition to the requirements specified in the container requirements table,
the implicitly-declared move constructor and move assignment operator for 
array
require that 
T be 
Cpp17MoveConstructible or 
Cpp17MoveAssignable,
respectively
. template<class T, class... U>
  array(T, U...) -> array<T, 1 + sizeof...(U)>;
Mandates: 
(is_same_v<T, U> && ...) is 
true. constexpr size_type size() const noexcept;
constexpr T* data() noexcept;
constexpr const T* data() const noexcept;
Returns: A pointer such that [
data(), data() + size()) is a valid range
.  For a
non-empty array, 
data() == addressof(front()) is 
true.constexpr void fill(const T& u);
Effects: As if by 
fill_n(begin(), N, u). constexpr void swap(array& y) noexcept(is_nothrow_swappable_v<T>);
Effects: Equivalent to 
swap_ranges(begin(), end(), y.begin()). [
Note 1: 
Unlike the 
swap function for other containers, 
array::swap
takes linear time, can exit via an exception, and does not cause iterators to
become associated with the other container
. — 
end note]
template<class T, size_t N>
  constexpr void swap(array<T, N>& x, array<T, N>& y) noexcept(noexcept(x.swap(y)));
Constraints: 
N == 0 or 
is_swappable_v<T> is 
true. Effects: As if by 
x.swap(y). array shall provide support for the special case 
N == 0. In the case that 
N == 0, 
begin() == end() == unique value
.The return value of 
data() is unspecified
.The effect of calling 
front() or 
back() for a zero-sized array is
undefined
.Member function 
swap() shall have a
non-throwing exception specification
.template<class T, size_t N>
  constexpr array<remove_cv_t<T>, N> to_array(T (&a)[N]);
Mandates: 
is_array_v<T> is 
false and
is_constructible_v<remove_cv_t<T>, T&> is 
true. Preconditions: 
T meets the 
Cpp17CopyConstructible requirements
. Returns: 
{{ a[0], …, a[N - 1] }}. template<class T, size_t N>
  constexpr array<remove_cv_t<T>, N> to_array(T (&&a)[N]);
Mandates: 
is_array_v<T> is 
false and
is_constructible_v<remove_cv_t<T>, T> is 
true. Preconditions: 
T meets the 
Cpp17MoveConstructible requirements
. Returns: 
{{ std::move(a[0]), …, std::move(a[N - 1]) }}. template<class T, size_t N>
  struct tuple_size<array<T, N>> : integral_constant<size_t, N> { };
template<size_t I, class T, size_t N>
  struct tuple_element<I, array<T, N>> {
    using type = T;
  };
template<size_t I, class T, size_t N>
  constexpr T& get(array<T, N>& a) noexcept;
template<size_t I, class T, size_t N>
  constexpr T&& get(array<T, N>&& a) noexcept;
template<size_t I, class T, size_t N>
  constexpr const T& get(const array<T, N>& a) noexcept;
template<size_t I, class T, size_t N>
  constexpr const T&& get(const array<T, N>&& a) noexcept;
Returns: A reference to the 
Ith element of 
a,
where indexing is zero-based
.  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
.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);
    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;
The member functions in this subclause
do not affect the validity of iterators and references
when inserting elements, and when erasing elements
invalidate iterators and references to the erased elements only
.If an exception is thrown by any of these member functions
there is no effect on the container
.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, [&](const auto& elem) -> bool { 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 
hive is a type of sequence container
that provides constant-time insertion and erasure operations
.Storage is automatically managed in multiple memory blocks,
referred to as 
element blocks.Insertion position is determined by the container, and insertion
may re-use the memory locations of erased elements
. Active blocks which become empty of elements are
either deallocated or become reserved blocks
.Reserved blocks become active blocks when they are used to store elements
.A user can create additional reserved blocks by calling 
reserve. Erasures use unspecified techniques of constant time complexity
to identify the memory locations of erased elements,
which are subsequently skipped during iteration,
as opposed to relocating subsequent elements during erasure
.Active block capacities have
an 
implementation-defined growth factor
(which need not be integral),
for example a new active block's capacity could be equal to
the summed capacities of the pre-existing active blocks
.Limits can be placed on
both the minimum and maximum element capacities of element blocks,
both by users and implementations
.- The minimum limit shall be no larger than the maximum limit .
- When limits are not specified by a user during construction,
the implementation's default limits are used .
- The default limits of an implementation are not guaranteed to be the same as
the minimum and maximum possible capacities
for an implementation's element blocks .
- [ Note 1- :  - To allow latitude for
both implementation-specific and user-directed optimization .
-  —  end note- ] 
- 
The latter are defined as hard limits .
- The maximum hard limit shall be no larger than
 std::allocator_traits<Allocator>::max_size().
- If user-specified limits are not within hard limits, or
if the specified minimum limit is greater than the specified maximum limit,
the behavior is undefined .
- An element block is said to be  within the bounds- 
of a pair of minimum/maximum limits
when its capacity is greater-or-equal-to the minimum limit and
less-than-or-equal-to the maximum limit .
A 
hive conforms to
the requirements for containers (
[container.reqmts]),
with the exception of operators 
== and 
!=.Descriptions are provided here only for operations on 
hive
that are not described in that table or for operations
where there is additional semantic information
.The iterators of 
hive meet
the 
Cpp17BidirectionalIterator requirements
but also model 
three_way_comparable<strong_ordering>.namespace std {
  template<class T, class Allocator = allocator<T>>
  class hive {
  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 hive() noexcept(noexcept(Allocator())) : hive(Allocator()) {}
    constexpr explicit hive(const Allocator&) noexcept;
    constexpr explicit hive(hive_limits block_limits) : hive(block_limits, Allocator()) {}
    constexpr hive(hive_limits block_limits, const Allocator&);
    explicit hive(size_type n, const Allocator& = Allocator());
    hive(size_type n, hive_limits block_limits, const Allocator& = Allocator());
    hive(size_type n, const T& value, const Allocator& = Allocator());
    hive(size_type n, const T& value, hive_limits block_limits, const Allocator& = Allocator());
    template<class InputIterator>
      hive(InputIterator first, InputIterator last, const Allocator& = Allocator());
    template<class InputIterator>
      hive(InputIterator first, InputIterator last, hive_limits block_limits,
           const Allocator& = Allocator());
    template<container-compatible-range<T> R>
      hive(from_range_t, R&& rg, const Allocator& = Allocator());
    template<container-compatible-range<T> R>
      hive(from_range_t, R&& rg, hive_limits block_limits, const Allocator& = Allocator());
    hive(const hive& x);
    hive(hive&&) noexcept;
    hive(const hive& x, const type_identity_t<Allocator>& alloc);
    hive(hive&&, const type_identity_t<Allocator>& alloc);
    hive(initializer_list<T> il, const Allocator& = Allocator());
    hive(initializer_list<T> il, hive_limits block_limits, const Allocator& = Allocator());
    ~hive();
    hive& operator=(const hive& x);
    hive& operator=(hive&& x) noexcept(see below);
    hive& operator=(initializer_list<T>);
    template<class InputIterator>
      void assign(InputIterator first, InputIterator last);
    template<container-compatible-range<T> R>
      void assign_range(R&& rg);
    void assign(size_type n, const T& t);
    void assign(initializer_list<T>);
    allocator_type get_allocator() const noexcept;
    
    iterator                begin() noexcept;
    const_iterator          begin() const noexcept;
    iterator                end() noexcept;
    const_iterator          end() const noexcept;
    reverse_iterator        rbegin() noexcept;
    const_reverse_iterator  rbegin() const noexcept;
    reverse_iterator        rend() noexcept;
    const_reverse_iterator  rend() const noexcept;
    const_iterator          cbegin() const noexcept;
    const_iterator          cend() const noexcept;
    const_reverse_iterator  crbegin() const noexcept;
    const_reverse_iterator  crend() const noexcept;
    
    bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;
    size_type capacity() const noexcept;
    void reserve(size_type n);
    void shrink_to_fit();
    void trim_capacity() noexcept;
    void trim_capacity(size_type n) noexcept;
    constexpr hive_limits block_capacity_limits() const noexcept;
    static constexpr hive_limits block_capacity_default_limits() noexcept;
    static constexpr hive_limits block_capacity_hard_limits() noexcept;
    void reshape(hive_limits block_limits);
    
    template<class... Args> iterator emplace(Args&&... args);
    template<class... Args> iterator emplace_hint(const_iterator hint, Args&&... args);
    iterator insert(const T& x);
    iterator insert(T&& x);
    iterator insert(const_iterator hint, const T& x);
    iterator insert(const_iterator hint, T&& x);
    void insert(initializer_list<T> il);
    template<container-compatible-range<T> R>
      void insert_range(R&& rg);
    template<class InputIterator>
      void insert(InputIterator first, InputIterator last);
    void insert(size_type n, const T& x);
    iterator erase(const_iterator position);
    iterator erase(const_iterator first, const_iterator last);
    void swap(hive&) noexcept(see below);
    void clear() noexcept;
    
    void splice(hive& x);
    void splice(hive&& x);
    template<class BinaryPredicate = equal_to<T>>
      size_type unique(BinaryPredicate binary_pred = BinaryPredicate());
    template<class Compare = less<T>>
      void sort(Compare comp = Compare());
    iterator get_iterator(const_pointer p) noexcept;
    const_iterator get_iterator(const_pointer p) const noexcept;
  private:
    hive_limits current-limits = implementation-defined;     
  };
  template<class InputIterator, class Allocator = allocator<iter-value-type<InputIterator>>>
    hive(InputIterator, InputIterator, Allocator = Allocator())
      -> hive<iter-value-type<InputIterator>, Allocator>;
  template<class InputIterator, class Allocator = allocator<iter-value-type<InputIterator>>>
    hive(InputIterator, InputIterator, hive_limits, Allocator = Allocator())
      -> hive<iter-value-type<InputIterator>, Allocator>;
  template<ranges::input_range R, class Allocator = allocator<ranges::range_value_t<R>>>
    hive(from_range_t, R&&, Allocator = Allocator())
      -> hive<ranges::range_value_t<R>, Allocator>;
  template<ranges::input_range R, class Allocator = allocator<ranges::range_value_t<R>>>
    hive(from_range_t, R&&, hive_limits, Allocator = Allocator())
      -> hive<ranges::range_value_t<R>, Allocator>;
}
 constexpr explicit hive(const Allocator&) noexcept;
Effects: Constructs an empty 
hive, using the specified allocator
. constexpr hive(hive_limits block_limits, const Allocator&);
Effects: Constructs an empty 
hive, using the specified allocator
.  Initializes 
current-limits with 
block_limits.explicit hive(size_type n, const Allocator& = Allocator());
hive(size_type n, hive_limits block_limits, const Allocator& = Allocator());
Preconditions: 
T is 
Cpp17DefaultInsertable into 
hive. Effects: Constructs a 
hive with 
n default-inserted elements,
using the specified allocator
.  If the second overload is called,
also initializes 
current-limits with 
block_limits.hive(size_type n, const T& value, const Allocator& = Allocator());
hive(size_type n, const T& value, hive_limits block_limits, const Allocator& = Allocator());
Preconditions: 
T is 
Cpp17CopyInsertable into 
hive. Effects: Constructs a 
hive with 
n copies of 
value,
using the specified allocator
.  If the second overload is called,
also initializes 
current-limits with 
block_limits.template<class InputIterator>
  hive(InputIterator first, InputIterator last, const Allocator& = Allocator());
template<class InputIterator>
  hive(InputIterator first, InputIterator last, hive_limits block_limits,
       const Allocator& = Allocator());
Effects: Constructs a 
hive equal to the range [
first, last),
using the specified allocator
.  If the second overload is called,
also initializes 
current-limits with 
block_limits.Complexity: Linear in 
distance(first, last). Effects: Constructs a 
hive object with the elements of the range 
rg,
using the specified allocator
.  If the second overload is called,
also initializes 
current-limits with 
block_limits.Complexity: Linear in 
ranges::distance(rg). hive(const hive& x);
hive(const hive& x, const type_identity_t<Allocator>& alloc);
Preconditions: 
T is 
Cpp17CopyInsertable into 
hive. Effects: Constructs a 
hive object with the elements of 
x.  If the second overload is called, uses 
alloc.Initializes 
current-limits with 
x.current-limits.Complexity: Linear in 
x.size(). hive(hive&& x) noexcept;
hive(hive&& x, const type_identity_t<Allocator>& alloc);
Preconditions: For the second overload,
when 
allocator_traits<alloc>::is_always_equal::value is 
false,
T meets the 
Cpp17MoveInsertable requirements
. Effects: When the first overload is called, or
the second overload is called and
alloc == x.get_allocator() is 
true,
current-limits is set to 
x.current-limits and
each element block is moved from 
x into 
*this.  Pointers and references to the elements of 
x now refer to
those same elements but as members of 
*this.Iterators referring to the elements of 
x
will continue to refer to their elements,
but they now behave as iterators into 
*this.If the second overload is called and
alloc == x.get_allocator() is 
false,
each element in 
x is moved into 
*this.References, pointers and iterators referring to the elements of 
x, as well as the past-the-end iterator of 
x, are invalidated
.Postconditions: 
x.empty() is 
true. Complexity: If the second overload is called and
alloc == x.get_allocator() is 
false, linear in 
x.size().  hive(initializer_list<T> il, const Allocator& = Allocator());
hive(initializer_list<T> il, hive_limits block_limits, const Allocator& = Allocator());
Preconditions: 
T is 
Cpp17CopyInsertable into 
hive. Effects: Constructs a 
hive object with the elements of 
il,
using the specified allocator
.  If the second overload is called,
also initializes 
current-limits with 
block_limits.Complexity: Linear in 
il.size(). hive& operator=(const hive& x);
Preconditions: 
T is 
Cpp17CopyInsertable into 
hive and
Cpp17CopyAssignable. Effects: All elements in 
*this are either copy-assigned to, or destroyed
.  All elements in 
x are copied into 
*this.[
Note 1: 
current-limits is unchanged
.  — 
end note]
Complexity: Linear in 
size() + x.size(). hive& operator=(hive&& x)
  noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value ||
           allocator_traits<Allocator>::is_always_equal::value);
Preconditions: When
(allocator_traits<Allocator>::propagate_on_container_move_assignment::value ||
 allocator_traits<Allocator>::is_always_equal::value)
is 
false,
T is 
Cpp17MoveInsertable into 
hive and
Cpp17MoveAssignable. Effects: Each element in 
*this is either move-assigned to, or destroyed
.  When
(allocator_traits<Allocator>::propagate_on_container_move_assignment::value ||
 get_allocator() == x.get_allocator())
is 
true,
current-limits is set to 
x.current-limits and
each element block is moved from 
x into 
*this.Pointers and references to the elements of 
x
now refer to those same elements but as members of 
*this.Iterators referring to the elements of 
x
will continue to refer to their elements,
but they now behave as iterators into 
*this, not into 
x.When
(allocator_traits<Allocator>::propagate_on_container_move_assignment::value ||
 get_allocator() == x.get_allocator())
is 
false,
each element in 
x is moved into 
*this.References, pointers and iterators referring to the elements of 
x,
as well as the past-the-end iterator of 
x, are invalidated
.Postconditions: 
x.empty() is 
true. Complexity: Linear in 
size().  If
(allocator_traits<Allocator>::propagate_on_container_move_assignment::value ||
 get_allocator() == x.get_allocator())
is 
false, also linear in 
x.size().size_type capacity() const noexcept;
Returns: The total number of elements that 
*this can hold
without requiring allocation of more element blocks
. void reserve(size_type n);
Effects: If 
n <= capacity() is 
true, there are no effects
.  Otherwise increases 
capacity() by allocating reserved blocks
.Postconditions: 
capacity() >= n is 
true. Throws: 
length_error if 
n > max_size(),
as well as any exceptions thrown by the allocator
. Complexity: It does not change the size of the sequence and
takes at most linear time in the number of reserved blocks allocated
. Remarks: All references, pointers, and iterators referring to elements in 
*this,
as well as the past-the-end iterator, remain valid
. Preconditions: 
T is 
Cpp17MoveInsertable into 
hive. Effects: 
shrink_to_fit is a non-binding request
to reduce 
capacity() to be closer to 
size().  [
Note 1: 
The request is non-binding
to allow latitude for implementation-specific optimizations
. — 
end note]
It does not increase 
capacity(), but may reduce 
capacity().It may reallocate elements
.If 
capacity() is already equal to 
size(), there are no effects
.If an exception is thrown during allocation of a new element block,
capacity() may be reduced and reallocation may occur
.Otherwise if an exception is thrown, the effects are unspecified
.Complexity: If reallocation happens, linear in the size of the sequence
. Remarks: If reallocation happens,
the order of the elements in 
*this may change and
all references, pointers, and iterators
referring to the elements in 
*this,
as well as the past-the-end iterator, are invalidated
. void trim_capacity() noexcept;
void trim_capacity(size_type n) noexcept;
Effects: For the first overload, all reserved blocks are deallocated, and
capacity() is reduced accordingly
.  For the second overload, 
capacity() is reduced to no less than 
n.Complexity: Linear in the number of reserved blocks deallocated
. Remarks: All references, pointers, and iterators referring to elements in 
*this,
as well as the past-the-end iterator, remain valid
. constexpr hive_limits block_capacity_limits() const noexcept;
static constexpr hive_limits block_capacity_default_limits() noexcept;
Returns: A 
hive_limits struct
with the 
min and 
max members set to
the implementation's default limits
. static constexpr hive_limits block_capacity_hard_limits() noexcept;
Returns: A 
hive_limits struct
with the 
min and 
max members set to
the implementation's hard limits
. void reshape(hive_limits block_limits);
Preconditions: 
T is 
Cpp17MoveInsertable into 
hive. Effects: For any active blocks not within the bounds of 
block_limits,
the elements within those active blocks are reallocated
to new or existing element blocks which are within the bounds
.  Any element blocks not within the bounds of 
block_limits
are deallocated
.If an exception is thrown during allocation of a new element block,
capacity() may be reduced,
reallocation may occur, and
current-limits may be assigned
a value other than 
block_limits.Otherwise 
block_limits is assigned to 
current-limits.If any other exception is thrown the effects are unspecified
.Postconditions: 
size() is unchanged
. Complexity: Linear in the number of element blocks in 
*this.  If reallocation happens, also linear in the number of elements reallocated
.Remarks: This operation may change 
capacity().  If reallocation happens, the order of the elements in 
*this may change
.Reallocation invalidates all references, pointers, and iterators
referring to the elements in 
*this,
as well as the past-the-end iterator
.[
Note 2: 
If no reallocation happens, they remain valid
. — 
end note]
template<class... Args> iterator emplace(Args&&... args);
template<class... Args> iterator emplace_hint(const_iterator hint, Args&&... args);
Preconditions: 
T is 
Cpp17EmplaceConstructible into 
hive from 
args. Effects: Inserts an object of type 
T
constructed with 
std::forward<Args>(args)....  The 
hint parameter is ignored
.If an exception is thrown, there are no effects
.[
Note 1: 
args can directly or indirectly refer to a value in 
*this.  — 
end note]
Returns: An iterator that points to the new element
.  Exactly one object of type 
T is constructed
. Remarks: Invalidates the past-the-end iterator
. iterator insert(const T& x);
iterator insert(const_iterator hint, const T& x);
iterator insert(T&& x);
iterator insert(const_iterator hint, T&& x);
Effects: Equivalent to: 
return emplace(std::forward<decltype(x)>(x));
[
Note 2: 
The 
hint parameter is ignored
. — 
end note]
 Preconditions: 
T is 
Cpp17EmplaceInsertable into 
hive
from 
*ranges::begin(rg).  rg and 
*this do not overlap
. Effects: Inserts copies of elements in 
rg.  Each iterator in the range 
rg is dereferenced exactly once
.Complexity: Linear in the number of elements inserted
.  Exactly one object of type 
T is constructed for each element inserted
.Remarks: If an element is inserted, invalidates the past-the-end iterator
. void insert(size_type n, const T& x);
Preconditions: 
T is 
Cpp17CopyInsertable into 
hive. Effects: Inserts 
n copies of 
x.  Exactly one object of type 
T is constructed for each element inserted
. Remarks: If an element is inserted, invalidates the past-the-end iterator
. template<class InputIterator>
  void insert(InputIterator first, InputIterator last);
Effects: Equivalent to 
insert_range(ranges::subrange(first, last)). iterator erase(const_iterator position);
iterator erase(const_iterator first, const_iterator last);
Complexity: Linear in the number of elements erased
.  Additionally, if any active blocks become empty of elements
as a result of the function call,
at worst linear in the number of element blocks
.Remarks: Invalidates references, pointers and iterators
referring to the erased elements
.  An erase operation that erases the last element in 
*this
also invalidates the past-the-end iterator
.void swap(hive& x)
  noexcept(allocator_traits<Allocator>::propagate_on_container_swap::value ||
           allocator_traits<Allocator>::is_always_equal::value);
Effects: Exchanges the contents, 
capacity(), and 
current-limits
of 
*this with that of 
x. 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 
hive and 
n is an integer,
are the same as those of 
next(i, n) and 
prev(i, n), respectively
.void splice(hive& x);
void splice(hive&& x);
Preconditions: 
get_allocator() == x.get_allocator() is 
true. Effects: If 
addressof(x) == this is 
true,
the behavior is erroneous and there are no effects
.  Otherwise, inserts the contents of 
x into 
*this 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 continue to refer to their elements,
but they now behave as iterators into 
*this, not into 
x.Throws: 
length_error if any of 
x's active blocks
are not within the bounds of 
current-limits. Complexity: Linear in the sum of
all element blocks in 
x plus all element blocks in 
*this. Remarks: Reserved blocks in 
x are not transferred into 
*this.  If 
addressof(x) == this is 
false,
invalidates the past-the-end iterator for both 
x and 
*this.template<class BinaryPredicate = equal_to<T>>
  size_type unique(BinaryPredicate binary_pred = BinaryPredicate());
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 
hive,
erases all elements referred to by the iterator 
i
in the range [
begin() + 1, end())
for which 
binary_pred(*i, *(i - 1)) is 
true.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
. Remarks: Invalidates references, pointers, and iterators
referring to the erased elements
.  If the last element in 
*this is erased,
also invalidates the past-the-end iterator
.template<class Compare = less<T>>
  void sort(Compare comp = Compare());
Preconditions: 
T is 
Cpp17MoveInsertable into 
hive,
Cpp17MoveAssignable, and 
Cpp17Swappable. Effects: Sorts 
*this according to the 
comp function object
.  If an exception is thrown,
the order of the elements in 
*this is unspecified
.Complexity: 
O(NlogN) comparisons, where 
N is 
size().  References, pointers, and iterators referring to elements in 
*this,
as well as the past-the-end iterator, may be invalidated
. iterator get_iterator(const_pointer p) noexcept;
const_iterator get_iterator(const_pointer p) const noexcept;
Preconditions: 
p points to an element in 
*this. Returns: An 
iterator or 
const_iterator
pointing to the same element as 
p. Complexity: Linear in the number of active blocks in 
*this. template<class T, class Allocator, class U = T>
  typename hive<T, Allocator>::size_type
    erase(hive<T, Allocator>& c, const U& value);
Effects: Equivalent to:
return erase_if(c, [&](const auto& elem) -> bool { return elem == value; });
template<class T, class Allocator, class Predicate>
  typename hive<T, Allocator>::size_type
    erase_if(hive<T, 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
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> constexpr 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
.void sort();
template<class Compare> 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 is 
size(). template<class T, class Allocator, class U = T>
  typename list<T, Allocator>::size_type
    constexpr erase(list<T, Allocator>& c, const U& value);
Effects: Equivalent to:
return erase_if(c, [&](const auto& elem) -> bool { return elem == value; });
template<class T, class Allocator, class Predicate>
  typename list<T, Allocator>::size_type
    constexpr erase_if(list<T, Allocator>& c, Predicate pred);
Effects: Equivalent to: return c.remove_if(pred);
A
vector
is a sequence container that supports
(amortized) constant time insert and erase operations at the end;
insert and erase in the middle take linear time
.Storage management is handled automatically, though hints can be given
to improve efficiency
. The exceptions are the
push_front, 
prepend_range, 
pop_front, and 
emplace_front member functions, which are not
provided
.Descriptions are provided here only for operations on 
vector
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 vector {
  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 vector() noexcept(noexcept(Allocator())) : vector(Allocator()) { }
    constexpr explicit vector(const Allocator&) noexcept;
    constexpr explicit vector(size_type n, const Allocator& = Allocator());
    constexpr vector(size_type n, const T& value, const Allocator& = Allocator());
    template<class InputIterator>
      constexpr vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
    template<container-compatible-range<T> R>
      constexpr vector(from_range_t, R&& rg, const Allocator& = Allocator());
    constexpr vector(const vector& x);
    constexpr vector(vector&&) noexcept;
    constexpr vector(const vector&, const type_identity_t<Allocator>&);
    constexpr vector(vector&&, const type_identity_t<Allocator>&);
    constexpr vector(initializer_list<T>, const Allocator& = Allocator());
    constexpr ~vector();
    constexpr vector& operator=(const vector& x);
    constexpr vector& operator=(vector&& x)
      noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value ||
               allocator_traits<Allocator>::is_always_equal::value);
    constexpr vector& 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& u);
    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 size_type capacity() const noexcept;
    constexpr void      resize(size_type sz);
    constexpr void      resize(size_type sz, const T& c);
    constexpr void      reserve(size_type n);
    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;
    
    constexpr T*       data() noexcept;
    constexpr const T* data() const noexcept;
    
    template<class... Args> constexpr reference emplace_back(Args&&... args);
    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> constexpr 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 first, const_iterator last);
    constexpr void     swap(vector&)
      noexcept(allocator_traits<Allocator>::propagate_on_container_swap::value ||
               allocator_traits<Allocator>::is_always_equal::value);
    constexpr void     clear() noexcept;
  };
  template<class InputIterator, class Allocator = allocator<iter-value-type<InputIterator>>>
    vector(InputIterator, InputIterator, Allocator = Allocator())
      -> vector<iter-value-type<InputIterator>, Allocator>;
  template<ranges::input_range R, class Allocator = allocator<ranges::range_value_t<R>>>
    vector(from_range_t, R&&, Allocator = Allocator())
      -> vector<ranges::range_value_t<R>, Allocator>;
}
  T shall be complete before any member of the resulting specialization
of 
vector is referenced
.  constexpr explicit vector(const Allocator&) noexcept;
Effects: Constructs an empty 
vector, using the
specified allocator
. constexpr explicit vector(size_type n, const Allocator& = Allocator());
Preconditions: 
T is 
Cpp17DefaultInsertable into 
vector. Effects: Constructs a 
vector with 
n
default-inserted elements using the specified allocator
. constexpr vector(size_type n, const T& value,
                 const Allocator& = Allocator());
Preconditions: 
T is
Cpp17CopyInsertable into 
vector. Effects: Constructs a 
vector with 
n
copies of 
value, using the specified allocator
. template<class InputIterator>
  constexpr vector(InputIterator first, InputIterator last,
                   const Allocator& = Allocator());
Effects: Constructs a 
vector equal to the
range [
first, last), using the specified allocator
. Complexity: Makes only 
N
calls to the copy constructor of
T
(where 
N
is the distance between
first
and
last)
and no reallocations if
InputIterator meets the 
Cpp17ForwardIterator requirements
.  It makes order
N
calls to the copy constructor of
T
and order
logN
reallocations if they are just input iterators
.Effects: Constructs a 
vector object with the elements of the range 
rg,
using the specified allocator
. Complexity: Initializes exactly 
N elements
from the results of dereferencing successive iterators of 
rg,
where 
N is 
ranges::distance(rg). Performs no reallocations if:
Otherwise, performs order 
logN reallocations and
order 
N calls to the copy or move constructor of 
T.constexpr size_type capacity() const noexcept;
Returns: The total number of elements that the vector can hold
without requiring reallocation
. Complexity: Constant time
. constexpr void reserve(size_type n);
Preconditions: 
T is 
Cpp17MoveInsertable into 
vector. Effects: A directive that informs a
vector
of a planned change in size, so that it can manage the storage allocation accordingly
.  After
reserve(),
capacity()
is greater or equal to the argument of
reserve
if reallocation happens; and equal to the previous value of
capacity()
otherwise
.Reallocation happens at this point if and only if the current capacity is less than the
argument of
reserve().If an exception is thrown
other than by the move constructor of a non-
Cpp17CopyInsertable type,
there are no effects
.Throws: 
length_error if 
n >
max_size(). Complexity: It does not change the size of the sequence and takes at most linear
time in the size of the sequence
. Remarks: Reallocation invalidates all the references, pointers, and iterators
referring to the elements in the sequence, as well as the past-the-end iterator
.  [
Note 1: 
If no reallocation happens, they remain valid
. — 
end note]
No reallocation shall take place during insertions that happen
after a call to 
reserve()
until an insertion would make the size of the vector
greater than the value of 
capacity().constexpr void shrink_to_fit();
Preconditions: 
T is 
Cpp17MoveInsertable into 
vector. Effects: 
shrink_to_fit is a non-binding request to reduce
capacity() to 
size().  [
Note 2: 
The request is non-binding to allow latitude for
implementation-specific optimizations
. — 
end note]
It does not increase 
capacity(), but may reduce 
capacity()
by causing reallocation
.If an exception is thrown other than by the move constructor
of a non-
Cpp17CopyInsertable T, there are no effects
.Complexity: If reallocation happens,
linear in the size of the sequence
. Remarks: Reallocation invalidates all the references, pointers, and iterators
referring to the elements in the sequence as well as the past-the-end iterator
.  [
Note 3: 
If no reallocation happens, they remain valid
. — 
end note]
constexpr void swap(vector& x)
  noexcept(allocator_traits<Allocator>::propagate_on_container_swap::value ||
           allocator_traits<Allocator>::is_always_equal::value);
Effects: Exchanges the contents and
capacity()
of
*this
with that of 
x. Complexity: Constant time
. constexpr void resize(size_type sz);
Preconditions: 
T is
Cpp17MoveInsertable and 
Cpp17DefaultInsertable into 
vector. Effects: If 
sz < size(), erases the last 
size() - sz elements
from the sequence
.  Otherwise,
appends 
sz - size() default-inserted elements to the sequence
.Remarks: If an exception is thrown other than by the move constructor of a non-
Cpp17CopyInsertable
T, there are no effects
. constexpr void resize(size_type sz, const T& c);
Preconditions: 
T is
Cpp17CopyInsertable into 
vector. Effects: If 
sz < size(), erases the last 
size() - sz elements
from the sequence
.  Otherwise,
appends 
sz - size() copies of 
c to the sequence
.Remarks: If an exception is thrown, there are no effects
. constexpr T*       data() noexcept;
constexpr const T* data() const noexcept;
Returns: A pointer such that [
data(), data() + size()) is a valid range
.  For a
non-empty vector, 
data() == addressof(front()) is 
true.Complexity: Constant time
. 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_back(Args&&... args);
template<class... Args> constexpr iterator emplace(const_iterator position, Args&&... args);
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: If reallocation happens,
linear in the number of elements of the resulting vector;
otherwise,
linear in the number of elements inserted plus the distance
to the end of the vector
. Remarks: Causes reallocation if the new size is greater than the old capacity
.  Reallocation invalidates all the references, pointers, and iterators
referring to the elements in the sequence, as well as the past-the-end iterator
.If no reallocation happens, then
references, pointers, and iterators
before the insertion point remain valid
but those at or after the insertion point,
including the past-the-end iterator,
are invalidated
.If an exception is thrown other than by
the copy constructor, move constructor,
assignment operator, or move assignment operator of
T or by any 
InputIterator operation,
there are no effects
.If an exception is thrown while inserting a single element at the end and
T is 
Cpp17CopyInsertable or 
is_nothrow_move_constructible_v<T>
is 
true, there are no effects
.Otherwise, if an exception is thrown by the move constructor of a non-
Cpp17CopyInsertable
T, the effects are unspecified
.For the declarations taking a range 
R,
performs at most one reallocation if:
For the declarations taking a pair of 
InputIterator,
performs at most one reallocation if
InputIterator meets the 
Cpp17ForwardIterator requirements
.constexpr iterator erase(const_iterator position);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void pop_back();
Effects: Invalidates iterators and references at or after the point of the erase
. Throws: Nothing unless an exception is thrown by the
assignment operator or move assignment operator of
T. Complexity: The destructor of 
T is called the number of times equal to the
number of the elements erased, but the assignment operator
of 
T is called the number of times equal to the number of
elements in the vector after the erased elements
. template<class T, class Allocator, class U = T>
  constexpr typename vector<T, Allocator>::size_type
    erase(vector<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 vector<T, Allocator>::size_type
    erase_if(vector<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;
To optimize space allocation, a partial specialization of 
vector for
bool elements is provided:
namespace std {
  template<class Allocator>
  class vector<bool, Allocator> {
  public:
    
    using value_type             = bool;
    using allocator_type         = Allocator;
    using pointer                = implementation-defined;
    using const_pointer          = implementation-defined;
    using const_reference        = bool;
    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>;
    
    class reference {
    public:
      constexpr reference(const reference&) = default;
      constexpr ~reference();
      constexpr operator bool() const noexcept;
      constexpr reference& operator=(bool x) noexcept;
      constexpr reference& operator=(const reference& x) noexcept;
      constexpr const reference& operator=(bool x) const noexcept;
      constexpr void flip() noexcept;   
    };
    
    constexpr vector() noexcept(noexcept(Allocator())) : vector(Allocator()) { }
    constexpr explicit vector(const Allocator&) noexcept;
    constexpr explicit vector(size_type n, const Allocator& = Allocator());
    constexpr vector(size_type n, const bool& value, const Allocator& = Allocator());
    template<class InputIterator>
      constexpr vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
    template<container-compatible-range<bool> R>
      constexpr vector(from_range_t, R&& rg, const Allocator& = Allocator());
    constexpr vector(const vector& x);
    constexpr vector(vector&& x) noexcept;
    constexpr vector(const vector&, const type_identity_t<Allocator>&);
    constexpr vector(vector&&, const type_identity_t<Allocator>&);
    constexpr vector(initializer_list<bool>, const Allocator& = Allocator());
    constexpr ~vector();
    constexpr vector& operator=(const vector& x);
    constexpr vector& operator=(vector&& x)
      noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value ||
               allocator_traits<Allocator>::is_always_equal::value);
    constexpr vector& operator=(initializer_list<bool>);
    template<class InputIterator>
      constexpr void assign(InputIterator first, InputIterator last);
    template<container-compatible-range<bool> R>
      constexpr void assign_range(R&& rg);
    constexpr void assign(size_type n, const bool& t);
    constexpr void assign(initializer_list<bool>);
    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 size_type capacity() const noexcept;
    constexpr void      resize(size_type sz, bool c = false);
    constexpr void      reserve(size_type n);
    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_back(Args&&... args);
    constexpr void push_back(const bool& x);
    template<container-compatible-range<bool> R>
      constexpr void append_range(R&& rg);
    constexpr void pop_back();
    template<class... Args> constexpr iterator emplace(const_iterator position, Args&&... args);
    constexpr iterator insert(const_iterator position, const bool& x);
    constexpr iterator insert(const_iterator position, size_type n, const bool& x);
    template<class InputIterator>
      constexpr iterator insert(const_iterator position,
                                InputIterator first, InputIterator last);
    template<container-compatible-range<bool> R>
      constexpr iterator insert_range(const_iterator position, R&& rg);
    constexpr iterator insert(const_iterator position, initializer_list<bool> il);
    constexpr iterator erase(const_iterator position);
    constexpr iterator erase(const_iterator first, const_iterator last);
    constexpr void swap(vector&)
      noexcept(allocator_traits<Allocator>::propagate_on_container_swap::value ||
               allocator_traits<Allocator>::is_always_equal::value);
    static constexpr void swap(reference x, reference y) noexcept;
    constexpr void flip() noexcept;     
    constexpr void clear() noexcept;
  };
}
Unless described below, all operations have the same requirements and
semantics as the primary 
vector template, except that operations
dealing with the 
bool value type map to bit values in the
container storage and
allocator_traits::construct
is not used to construct these values
.There is no requirement that the data be stored as a contiguous allocation
of 
bool values
.A space-optimized representation of bits is
recommended instead
.reference
is a class that simulates the behavior of references of a single bit in
vector<bool>.  The conversion function returns 
true
when the bit is set, and 
false otherwise
.The assignment operators
set the bit when the argument is (convertible to) 
true and
clear it otherwise
.flip reverses the state of the bit
. constexpr void flip() noexcept;
Effects: Replaces each element in the container with its complement
. static constexpr void swap(reference x, reference y) noexcept;
Effects: Exchanges the contents of x and y as if by:
bool b = x;
x = y;
y = b;
template<class Allocator> struct hash<vector<bool, Allocator>>;
template<class T>
  constexpr bool is-vector-bool-reference = see below;
The expression
is-vector-bool-reference<T> is 
true
if 
T denotes the type 
vector<bool, Alloc>::reference
for some type 
Alloc and
vector<bool, Alloc> is not a program-defined specialization
.namespace std {
  template<class T, class charT>
    requires is-vector-bool-reference<T>
  struct formatter<T, charT> {
  private:
    formatter<bool, charT> underlying_;       
  public:
    template<class ParseContext>
      constexpr typename ParseContext::iterator
        parse(ParseContext& ctx);
    template<class FormatContext>
      typename FormatContext::iterator
        format(const T& ref, FormatContext& ctx) const;
  };
}
 Equivalent to: return underlying_.parse(ctx);
Equivalent to: return underlying_.format(ref, ctx);
An 
inplace_vector is a contiguous container
.Its capacity is fixed and
its elements are stored within the 
inplace_vector object itself
. The exceptions are the
push_front,
prepend_range,
pop_front, and
emplace_front
member functions, which are not provided
.Descriptions are provided here only
for operations on 
inplace_vector that
are not described in one of these tables or
for operations where there is additional semantic information
. For any 
N,
inplace_vector<T, N>::iterator and
inplace_vector<T, N>::const_iterator
meet the constexpr iterator requirements
.Any member function of 
inplace_vector<T, N> that
would cause the size to exceed 
N
throws an exception of type 
bad_alloc.Let 
IV denote a specialization of 
inplace_vector<T, N>.If 
N is zero, then
IV is trivially copyable and empty, and
std::is_trivially_default_constructible_v<IV> is 
true.Otherwise:
- If  is_trivially_copy_constructible_v<T>-  is  true- , then
 IV-  has a trivial copy constructor .
- If  is_trivially_move_constructible_v<T>-  is  true- , then
 IV-  has a trivial move constructor .
- If  is_trivially_destructible_v<T>-  is  true- , then:
   - IV has a trivial destructor.
- If
  is_trivially_copy_constructible_v<T> && is_trivially_copy_assignable_v<T>
  is true, then
  IV has a trivial copy assignment operator.
- If
  is_trivially_move_constructible_v<T> && is_trivially_move_assignable_v<T>
  is true, then
  IV has a trivial move assignment operator.
 
namespace std {
  template<class T, size_t N>
  class inplace_vector {
  public:
    
    using value_type             = T;
    using pointer                = T*;
    using const_pointer          = const T*;
    using reference              = value_type&;
    using const_reference        = const value_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>;
    
    constexpr inplace_vector() noexcept;
    constexpr explicit inplace_vector(size_type n);                         
    constexpr inplace_vector(size_type n, const T& value);                  
    template<class InputIterator>
      constexpr inplace_vector(InputIterator first, InputIterator last);    
    template<container-compatible-range<T> R>
      constexpr inplace_vector(from_range_t, R&& rg);                       
    constexpr inplace_vector(const inplace_vector&);
    constexpr inplace_vector(inplace_vector&&)
      noexcept(N == 0 || is_nothrow_move_constructible_v<T>);
    constexpr inplace_vector(initializer_list<T> il);                       
    constexpr ~inplace_vector();
    constexpr inplace_vector& operator=(const inplace_vector& other);
    constexpr inplace_vector& operator=(inplace_vector&& other)
      noexcept(N == 0 || (is_nothrow_move_assignable_v<T> &&
                          is_nothrow_move_constructible_v<T>));
    constexpr inplace_vector& 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& u);                         
    constexpr void assign(initializer_list<T> il);                          
    
    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;
    static constexpr size_type max_size() noexcept;
    static constexpr size_type capacity() noexcept;
    constexpr void resize(size_type sz);                                    
    constexpr void resize(size_type sz, const T& c);                        
    static constexpr void reserve(size_type n);                             
    static constexpr void shrink_to_fit() noexcept;
    
    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;
    
    constexpr       T* data()       noexcept;
    constexpr const T* data() const noexcept;
    
    template<class... Args>
      constexpr reference emplace_back(Args&&... args);                     
    constexpr reference push_back(const T& x);                              
    constexpr reference push_back(T&& x);                                   
    template<container-compatible-range<T> R>
      constexpr void append_range(R&& rg);                                  
    constexpr void pop_back();
    template<class... Args>
      constexpr pointer try_emplace_back(Args&&... args);
    constexpr pointer try_push_back(const T& x);
    constexpr pointer try_push_back(T&& x);
    template<container-compatible-range<T> R>
      constexpr ranges::borrowed_iterator_t<R> try_append_range(R&& rg);
    template<class... Args>
      constexpr reference unchecked_emplace_back(Args&&... args);
    constexpr reference unchecked_push_back(const T& x);
    constexpr reference unchecked_push_back(T&& x);
    template<class... Args>
      constexpr 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 first, const_iterator last);
    constexpr void swap(inplace_vector& x)
      noexcept(N == 0 || (is_nothrow_swappable_v<T> &&
                          is_nothrow_move_constructible_v<T>));
    constexpr void clear() noexcept;
    friend constexpr bool operator==(const inplace_vector& x,
                                     const inplace_vector& y);
    friend constexpr synth-three-way-result<T>
      operator<=>(const inplace_vector& x, const inplace_vector& y);
    friend constexpr void swap(inplace_vector& x, inplace_vector& y)
      noexcept(N == 0 || (is_nothrow_swappable_v<T> &&
                          is_nothrow_move_constructible_v<T>))
      { x.swap(y); }
  };
}
 constexpr explicit inplace_vector(size_type n);
Preconditions: 
T is 
Cpp17DefaultInsertable into 
inplace_vector. Effects: Constructs an 
inplace_vector with 
n default-inserted elements
. constexpr inplace_vector(size_type n, const T& value);
Preconditions: 
T is 
Cpp17CopyInsertable into 
inplace_vector. Effects: Constructs an 
inplace_vector with 
n copies of 
value. template<class InputIterator>
  constexpr inplace_vector(InputIterator first, InputIterator last);
Effects: Constructs an 
inplace_vector equal to the range [
first, last)
. Complexity: Linear in 
distance(first, last). Effects: Constructs an 
inplace_vector with
the elements of the range 
rg. Complexity: Linear in 
ranges::distance(rg). static constexpr size_type capacity() noexcept;
static constexpr size_type max_size() noexcept;
constexpr void resize(size_type sz);
Preconditions: 
T is 
Cpp17DefaultInsertable into 
inplace_vector. Effects: If 
sz < size(),
erases the last 
size() - sz elements from the sequence
.  Otherwise,
appends 
sz - size() default-inserted elements to the sequence
.Remarks: If an exception is thrown, there are no effects on 
*this. constexpr void resize(size_type sz, const T& c);
Preconditions: 
T is 
Cpp17CopyInsertable into 
inplace_vector. Effects: If 
sz < size(),
erases the last 
size() - sz elements from the sequence
.  Otherwise,
appends 
sz - size() copies of 
c to the sequence
.Remarks: If an exception is thrown, there are no effects on 
*this. static constexpr void reserve(size_type n);
Throws: 
bad_alloc if 
n > capacity() is 
true. static constexpr void shrink_to_fit() noexcept;
constexpr       T* data()       noexcept;
constexpr const T* data() const noexcept;
Returns: A pointer such that [
data(), data() + size()) is a valid range
.  For a non-empty 
inplace_vector,
data() == addressof(front()) is 
true.Complexity: Constant time
. 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);
template<class... Args>
  constexpr iterator emplace(const_iterator position, Args&&... args);
template<container-compatible-range<T> R>
  constexpr void append_range(R&& rg);
Let 
n be the value of 
size() before this call for
the 
append_range overload, and
distance(begin, position) otherwise
.Complexity: Linear in the number of elements inserted plus
the distance to the end of the vector
. Remarks: If an exception is thrown other than by the
copy constructor,
move constructor,
assignment operator, or
move assignment operator
of 
T or by
any 
InputIterator operation,
there are no effects
.  Otherwise,
if an exception is thrown, then
size()  ≥ n and
elements in the range 
begin() + [0, n) are not modified
.constexpr reference push_back(const T& x);
constexpr reference push_back(T&& x);
template<class... Args>
  constexpr reference emplace_back(Args&&... args);
Throws: 
bad_alloc or
any exception thrown by the initialization of the inserted element
. Remarks: If an exception is thrown, there are no effects on 
*this. template<class... Args>
  constexpr pointer try_emplace_back(Args&&... args);
constexpr pointer try_push_back(const T& x);
constexpr pointer try_push_back(T&& x);
Let 
vals denote a pack:
- std::forward<Args>(args)... for the first overload,
- x for the second overload,
- std::move(x) for the third overload.
Preconditions: 
value_type is 
Cpp17EmplaceConstructible
into 
inplace_vector from 
vals.... Effects: If 
size() < capacity() is 
true,
appends an object of type 
T
direct-non-list-initialized with 
vals....  Otherwise, there are no effects
.Returns: 
nullptr if 
size() == capacity() is 
true,
otherwise 
addressof(back()). Throws: Nothing unless an exception is thrown by the initialization of the inserted element
. Remarks: If an exception is thrown, there are no effects on 
*this. Preconditions: value_type is Cpp17EmplaceConstructible
into inplace_vector from
 Effects: Appends copies of initial elements in 
rg before 
end(),
until all elements are inserted or 
size() == capacity() is 
true.  Each iterator in the range 
rg is dereferenced at most once
.Returns: An iterator pointing to the first element of 
rg
that was not inserted into 
*this,
or 
ranges::end(rg) if no such element exists
. Complexity: Linear in the number of elements inserted
. Remarks: Let 
n be the value of 
size() prior to this call
.  If an exception is thrown after the insertion of 
k elements, then
size() equals 
n+k,
elements in the range 
begin() + [0, n) are not modified, and
elements in the range 
begin() + [n, n+k) correspond to
the inserted elements
.template<class... Args>
  constexpr reference unchecked_emplace_back(Args&&... args);
Preconditions: 
size() < capacity() is 
true. Effects: Equivalent to:
return *try_emplace_back(std::forward<Args>(args)...);
constexpr reference unchecked_push_back(const T& x);
constexpr reference unchecked_push_back(T&& x);
Preconditions: 
size() < capacity() is 
true. Effects: Equivalent to:
return *try_push_back(std::forward<decltype(x)>(x));
constexpr iterator erase(const_iterator position);
constexpr iterator erase(const_iterator first, const_iterator last);
constexpr void pop_back();
Effects: Invalidates iterators and references at or after the point of the erase
. Throws: Nothing unless an exception is thrown by
the assignment operator or move assignment operator of 
T. Complexity: The destructor of 
T is called the number of times
equal to the number of the elements erased, but
the assignment operator of 
T is called the number of times
equal to the number of elements after the erased elements
. template<class T, size_t N, class U = T>
  constexpr size_t erase(inplace_vector<T, N>& 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, size_t N, class Predicate>
  constexpr size_t erase_if(inplace_vector<T, N>& 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;
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 {
    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);
    constexpr pair<iterator, bool> insert(const value_type& x);
    constexpr pair<iterator, bool> 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>
  typename map<Key, T, Compare, Allocator>::size_type
    constexpr 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 {
    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> 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>
  typename multimap<Key, T, Compare, Allocator>::size_type
    constexpr 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();
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> constexpr 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>;
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> constexpr explicit 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)
and value-initializes 
comp;
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). template<class InputIterator>
  constexpr 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, InputIterator first, InputIterator last,
                         const key_compare& comp = key_compare())
        : c(), compare(comp) { insert(sorted_unique, first, last); }
    template<container-compatible-range<value_type> R>
      constexpr flat_map(from_range_t, R&& rg)
        : flat_map(from_range, 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, initializer_list<value_type> il,
                       const key_compare& comp = key_compare())
        : flat_map(sorted_unique, 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;
    
    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, initializer_list<value_type> il)
      { insert(sorted_unique, 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;
    friend constexpr bool operator==(const flat_map& x, const flat_map& y);
    friend constexpr synth-three-way-result<value_type>
      operator<=>(const flat_map& x, const flat_map& y);
    friend constexpr 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, 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);
Effects: Equivalent to 
flat_map(sorted_unique, key_cont, mapped_cont) and
flat_map(sorted_unique, 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 = upper_bound(c.keys.begin(), c.keys.end(), 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, InputIterator first, InputIterator last,
                              const key_compare& comp = key_compare())
        : c(), compare(comp) { insert(sorted_equivalent, first, last); }
    template<container-compatible-range<value_type> R>
      constexpr flat_multimap(from_range_t, R&& rg)
        : flat_multimap(from_range, 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, initializer_list<value_type> il,
                            const key_compare& comp = key_compare())
        : flat_multimap(sorted_equivalent, 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);
    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;
    
    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, initializer_list<value_type> il)
      { insert(sorted_equivalent, 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;
    friend constexpr bool operator==(const flat_multimap& x, const flat_multimap& y);
    friend constexpr synth-three-way-result<value_type>
      operator<=>(const flat_multimap& x, const flat_multimap& y);
    friend constexpr 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.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);
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, 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);
Effects: Equivalent to 
flat_multimap(sorted_equivalent, key_cont, mapped_cont) and
flat_multimap(sorted_equivalent, 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]
 
#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);
}
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, R&& rg)
        : flat_set(from_range, 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, initializer_list<value_type> il,
             const key_compare& comp = key_compare())
        : flat_set(sorted_unique, 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;
    
    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> constexpr 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, initializer_list<value_type> il)
      { insert(sorted_unique, 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;
    friend constexpr bool operator==(const flat_set& x, const flat_set& y);
    friend constexpr synth-three-way-result<value_type>
      operator<=>(const flat_set& x, const flat_set& y);
    friend constexpr 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, 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);
Effects: Equivalent to
flat_set(sorted_unique, cont) and
flat_set(sorted_unique, 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, R&& rg)
        : flat_multiset(from_range, std::forward<R>(rg), key_compare()) { }
    template<container-compatible-range<value_type> R>
      constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp)
        : flat_multiset(comp)
        { insert_range(std::forward<R>(rg)); }
    constexpr flat_multiset(initializer_list<value_type> il,
                            const key_compare& comp = key_compare())
      : flat_multiset(il.begin(), il.end(), comp) { }
    constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il,
                            const key_compare& comp = key_compare())
        : flat_multiset(sorted_equivalent, 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;
    
    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, initializer_list<value_type> il)
      { insert(sorted_equivalent, 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;
    friend constexpr bool operator==(const flat_multiset& x, const flat_multiset& y);
    friend constexpr synth-three-way-result<value_type>
      operator<=>(const flat_multiset& x, const flat_multiset& y);
    friend constexpr 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, 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);
Effects: Equivalent to 
flat_multiset(sorted_equivalent, cont) and
flat_multiset(sorted_equivalent, 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]
 The header 
 defines the view 
span.The header 
 defines the class template 
mdspan and
other facilities for interacting with these multidimensional views
.A 
span is a view over a contiguous sequence of objects,
the storage of which is owned by some other object
.All member functions of 
span have constant time complexity
.namespace std {
  template<class ElementType, size_t Extent = dynamic_extent>
  class span {
  public:
    
    using element_type = ElementType;
    using value_type = remove_cv_t<ElementType>;
    using size_type = size_t;
    using difference_type = ptrdiff_t;
    using pointer = element_type*;
    using const_pointer = const element_type*;
    using reference = element_type&;
    using const_reference = const element_type&;
    using iterator = implementation-defined;        
    using const_iterator = std::const_iterator<iterator>;
    using reverse_iterator = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::const_iterator<reverse_iterator>;
    static constexpr size_type extent = Extent;
    
    constexpr span() noexcept;
    template<class It>
      constexpr explicit(extent != dynamic_extent) span(It first, size_type count);
    template<class It, class End>
      constexpr explicit(extent != dynamic_extent) span(It first, End last);
    template<size_t N>
      constexpr span(type_identity_t<element_type> (&arr)[N]) noexcept;
    template<class T, size_t N>
      constexpr span(array<T, N>& arr) noexcept;
    template<class T, size_t N>
      constexpr span(const array<T, N>& arr) noexcept;
    template<class R>
      constexpr explicit(extent != dynamic_extent) span(R&& r);
    constexpr explicit(extent != dynamic_extent) span(std::initializer_list<value_type> il);
    constexpr span(const span& other) noexcept = default;
    template<class OtherElementType, size_t OtherExtent>
      constexpr explicit(see below) span(const span<OtherElementType, OtherExtent>& s) noexcept;
    constexpr span& operator=(const span& other) noexcept = default;
    
    template<size_t Count>
      constexpr span<element_type, Count> first() const;
    template<size_t Count>
      constexpr span<element_type, Count> last() const;
    template<size_t Offset, size_t Count = dynamic_extent>
      constexpr span<element_type, see below> subspan() const;
    constexpr span<element_type, dynamic_extent> first(size_type count) const;
    constexpr span<element_type, dynamic_extent> last(size_type count) const;
    constexpr span<element_type, dynamic_extent> subspan(
      size_type offset, size_type count = dynamic_extent) const;
    
    constexpr size_type size() const noexcept;
    constexpr size_type size_bytes() const noexcept;
    constexpr bool empty() const noexcept;
    
    constexpr reference operator[](size_type idx) const;
    constexpr reference at(size_type idx) const;                            
    constexpr reference front() const;
    constexpr reference back() const;
    constexpr pointer data() const noexcept;
    
    constexpr iterator begin() const noexcept;
    constexpr iterator end() const noexcept;
    constexpr const_iterator cbegin() const noexcept { return begin(); }
    constexpr const_iterator cend() const noexcept { return end(); }
    constexpr reverse_iterator rbegin() const noexcept;
    constexpr reverse_iterator rend() const noexcept;
    constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); }
    constexpr const_reverse_iterator crend() const noexcept { return rend(); }
  private:
    pointer data_;              
    size_type size_;            
  };
  template<class It, class EndOrSize>
    span(It, EndOrSize) -> span<remove_reference_t<iter_reference_t<It>>,
                                maybe-static-ext<EndOrSize>>;
  template<class T, size_t N>
    span(T (&)[N]) -> span<T, N>;
  template<class T, size_t N>
    span(array<T, N>&) -> span<T, N>;
  template<class T, size_t N>
    span(const array<T, N>&) -> span<const T, N>;
  template<class R>
    span(R&&) -> span<remove_reference_t<ranges::range_reference_t<R>>>;
}
 ElementType is required to be
a complete object type that is not an abstract class type
. For a 
span s,
any operation that invalidates a pointer in
the range [
s.data(), s.data() + s.size())
invalidates pointers, iterators, and references to elements of 
s.constexpr span() noexcept;
Constraints: 
Extent == dynamic_extent || Extent == 0 is 
true. Postconditions: 
size() == 0 && data() == nullptr. template<class It>
  constexpr explicit(extent != dynamic_extent) span(It first, size_type count);
Constraints: Let 
U be 
remove_reference_t<iter_reference_t<It>>.  - is_convertible_v<U(*)[], element_type(*)[]>-  is  true.
 - [ Note 1- :  - The intent is to allow only qualification conversions
of the iterator reference type to  element_type.
-  —  end note- ] 
Preconditions: 
- [ first, first + count- ) is a valid range .
 Hardened preconditions: If 
extent is not equal to 
dynamic_extent,
then 
count == extent is 
true. Effects: Initializes 
data_ with 
to_address(first) and
size_ with 
count. template<class It, class End>
  constexpr explicit(extent != dynamic_extent) span(It first, End last);
Constraints: Let 
U be 
remove_reference_t<iter_reference_t<It>>.  - is_convertible_v<U(*)[], element_type(*)[]>-  is  true.
 - [ Note 2- :  - The intent is to allow only qualification conversions
of the iterator reference type to  element_type.
-  —  end note- ] 
- is_convertible_v<End, size_t>-  is  false.
 
Preconditions: 
- [ first, last- ) is a valid range .
 Hardened preconditions: If 
extent is not equal to 
dynamic_extent,
then 
(last - first) == extent is 
true. Effects: Initializes 
data_ with 
to_address(first) and
size_ with 
last - first. Throws: When and what 
last - first throws
. template<size_t N> constexpr span(type_identity_t<element_type> (&arr)[N]) noexcept;
template<class T, size_t N> constexpr span(array<T, N>& arr) noexcept;
template<class T, size_t N> constexpr span(const array<T, N>& arr) noexcept;
Constraints: Let 
U be 
remove_pointer_t<decltype(std::data(arr))>.  - extent == dynamic_extent || N == extent is true, and
- is_convertible_v<U(*)[], element_type(*)[]> is true. [ Note 3:  The intent is to allow only qualification conversions
of the array element type to  element_type.
 —  end note] 
Effects: Constructs a 
span that is a view over the supplied array
.  [
Note 4: 
type_identity_t affects class template argument deduction
.  — 
end note]
Postconditions: 
size() == N && data() == std::data(arr) is 
true. template<class R> constexpr explicit(extent != dynamic_extent) span(R&& r);
Constraints: Let 
U be 
remove_reference_t<ranges::range_reference_t<R>>.  - Either  R-  satisfies  ranges::borrowed_range-  or
 is_const_v<element_type>-  is  true.
- remove_cvref_t<R>-  is not a specialization of  span.
 
- remove_cvref_t<R>-  is not a specialization of  array.
 
- is_array_v<remove_cvref_t<R>>-  is  false.
 
- is_convertible_v<U(*)[], element_type(*)[]>-  is  true.
 - [ Note 5- :  - The intent is to allow only qualification conversions
of the range reference type to  element_type.
-  —  end note- ] 
Hardened preconditions: If 
extent is not equal to 
dynamic_extent,
then 
ranges::size(r) == extent is 
true. Effects: Initializes 
data_ with 
ranges::data(r) and
size_ with 
ranges::size(r). Throws: What and when 
ranges::data(r) and 
ranges::size(r) throw
. constexpr explicit(extent != dynamic_extent) span(std::initializer_list<value_type> il);
Constraints: 
is_const_v<element_type> is 
true. Hardened preconditions: If 
extent is not equal to 
dynamic_extent,
then 
il.size() == extent is 
true. Effects: Initializes 
data_ with 
il.begin() and
size_ with 
il.size(). constexpr span(const span& other) noexcept = default;
Postconditions: 
other.size() == size() && other.data() == data(). template<class OtherElementType, size_t OtherExtent>
  constexpr explicit(see below) span(const span<OtherElementType, OtherExtent>& s) noexcept;
Constraints: 
- extent == dynamic_extent || OtherExtent == dynamic_extent || extent == OtherExtent is true, and
- is_convertible_v<OtherElementType(*)[], element_type(*)[]> is true. [ Note 6:  The intent is to allow only qualification conversions
of the  OtherElementType to  element_type.
 —  end note] 
 Hardened preconditions: If 
extent is not equal to 
dynamic_extent,
then 
s.size() == extent is 
true. Effects: Constructs a 
span that is a view over the range
[
s.data(), s.data() + s.size())
. Postconditions: 
size() == s.size() && data() == s.data(). Remarks: The expression inside explicit is equivalent to:
extent != dynamic_extent && OtherExtent == dynamic_extent
constexpr span& operator=(const span& other) noexcept = default;
Postconditions: 
size() == other.size() && data() == other.data(). template<class It, class EndOrSize>
  span(It, EndOrSize) -> span<remove_reference_t<iter_reference_t<It>>,
                              maybe-static-ext<EndOrSize>>;
template<class R>
  span(R&&) -> span<remove_reference_t<ranges::range_reference_t<R>>>;
template<size_t Count> constexpr span<element_type, Count> first() const;
Mandates: 
Count <= Extent is 
true. Hardened preconditions: 
Count <= size() is 
true. Effects: Equivalent to: 
return R{data(), Count};
where 
R is the return type
. template<size_t Count> constexpr span<element_type, Count> last() const;
Mandates: 
Count <= Extent is 
true. Hardened preconditions: 
Count <= size() is 
true. Effects: Equivalent to: 
return R{data() + (size() - Count), Count};
where 
R is the return type
. template<size_t Offset, size_t Count = dynamic_extent>
  constexpr span<element_type, see below> subspan() const;
Mandates: 
Offset <= Extent && (Count == dynamic_extent || Count <= Extent - Offset)
is 
true. Hardened preconditions: 
Offset <= size() && (Count == dynamic_extent || Count <= size() - Offset)
is 
true. Effects: Equivalent to:
return span<ElementType, see below>(
  data() + Offset, Count != dynamic_extent ? Count : size() - Offset);
Remarks: The second template argument of the returned span type is:
Count != dynamic_extent ? Count
                        : (Extent != dynamic_extent ? Extent - Offset
                                                    : dynamic_extent)
constexpr span<element_type, dynamic_extent> first(size_type count) const;
Hardened preconditions: 
count <= size() is 
true. Effects: Equivalent to: return {data(), count};
constexpr span<element_type, dynamic_extent> last(size_type count) const;
Hardened preconditions: 
count <= size() is 
true. Effects: Equivalent to: return {data() + (size() - count), count};
constexpr span<element_type, dynamic_extent> subspan(
  size_type offset, size_type count = dynamic_extent) const;
Hardened preconditions: 
offset <= size() && (count == dynamic_extent || count <= size() - offset)
is 
true. Effects: Equivalent to:
return {data() + offset, count == dynamic_extent ? size() - offset : count};
constexpr size_type size() const noexcept;
Effects: Equivalent to: return size_;
constexpr size_type size_bytes() const noexcept;
Effects: Equivalent to: return size() * sizeof(element_type);
constexpr bool empty() const noexcept;
Effects: Equivalent to: return size() == 0;
constexpr reference operator[](size_type idx) const;
Hardened preconditions: 
idx < size() is 
true. Returns: 
*(data() + idx). constexpr reference at(size_type idx) const;
Returns: 
*(data() + idx). Throws: 
out_of_range if 
idx >= size() is 
true. constexpr reference front() const;
Hardened preconditions: 
empty() is 
false. constexpr reference back() const;
Hardened preconditions: 
empty() is 
false. Returns: 
*(data() + (size() - 1)). constexpr pointer data() const noexcept;
using iterator = implementation-defined;
All requirements on container iterators (
[container.reqmts]) apply to
span::iterator as well
.constexpr iterator begin() const noexcept;
Returns: An iterator referring to the first element in the span
.  If 
empty() is 
true, then it returns the
same value as 
end().constexpr iterator end() const noexcept;
Returns: An iterator which is the past-the-end value
. constexpr reverse_iterator rbegin() const noexcept;
Effects: Equivalent to: return reverse_iterator(end());
constexpr reverse_iterator rend() const noexcept;
Effects: Equivalent to: return reverse_iterator(begin());
template<class ElementType, size_t Extent>
  span<const byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>
    as_bytes(span<ElementType, Extent> s) noexcept;
Effects: Equivalent to: 
return R{reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
where 
R is the return type
. template<class ElementType, size_t Extent>
  span<byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>
    as_writable_bytes(span<ElementType, Extent> s) noexcept;
Constraints: 
is_const_v<ElementType> is 
false. Effects: Equivalent to: 
return R{reinterpret_cast<byte*>(s.data()), s.size_bytes()};
where 
R is the return type
.  Each interval can be represented by a half-open range 
[Li,Ui),
where 
Li and 
Ui are the lower and upper bounds of
the 
ith dimension
.The 
rank of a multidimensional index space is
the number of intervals it represents
. An integer 
r is a 
rank index of an index space 
S
if 
r is in the range 
[0,rank of S).A pack of integers 
idx is
a 
multidimensional index in a multidimensional index space 
S
(or representation thereof) if both of the following are true:
- sizeof...(idx) is equal to the rank of S, and
- for every rank index i of S,
the ith value of idx is an integer
in the interval [Li,Ui) of S.
The class template 
extents represents
a multidimensional index space of rank equal to 
sizeof...(Extents).In 
[views],
extents is used synonymously with multidimensional index space
.namespace std {
  template<class IndexType, size_t... Extents>
  class extents {
  public:
    using index_type = IndexType;
    using size_type = make_unsigned_t<index_type>;
    using rank_type = size_t;
    
    static constexpr rank_type rank() noexcept { return sizeof...(Extents); }
    static constexpr rank_type rank_dynamic() noexcept { return dynamic-index(rank()); }
    static constexpr size_t static_extent(rank_type) noexcept;
    constexpr index_type extent(rank_type) const noexcept;
    
    constexpr extents() noexcept = default;
    template<class OtherIndexType, size_t... OtherExtents>
      constexpr explicit(see below)
        extents(const extents<OtherIndexType, OtherExtents...>&) noexcept;
    template<class... OtherIndexTypes>
      constexpr explicit extents(OtherIndexTypes...) noexcept;
    template<class OtherIndexType, size_t N>
      constexpr explicit(N != rank_dynamic())
        extents(span<OtherIndexType, N>) noexcept;
    template<class OtherIndexType, size_t N>
      constexpr explicit(N != rank_dynamic())
        extents(const array<OtherIndexType, N>&) noexcept;
    
    template<class OtherIndexType, size_t... OtherExtents>
      friend constexpr bool operator==(const extents&,
                                       const extents<OtherIndexType, OtherExtents...>&) noexcept;
    
    constexpr size_t fwd-prod-of-extents(rank_type) const noexcept;     
    constexpr size_t rev-prod-of-extents(rank_type) const noexcept;     
    template<class OtherIndexType>
      static constexpr auto index-cast(OtherIndexType&&) noexcept;      
  private:
    static constexpr rank_type dynamic-index(rank_type) noexcept;       
    static constexpr rank_type dynamic-index-inv(rank_type) noexcept;   
    array<index_type, rank_dynamic()> dynamic-extents{};                
  };
  template<class... Integrals>
    explicit extents(Integrals...)
      -> see below;
}
 Mandates: 
- IndexType is a signed or unsigned integer type, and
- each element of Extents is either equal to dynamic_extent, or
is representable as a value of type IndexType.
 Each specialization of 
extents models 
regular and
is trivially copyable
.Let 
Er be the 
rth element of 
Extents.Let 
Dr be the value of 
dynamic-extents[dynamic-index(r)]
if 
Er is a dynamic extent,
otherwise 
Er.The 
rth interval of the multidimensional index space
represented by an 
extents object is 
[0,Dr).static constexpr rank_type dynamic-index(rank_type i) noexcept;
Preconditions: 
i <= rank() is 
true. Returns: The number of 
Er with 
r<i for which 
Er is a dynamic extent
. static constexpr rank_type dynamic-index-inv(rank_type i) noexcept;
Preconditions: 
i < rank_dynamic() is 
true. Returns: The minimum value of 
r
such that 
dynamic-index(r + 1) == i + 1 is 
true. constexpr size_t fwd-prod-of-extents(rank_type i) const noexcept;
Preconditions: 
i <= rank() is 
true. Returns: If 
i > 0 is 
true,
the product of 
extent(k) for all 
k in the range 
[0, i),
otherwise 
1. constexpr size_t rev-prod-of-extents(rank_type i) const noexcept;
Preconditions: 
i < rank() is 
true. Returns: If 
i + 1 < rank() is 
true,
the product of 
extent(k)
for all 
k in the range 
[i + 1, rank()),
otherwise 
1. template<class OtherIndexType>
  static constexpr auto index-cast(OtherIndexType&& i) noexcept;
Effects: 
- If OtherIndexType is an integral type other than bool,
then equivalent to return i;,
- otherwise, equivalent to return static_cast<index_type>(i);.
  [
Note 1: 
This function will always return an integral type other than 
bool.Since this function's call sites are constrained on
convertibility of 
OtherIndexType to 
index_type,
integer-class types can use the 
static_cast branch
without loss of precision
. — 
end note]
template<class OtherIndexType, size_t... OtherExtents>
  constexpr explicit(see below)
    extents(const extents<OtherIndexType, OtherExtents...>& other) noexcept;
Constraints: 
- sizeof...(OtherExtents) == rank()-  is  true.
 
- ((OtherExtents == dynamic_extent || Extents == dynamic_extent || OtherExtents ==
 Extents) && ...)-  is  true.
 
 Preconditions: 
- other.extent(r) equals Er
for each r for which Er is a static extent, and
- either
- sizeof...(OtherExtents) is zero, or
- other.extent(r) is representable as
a value of type index_type for every rank index r of other.
 
 Postconditions: 
*this == other is 
true. Remarks: The expression inside explicit is equivalent to:
(((Extents != dynamic_extent) && (OtherExtents == dynamic_extent)) || ... ) ||
(numeric_limits<index_type>::max() < numeric_limits<OtherIndexType>::max())
template<class... OtherIndexTypes>
  constexpr explicit extents(OtherIndexTypes... exts) noexcept;
Let 
N be 
sizeof...(OtherIndexTypes),
and let 
exts_arr be
array<index_type, N>{static_cast<
index_type>(std::move(exts))...}.Constraints: 
- (is_convertible_v<OtherIndexTypes, index_type> && ...) is true,
- (is_nothrow_constructible_v<index_type, OtherIndexTypes> && ...) is true, and
- N == rank_dynamic() || N == rank() is true. [ Note 1:  One can construct  extents from just dynamic extents,
which are all the values getting stored, or
from all the extents with a precondition .
 —  end note] 
 Preconditions: 
- If N != rank_dynamic() is true,
exts_arr[r] equals Er
for each r for which Er is a static extent, and
- either
- sizeof...(exts) == 0 is true, or
- each element of exts is representable
as a nonnegative value of type index_type.
 
 Postconditions: 
*this == extents(exts_arr) is 
true. template<class OtherIndexType, size_t N>
  constexpr explicit(N != rank_dynamic())
    extents(span<OtherIndexType, N> exts) noexcept;
template<class OtherIndexType, size_t N>
  constexpr explicit(N != rank_dynamic())
    extents(const array<OtherIndexType, N>& exts) noexcept;
Constraints: 
- is_convertible_v<const OtherIndexType&, index_type> is true,
- is_nothrow_constructible_v<index_type, const OtherIndexType&> is true, and
- N == rank_dynamic() || N == rank() is true.
 Preconditions: 
- If N != rank_dynamic() is true,
exts[r] equals Er for each r for which Er is a static extent, and
- either
- N is zero, or
- exts[r] is representable
as a nonnegative value of type index_type for every rank index r.
 
 Effects: 
- If  N-  equals  rank_dynamic()- ,
for all  d-  in the range  [0, rank_dynamic())- ,
direct-non-list-initializes  dynamic-extents[d]- 
with  as_const(exts[d]).
- Otherwise, for all  d-  in the range  [0, rank_dynamic())- ,
direct-non-list-initializes  dynamic-extents[d]- 
with  as_const(exts[dynamic-index-inv(d)]).
 template<class... Integrals>
  explicit extents(Integrals...) -> see below;
Constraints: 
(is_convertible_v<Integrals, size_t> && ...) is 
true. static constexpr size_t static_extent(rank_type i) noexcept;
Preconditions: 
i < rank() is 
true. constexpr index_type extent(rank_type i) const noexcept;
Preconditions: 
i < rank() is 
true. template<class OtherIndexType, size_t... OtherExtents>
  friend constexpr bool operator==(const extents& lhs,
                                   const extents<OtherIndexType, OtherExtents...>& rhs) noexcept;
Returns: 
true if 
lhs.rank() equals 
rhs.rank() and
if 
lhs.extent(r) equals 
rhs.extent(r)
for every rank index 
r of 
rhs,
otherwise 
false. template<class IndexType, size_t Rank>
  using dextents = see below;
Result: A type 
E that is a specialization of 
extents
such that 
E::rank() == Rank && E::rank() == E::rank_dynamic() is 
true, and
E::index_type denotes 
IndexType. template<size_t Rank, class IndexType = size_t>
  using dims = see below;
Result: A type 
E that is a specialization of 
extents
such that 
E::rank() == Rank && E::rank() == E::rank_dynamic() is 
true, and
E::index_type denotes 
IndexType. - M-  denotes a layout mapping class .
 
- m-  denotes a (possibly const) value of type  M.
 
- i-  and  j-  are packs of (possibly const) integers
that are multidimensional indices in  m.extents()-  ( [mdspan.overview]- ) .
 - [ Note 1- :  - The type of each element of the packs can be a different integer type .
-  —  end note- ] 
- r-  is a (possibly const) rank index of  typename M::extents_type.
 
- dr-  is a pack of (possibly const) integers
for which  sizeof...(dr) == M::extents_type::rank()-  is  true- ,
the  rth-  element is equal to 1, and
all other elements are equal to 0 .
 
In 
[mdspan.layout.reqmts] through 
[mdspan.layout.stride]:
- Let is-mapping-of be the exposition-only variable template defined as follows:
template<class Layout, class Mapping>
constexpr bool is-mapping-of =  
  is_same_v<typename Layout::template mapping<typename Mapping::extents_type>, Mapping>;
- Let is-layout-left-padded-mapping-of be
the exposition-only variable template defined as follows:
template<class Mapping>
constexpr bool is-layout-left-padded-mapping-of = see below;   
where is-layout-left-padded-mapping-of<Mapping> is true
if and only if Mapping denotes
a specialization of layout_left_padded<S>::mapping
for some value S of type size_t.
- Let is-layout-right-padded-mapping-of be
the exposition-only variable template defined as follows:
template<class Mapping>
constexpr bool is-layout-right-padded-mapping-of = see below;   
where is-layout-right-padded-mapping-of<Mapping> is true
if and only if Mapping denotes
a specialization of layout_right_padded<S>::mapping
for some value S of type size_t.
- For nonnegative integers x and y,
let LEAST-MULTIPLE-AT-LEAST(x,y) denote
- y if x is zero,
- otherwise, the least multiple of x that is greater than or equal to y.
 
- M models copyable and equality_comparable,
- is_nothrow_move_constructible_v<M> is true,
- is_nothrow_move_assignable_v<M> is true,
- is_nothrow_swappable_v<M> is true, and
- the following types and expressions are well-formed and
have the specified semantics.
Result: A type that is a specialization of 
extents. Result: 
typename M::extents_type::index_type. Result: 
typename M::extents_type::rank_type. Result: const typename M::extents_type&
Result: typename M::index_type
Returns: A nonnegative integer
less than 
numeric_limits<typename M::index_type>::max() and
less than or equal to 
numeric_limits<size_t>::max(). m(i...) == m(static_cast<typename M::index_type>(i)...)
Result: typename M::index_type
Returns: If the size of the multidimensional index space 
m.extents() is 0,
then 
0,
else 
1 plus the maximum value of 
m(i...) for all 
i. Returns: 
true only if
for every 
i and 
j where 
(i != j || ...) is 
true,
m(i...) != m(j...) is 
true.  [
Note 1: 
A mapping can return 
false even if the condition is met
.For certain layouts, it is possibly not feasible to determine efficiently
whether the layout is unique
. — 
end note]
Returns: 
true only if
for all 
k in the range 
[0, m.required_span_size())
there exists an 
i such that 
m(i...) equals 
k.  [
Note 2: 
A mapping can return 
false even if the condition is met
.For certain layouts, it is possibly not feasible to determine efficiently
whether the layout is exhaustive
. — 
end note]
Returns: 
true only if
for every rank index 
r of 
m.extents() there exists an integer 
sr
such that,
for all 
i where 
(i+dr) is
a multidimensional index in 
m.extents() (
[mdspan.overview]),
m((i + dr)...) - m(i...) equals 
sr.  [
Note 3: 
This implies that for a strided layout
m(i0,…,ik)=m(0,…,0)+i0×s0+⋯+ik×sk. — 
end note]
[
Note 4: 
A mapping can return 
false even if the condition is met
.For certain layouts, it is possibly not feasible to determine efficiently
whether the layout is strided
. — 
end note]
Preconditions: 
m.is_strided() is 
true. Result: typename M::index_type
Returns: 
sr as defined in 
m.is_strided() above
. [
Note 5: 
It is not required for 
m.stride(r) to be well-formed
if 
m.extents().rank() is zero,
even if 
m.is_always_strided() is 
true. — 
end note]
Returns: 
true only if 
m.is_unique() is 
true
for all possible objects 
m of type 
M.  [
Note 6: 
A mapping can return 
false even if the above condition is met
.For certain layout mappings, it is possibly not feasible to determine
whether every instance is unique
. — 
end note]
M::is_always_exhaustive()
Returns: 
true only if 
m.is_exhaustive() is 
true
for all possible objects 
m of type 
M.  [
Note 7: 
A mapping can return 
false even if the above condition is met
.For certain layout mappings, it is possibly not feasible to determine
whether every instance is exhaustive
. — 
end note]
Returns: 
true only if 
m.is_strided() is 
true
for all possible objects 
m of type 
M.  [
Note 8: 
A mapping can return 
false even if the above condition is met
.For certain layout mappings, it is possibly not feasible to determine
whether every instance is strided
. — 
end note]
A type 
MP meets the 
layout mapping policy requirements
if for a type 
E that is a specialization of 
extents,
MP::mapping<E> is valid and denotes a type 
X
that meets the layout mapping requirements (
[mdspan.layout.reqmts]), and
for which the 
qualified-id X::layout_type is valid and
denotes the type 
MP and
the 
qualified-id X::extents_type denotes 
E.namespace std {
  struct layout_left {
    template<class Extents>
      class mapping;
  };
  struct layout_right {
    template<class Extents>
      class mapping;
  };
  struct layout_stride {
    template<class Extents>
      class mapping;
  };
  template<size_t PaddingValue>
  struct layout_left_padded {
    template<class Extents> class mapping;
  };
  template<size_t PaddingValue>
  struct layout_right_padded {
    template<class Extents> class mapping;
  };
}
Each of 
layout_left, 
layout_right, and 
layout_stride,
as well as each specialization of
layout_left_padded and 
layout_right_padded,
meets the layout mapping policy requirements and is a trivially copyable type
.Furthermore,
is_trivially_default_constructible_v<T> is 
true
for any such type 
T.layout_left provides a layout mapping
where the leftmost extent has stride 1, and
strides increase left-to-right as the product of extents
. namespace std {
  template<class Extents>
  class layout_left::mapping {
  public:
    using extents_type = Extents;
    using index_type = typename extents_type::index_type;
    using size_type = typename extents_type::size_type;
    using rank_type = typename extents_type::rank_type;
    using layout_type = layout_left;
    
    constexpr mapping() noexcept = default;
    constexpr mapping(const mapping&) noexcept = default;
    constexpr mapping(const extents_type&) noexcept;
    template<class OtherExtents>
      constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
        mapping(const mapping<OtherExtents>&) noexcept;
    template<class OtherExtents>
      constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
        mapping(const layout_right::mapping<OtherExtents>&) noexcept;
    template<class LayoutLeftPaddedMapping>
      constexpr explicit(!is_convertible_v<typename LayoutLeftPaddedMapping::extents_type,
                                           extents_type>)
        mapping(const LayoutLeftPaddedMapping&) noexcept;
    template<class OtherExtents>
      constexpr explicit(extents_type::rank() > 0)
        mapping(const layout_stride::mapping<OtherExtents>&);
    constexpr mapping& operator=(const mapping&) noexcept = default;
    
    constexpr const extents_type& extents() const noexcept { return extents_; }
    constexpr index_type required_span_size() const noexcept;
    template<class... Indices>
      constexpr index_type operator()(Indices...) const noexcept;
    static constexpr bool is_always_unique() noexcept { return true; }
    static constexpr bool is_always_exhaustive() noexcept { return true; }
    static constexpr bool is_always_strided() noexcept { return true; }
    static constexpr bool is_unique() noexcept { return true; }
    static constexpr bool is_exhaustive() noexcept { return true; }
    static constexpr bool is_strided() noexcept { return true; }
    constexpr index_type stride(rank_type) const noexcept;
    template<class OtherExtents>
      friend constexpr bool operator==(const mapping&, const mapping<OtherExtents>&) noexcept;
  private:
    extents_type extents_{};                                               
    
    template<class... SliceSpecifiers>
      constexpr auto submdspan-mapping-impl(SliceSpecifiers...) const     
        -> see below;
    template<class... SliceSpecifiers>
      friend constexpr auto submdspan_mapping(
        const mapping& src, SliceSpecifiers... slices) {
          return src.submdspan-mapping-impl(slices...);
      }
  };
}
If 
Extents is not a specialization of 
extents,
then the program is ill-formed
.layout_left::mapping<E> is a trivially copyable type
that models 
regular for each 
E. Mandates: If 
Extents::rank_dynamic() == 0 is 
true,
then the size of the multidimensional index space 
Extents()
is representable as a value of type 
typename Extents::index_type. constexpr mapping(const extents_type& e) noexcept;
Preconditions: The size of the multidimensional index space 
e
is representable as a value of type 
index_type (
[basic.fundamental])
. Effects: Direct-non-list-initializes 
extents_ with 
e. template<class OtherExtents>
  constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
    mapping(const mapping<OtherExtents>& other) noexcept;
Constraints: 
is_constructible_v<extents_type, OtherExtents> is 
true. Preconditions: 
other.required_span_size() is representable as
a value of type 
index_type (
[basic.fundamental])
. Effects: Direct-non-list-initializes 
extents_ with 
other.extents(). template<class OtherExtents>
  constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
    mapping(const layout_right::mapping<OtherExtents>& other) noexcept;
Constraints: 
- extents_type::rank() <= 1 is true, and
- is_constructible_v<extents_type, OtherExtents> is true.
 Preconditions: 
other.required_span_size() is representable as
a value of type 
index_type (
[basic.fundamental])
. Effects: Direct-non-list-initializes 
extents_ with 
other.extents(). template<class LayoutLeftPaddedMapping>
  constexpr explicit(!is_convertible_v<typename LayoutLeftPaddedMapping::extents_type,
                                       extents_type>)
    mapping(const LayoutLeftPaddedMapping&) noexcept;
Constraints: 
- is-layout-left-padded-mapping-of<LayoutLeftPaddedMapping>-  is  true.
 
- is_constructible_v<extents_type, typename LayoutLeftPaddedMapping::extents_type>- is  true.
 
 Mandates: If
- Extents::rank() is greater than one,
- Extents::static_extent(0) does not equal dynamic_extent, and
- LayoutLeftPaddedMapping::static-padding-stride
does not equal dynamic_extent,
then 
Extents::static_extent(0) equals
LayoutLeftPaddedMapping::static-padding-stride. Preconditions: 
- If  extents_type::rank() > 1-  is  true- ,
then  other.stride(1)-  equals  other.extents(0).
- other.required_span_size()-  is representable as
a value of type  index_type.
 
 Effects: Direct-non-list-initializes 
extents_ with 
other.extents(). template<class OtherExtents>
  constexpr explicit(extents_type::rank() > 0)
    mapping(const layout_stride::mapping<OtherExtents>& other);
Constraints: 
is_constructible_v<extents_type, OtherExtents> is 
true. Preconditions: 
- If extents_type::rank() > 0 is true,
then for all r in the range [0, extents_type::rank()),
other.stride(r) equals
other.extents().fwd-prod-of-extents(r), and
- other.required_span_size() is representable as
a value of type index_type ([basic.fundamental]).
 Effects: Direct-non-list-initializes 
extents_ with 
other.extents(). constexpr index_type required_span_size() const noexcept;
Returns: 
extents().fwd-prod-of-extents(extents_type::rank()). template<class... Indices>
  constexpr index_type operator()(Indices... i) const noexcept;
Constraints: 
- sizeof...(Indices) == extents_type::rank() is true,
- (is_convertible_v<Indices, index_type> && ...) is true, and
- (is_nothrow_constructible_v<index_type, Indices> && ...) is true.
 Preconditions: 
extents_type::index-cast(i) is
a multidimensional index in 
extents_ (
[mdspan.overview])
. Effects: Let 
P be a parameter pack such that
is_same_v<index_sequence_for<Indices...>, index_sequence<P...>>
is 
true.  Equivalent to:
return ((static_cast<index_type>(i) * stride(P)) + ... + 0);
constexpr index_type stride(rank_type i) const noexcept;
Constraints: 
extents_type::rank() > 0 is 
true. Preconditions: 
i < extents_type::rank() is 
true. Returns: 
extents().fwd-prod-of-extents(i). template<class OtherExtents>
  friend constexpr bool operator==(const mapping& x, const mapping<OtherExtents>& y) noexcept;
Constraints: 
extents_type::rank() == OtherExtents::rank() is 
true. Effects: Equivalent to: return x.extents() == y.extents();
layout_right provides a layout mapping
where the rightmost extent is stride 1, and
strides increase right-to-left as the product of extents
. namespace std {
  template<class Extents>
  class layout_right::mapping {
  public:
    using extents_type = Extents;
    using index_type = typename extents_type::index_type;
    using size_type = typename extents_type::size_type;
    using rank_type = typename extents_type::rank_type;
    using layout_type = layout_right;
    
    constexpr mapping() noexcept = default;
    constexpr mapping(const mapping&) noexcept = default;
    constexpr mapping(const extents_type&) noexcept;
    template<class OtherExtents>
      constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
        mapping(const mapping<OtherExtents>&) noexcept;
    template<class OtherExtents>
      constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
        mapping(const layout_left::mapping<OtherExtents>&) noexcept;
    template<class LayoutRightPaddedMapping>
      constexpr explicit(!is_convertible_v<typename LayoutRightPaddedMapping::extents_type,
                                           extents_type>)
        mapping(const LayoutRightPaddedMapping&) noexcept;
    template<class OtherExtents>
      constexpr explicit(extents_type::rank() > 0)
        mapping(const layout_stride::mapping<OtherExtents>&) noexcept;
    constexpr mapping& operator=(const mapping&) noexcept = default;
    
    constexpr const extents_type& extents() const noexcept { return extents_; }
    constexpr index_type required_span_size() const noexcept;
    template<class... Indices>
      constexpr index_type operator()(Indices...) const noexcept;
    static constexpr bool is_always_unique() noexcept { return true; }
    static constexpr bool is_always_exhaustive() noexcept { return true; }
    static constexpr bool is_always_strided() noexcept { return true; }
    static constexpr bool is_unique() noexcept { return true; }
    static constexpr bool is_exhaustive() noexcept { return true; }
    static constexpr bool is_strided() noexcept { return true; }
    constexpr index_type stride(rank_type) const noexcept;
    template<class OtherExtents>
      friend constexpr bool operator==(const mapping&, const mapping<OtherExtents>&) noexcept;
  private:
    extents_type extents_{};    
    
    template<class... SliceSpecifiers>
      constexpr auto submdspan-mapping-impl(SliceSpecifiers...) const       
        -> see below;
    template<class... SliceSpecifiers>
      friend constexpr auto submdspan_mapping(
        const mapping& src, SliceSpecifiers... slices) {
          return src.submdspan-mapping-impl(slices...);
      }
  };
}
If 
Extents is not a specialization of 
extents,
then the program is ill-formed
.layout_right::mapping<E> is a trivially copyable type
that models 
regular for each 
E. Mandates: If 
Extents::rank_dynamic() == 0 is 
true,
then the size of the multidimensional index space 
Extents()
is representable as a value of type 
typename Extents::index_type. constexpr mapping(const extents_type& e) noexcept;
Preconditions: The size of the multidimensional index space 
e is representable as
a value of type 
index_type (
[basic.fundamental])
. Effects: Direct-non-list-initializes 
extents_ with 
e. template<class OtherExtents>
  constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
    mapping(const mapping<OtherExtents>& other) noexcept;
Constraints: 
is_constructible_v<extents_type, OtherExtents> is 
true. Preconditions: 
other.required_span_size() is representable as
a value of type 
index_type (
[basic.fundamental])
. Effects: Direct-non-list-initializes 
extents_ with 
other.extents(). template<class OtherExtents>
  constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
    mapping(const layout_left::mapping<OtherExtents>& other) noexcept;
Constraints: 
- extents_type::rank() <= 1 is true, and
- is_constructible_v<extents_type, OtherExtents> is true.
 Preconditions: 
other.required_span_size() is representable as
a value of type 
index_type (
[basic.fundamental])
. Effects: Direct-non-list-initializes 
extents_ with 
other.extents(). template<class LayoutRightPaddedMapping>
  constexpr explicit(!is_convertible_v<typename LayoutRightPaddedMapping::extents_type,
                                       extents_type>)
    mapping(const LayoutRightPaddedMapping&) noexcept;
Constraints: 
- is-layout-right-padded-mapping-of<LayoutRightPaddedMapping>- 
is  true.
 
- is_constructible_v<extents_type, typename LayoutRightPaddedMapping::extents_-
 type>- 
is  true.
 
 Mandates: If
- Extents::rank() is greater than one,
- Extents::static_extent(Extents::rank() - 1)
does not equal dynamic_extent, and
- LayoutRightPaddedMapping::static-padding-stride
does not equal dynamic_extent,
then 
Extents::static_extent(Extents::rank() - 1) equals
LayoutRightPaddedMapping::static-padding-stride. Preconditions: 
- If  extents_type::rank() > 1-  is  true- ,
then  other.stride(extents_type::rank() - 2)- equals
 other.extents().extent(extents_type::rank() - 1).
- other.required_span_size()-  is representable as
a value of type  index_type.
 
 Effects: Direct-non-list-initializes 
extents_ with 
other.extents(). template<class OtherExtents>
 constexpr explicit(extents_type::rank() > 0)
    mapping(const layout_stride::mapping<OtherExtents>& other) noexcept;
Constraints: 
is_constructible_v<extents_type, OtherExtents> is 
true. Preconditions: 
- If  extents_type::rank() > 0-  is  true- ,
then for all  r-  in the range  [0, extents_type::rank())- ,
 other.stride(r)-  equals
 other.extents().rev-prod-of-extents(r).
 Effects: Direct-non-list-initializes 
extents_ with 
other.extents(). constexpr index_type required_span_size() const noexcept;
Returns: 
extents().fwd-prod-of-extents(extents_type::rank()). template<class... Indices>
  constexpr index_type operator()(Indices... i) const noexcept;
Constraints: 
- sizeof...(Indices) == extents_type::rank() is true,
- (is_convertible_v<Indices, index_type> && ...) is true, and
- (is_nothrow_constructible_v<index_type, Indices> && ...) is
true.
 Preconditions: 
extents_type::index-cast(i) is
a multidimensional index in 
extents_ (
[mdspan.overview])
. Effects: Let 
P be a parameter pack such that
is_same_v<index_sequence_for<Indices...>, index_sequence<P...>>
is 
true.  Equivalent to:
return ((static_cast<index_type>(i) * stride(P)) + ... + 0);
constexpr index_type stride(rank_type i) const noexcept;
Constraints: 
extents_type::rank() > 0 is 
true. Preconditions: 
i < extents_type::rank() is 
true. Returns: 
extents().rev-prod-of-extents(i). template<class OtherExtents>
  friend constexpr bool operator==(const mapping& x, const mapping<OtherExtents>& y) noexcept;
Constraints: 
extents_type::rank() == OtherExtents::rank() is 
true. Effects: Equivalent to: return x.extents() == y.extents();
layout_stride provides a layout mapping
where the strides are user-defined
. namespace std {
  template<class Extents>
  class layout_stride::mapping {
  public:
    using extents_type = Extents;
    using index_type = typename extents_type::index_type;
    using size_type = typename extents_type::size_type;
    using rank_type = typename extents_type::rank_type;
    using layout_type = layout_stride;
  private:
    static constexpr rank_type rank_ = extents_type::rank();    
  public:
    
    constexpr mapping() noexcept;
    constexpr mapping(const mapping&) noexcept = default;
    template<class OtherIndexType>
      constexpr mapping(const extents_type&, span<OtherIndexType, rank_>) noexcept;
    template<class OtherIndexType>
      constexpr mapping(const extents_type&, const array<OtherIndexType, rank_>&) noexcept;
    template<class StridedLayoutMapping>
      constexpr explicit(see below) mapping(const StridedLayoutMapping&) noexcept;
    constexpr mapping& operator=(const mapping&) noexcept = default;
    
    constexpr const extents_type& extents() const noexcept { return extents_; }
    constexpr array<index_type, rank_> strides() const noexcept { return strides_; }
    constexpr index_type required_span_size() const noexcept;
    template<class... Indices>
      constexpr index_type operator()(Indices...) const noexcept;
    static constexpr bool is_always_unique() noexcept { return true; }
    static constexpr bool is_always_exhaustive() noexcept { return false; }
    static constexpr bool is_always_strided() noexcept { return true; }
    static constexpr bool is_unique() noexcept { return true; }
    constexpr bool is_exhaustive() const noexcept;
    static constexpr bool is_strided() noexcept { return true; }
    constexpr index_type stride(rank_type i) const noexcept { return strides_[i]; }
    template<class OtherMapping>
      friend constexpr bool operator==(const mapping&, const OtherMapping&) noexcept;
  private:
    extents_type extents_{};                    
    array<index_type, rank_> strides_{};        
    
    template<class... SliceSpecifiers>
      constexpr auto submdspan-mapping-impl(SliceSpecifiers...) const       
        -> see below;
    template<class... SliceSpecifiers>
      friend constexpr auto submdspan_mapping(
        const mapping& src, SliceSpecifiers... slices) {
          return src.submdspan-mapping-impl(slices...);
      }
  };
}
If 
Extents is not a specialization of 
extents,
then the program is ill-formed
.layout_stride::mapping<E> is a trivially copyable type
that models 
regular for each 
E. Mandates: If 
Extents::rank_dynamic() == 0 is 
true,
then the size of the multidimensional index space 
Extents()
is representable as a value of type 
typename Extents::index_type. Let 
REQUIRED-SPAN-SIZE(e, strides) be:
- 1, if e.rank() == 0 is true,
- otherwise 0, if the size of the multidimensional index space e is 0,
- otherwise 1 plus the sum of products of
(e.extent(r) - 1) and
extents_type::index-cast(strides[r])
  for all r in the range [0, e.rank()).
Let 
OFFSET(m) be:
- m(), if e.rank() == 0 is true,
- otherwise 0, if the size of the multidimensional index space e is 0,
- otherwise m(z...) for a pack of integers z
that is a multidimensional index in m.extents() and
each element of z equals 0.
Let is-extents be the exposition-only variable template
defined as follows:
template<class T>
  constexpr bool is-extents = false;                              
template<class IndexType, size_t... Args>
  constexpr bool is-extents<extents<IndexType, Args...>> = true;  
Let 
layout-mapping-alike be the exposition-only concept
defined as follows:
template<class M>
concept layout-mapping-alike = requires {                         
  requires is-extents<typename M::extents_type>;
  { M::is_always_strided() } -> same_as<bool>;
  { M::is_always_exhaustive() } -> same_as<bool>;
  { M::is_always_unique() } -> same_as<bool>;
  bool_constant<M::is_always_strided()>::value;
  bool_constant<M::is_always_exhaustive()>::value;
  bool_constant<M::is_always_unique()>::value;
};
[
Note 1: 
This concept checks that the functions
M::is_always_strided(),
M::is_always_exhaustive(), and
M::is_always_unique() exist,
are constant expressions, and
have a return type of 
bool. — 
end note]
constexpr mapping() noexcept;
Preconditions: 
layout_right::mapping<extents_type>().required_span_size()
is representable as a value of type 
index_type (
[basic.fundamental])
. Effects: Direct-non-list-initializes 
extents_ with 
extents_type(), and
for all 
d in the range [
0, rank_),
direct-non-list-initializes 
strides_[d] with
layout_right::mapping<extents_type>().stride(d). template<class OtherIndexType>
  constexpr mapping(const extents_type& e, span<OtherIndexType, rank_> s) noexcept;
template<class OtherIndexType>
  constexpr mapping(const extents_type& e, const array<OtherIndexType, rank_>& s) noexcept;
Constraints: 
- is_convertible_v<const OtherIndexType&, index_type> is true, and
- is_nothrow_constructible_v<index_type, const OtherIndexType&> is true.
 Preconditions: 
- The result of converting  s[i]-  to  index_type- 
is greater than  0- 
for all  i-  in the range  [0, rank_).
- If  rank_-  is greater than 0,
then there exists a permutation  P-  of the integers
in the range  [0, rank_)- ,
such that  s[pi] >= s[pi−1] * e.extent(pi−1)-  is  true- 
for all  i-  in the range  [1, rank_)- ,
where  pi-  is the  ith-  element of  P.
- [ Note 1- :  - For  layout_stride- ,
this condition is necessary and sufficient
for  is_unique()-  to be  true.
-  —  end note- ] 
 Effects: Direct-non-list-initializes 
extents_ with 
e, and
for all 
d in the range 
[0, rank_),
direct-non-list-initializes 
strides_[d] with 
as_const(s[d]). template<class StridedLayoutMapping>
  constexpr explicit(see below)
    mapping(const StridedLayoutMapping& other) noexcept;
Constraints: 
- is_constructible_v<extents_type, typename StridedLayoutMapping::extents_type> is
 
 
- StridedLayoutMapping::is_always_unique()-  is  true.
 
- StridedLayoutMapping::is_always_strided()-  is  true.
 
 Preconditions: 
- StridedLayoutMapping meets the layout mapping requirements ([mdspan.layout.reqmts]),
- other.stride(r) > 0 is true
for every rank index r of extents(),
- other.required_span_size() is representable as
a value of type index_type ([basic.fundamental]), and
- OFFSET(other) == 0 is true.
 Effects: Direct-non-list-initializes 
extents_ with 
other.extents(), and
for all 
d in the range 
[0, rank_),
direct-non-list-initializes 
strides_[d]
with 
other.stride(d). Remarks: The expression inside explicit is equivalent to:
!(is_convertible_v<typename StridedLayoutMapping::extents_type, extents_type> &&
  (is-mapping-of<layout_left, StridedLayoutMapping> ||
   is-mapping-of<layout_right, StridedLayoutMapping> ||
   is-layout-left-padded-mapping-of<StridedLayoutMapping> ||
   is-layout-right-padded-mapping-of<StridedLayoutMapping> ||
   is-mapping-of<layout_stride, StridedLayoutMapping>))
constexpr index_type required_span_size() const noexcept;
Returns: 
REQUIRED-SPAN-SIZE(extents(), strides_). template<class... Indices>
  constexpr index_type operator()(Indices... i) const noexcept;
Constraints: 
- sizeof...(Indices) == rank_ is true,
- (is_convertible_v<Indices, index_type> && ...) is true, and
- (is_nothrow_constructible_v<index_type, Indices> && ...) is true.
 Preconditions: 
extents_type::index-cast(i) is
a multidimensional index in 
extents_ (
[mdspan.overview])
. Effects: Let 
P be a parameter pack such that
is_same_v<index_sequence_for<Indices...>, index_sequence<P...>>
is 
true.  Equivalent to:
return ((static_cast<index_type>(i) * stride(P)) + ... + 0);
constexpr bool is_exhaustive() const noexcept;
Returns: 
- Otherwise,  true-  if there is
a permutation  P-  of the integers in the range  [0, rank_)- 
such that  stride(p0)-  equals 1, and
 stride(pi)-  equals  stride(pi−1) * extents().extent(pi−1)- 
for  i-  in the range  [1, rank_)- ,
where  pi-  is the  ith-  element of  P.
 template<class OtherMapping>
  friend constexpr bool operator==(const mapping& x, const OtherMapping& y) noexcept;
Constraints: 
- rank_ == OtherMapping::extents_type::rank()-  is  true.
 
- OtherMapping::is_always_strided()-  is  true.
 
 Returns: 
true if 
x.extents() == y.extents() is 
true,
OFFSET(y) == 0 is 
true, and
each of 
x.stride(r) == y.stride(r) is 
true
for 
r in the range  
[0, x.extents().rank()).  layout_left_padded provides a layout mapping
that behaves like 
layout_left::mapping,
except that the padding stride 
stride(1)
can be greater than or equal to 
extent(0). namespace std {
  template<size_t PaddingValue>
  template<class Extents>
  class layout_left_padded<PaddingValue>::mapping {
  public:
    static constexpr size_t padding_value = PaddingValue;
    using extents_type = Extents;
    using index_type = typename extents_type::index_type;
    using size_type = typename extents_type::size_type;
    using rank_type = typename extents_type::rank_type;
    using layout_type = layout_left_padded<PaddingValue>;
  private:
    static constexpr size_t rank_ = extents_type::rank();         
    static constexpr size_t first-static-extent =                 
      extents_type::static_extent(0);
    
    static constexpr size_t static-padding-stride = see below;  
  public:
    
    constexpr mapping() noexcept : mapping(extents_type{}) {}
    constexpr mapping(const mapping&) noexcept = default;
    constexpr mapping(const extents_type&);
    template<class OtherIndexType>
      constexpr mapping(const extents_type&, OtherIndexType);
    template<class OtherExtents>
      constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
        mapping(const layout_left::mapping<OtherExtents>&);
    template<class OtherExtents>
      constexpr explicit(extents_type::rank() > 0)
        mapping(const layout_stride::mapping<OtherExtents>&);
    template<class LayoutLeftPaddedMapping>
      constexpr explicit(see below)
        mapping(const LayoutLeftPaddedMapping&);
    template<class LayoutRightPaddedMapping>
      constexpr explicit(see below)
        mapping(const LayoutRightPaddedMapping&) noexcept;
    constexpr mapping& operator=(const mapping&) noexcept = default;
    
    constexpr const extents_type& extents() const noexcept { return extents_; }
    constexpr array<index_type, rank_> strides() const noexcept;
    constexpr index_type required_span_size() const noexcept;
    template<class... Indices>
      constexpr index_type operator()(Indices...) const noexcept;
    static constexpr bool is_always_unique() noexcept { return true; }
    static constexpr bool is_always_exhaustive() noexcept;
    static constexpr bool is_always_strided() noexcept { return true; }
    static constexpr bool is_unique() noexcept { return true; }
    constexpr bool is_exhaustive() const noexcept;
    static constexpr bool is_strided() noexcept { return true; }
    constexpr index_type stride(rank_type) const noexcept;
    template<class LayoutLeftPaddedMapping>
      friend constexpr bool operator==(const mapping&, const LayoutLeftPaddedMapping&) noexcept;
  private:
    
    index_type stride-1 = static-padding-stride;                           
    extents_type extents_{};                                               
    
    template<class... SliceSpecifiers>
      constexpr auto submdspan-mapping-impl(SliceSpecifiers...) const     
        -> see below;
    template<class... SliceSpecifiers>
      friend constexpr auto submdspan_mapping(const mapping& src, SliceSpecifiers... slices) {
      return src.submdspan-mapping-impl(slices...);
    }
  };
}
If 
Extents is not a specialization of 
extents,
then the program is ill-formed
.layout_left_padded::mapping<E> is a trivially copyable type
that models 
regular for each 
E. Throughout 
[mdspan.layout.leftpad],
let 
P_rank be the following
size 
rank_ parameter pack of 
size_t values:
- the empty parameter pack, if rank_ equals zero;
- otherwise, 0zu, if rank_ equals one;
- otherwise, the parameter pack 0zu, 1zu, …, rank_- 1.
Mandates: 
- If  rank_dynamic() == 0-  is  true- ,
then the size of the multidimensional index space  Extents()- 
is representable as a value of type  index_type.
- padding_value-  is representable as a value of type  index_type.
 
- If
 - rank_ is greater than one,
- padding_value does not equal dynamic_extent, and
- first-static-extent does not equal dynamic_extent,
 - 
then  LEAST-MULTIPLE-AT-LEAST(padding_value, first-static-extent)- 
is representable as a value of type  size_t- , and
is representable as a value of type  index_type.
- If
 - rank_ is greater than one,
- padding_value does not equal dynamic_extent, and
- extents_type::static_extent(k) does not equal dynamic_extent
for all k in the range [0, extents_type::rank()),
 - 
then the product of
 LEAST-MULTIPLE-AT-LEAST(padding_value, ext.static_extent(0))-  and
all values  ext.static_extent(k)- 
with  k-  in the range of [ 1, rank_- )
is representable as a value of type  size_t- , and
is representable as a value of type  index_type.
 static constexpr size_t static-padding-stride = see below;
The value is
- 0, if rank_ equals zero or one;
- otherwise, dynamic_extent,
if padding_value or first-static-extent equals
dynamic_extent;
- otherwise, the size_t value which is
LEAST-MULTIPLE-AT-LEAST(padding_value, first-static-extent).
index_type stride-1 = static-padding-stride;
Recommended practice: Implementations should not store this value
if 
static-padding-stride is not 
dynamic_extent.  [
Note 1: 
Using 
extents<index_type, static-padding-stride> instead of
index_type as the type of 
stride-1 would achieve this
. — 
end note]
constexpr mapping(const extents_type& ext);
Preconditions: 
- The size of the multidimensional index space  ext-  is representable as
a value of type  index_type.
- If  rank_-  is greater than one and
 padding_value-  does not equal  dynamic_extent- ,
then  LEAST-MULTIPLE-AT-LEAST(padding_value, ext.extent(0))- 
is representable as a value of type  index_type.
- If  rank_-  is greater than one and
 padding_value-  does not equal  dynamic_extent- ,
then the product of
 LEAST-MULTIPLE-AT-LEAST(padding_value, ext.extent(0))-  and
all values  ext.extent(k)- 
with  k-  in the range of [ 1, rank_- )
is representable as a value of type  index_type.
 Effects: 
- Direct-non-list-initializes extents_ with ext; and
- if rank_ is greater than one,
direct-non-list-initializes stride-1
- with ext.extent(0) if padding_value is dynamic_extent,
- otherwise with
LEAST-MULTIPLE-AT-LEAST(padding_value, ext.extent(0)).
 
 template<class OtherIndexType>
constexpr mapping(const extents_type& ext, OtherIndexType pad);
Constraints: 
- is_convertible_v<OtherIndexType, index_type>-  is  true.
 
- is_nothrow_constructible_v<index_type, OtherIndexType>-  is  true.
 
 Preconditions: 
- pad-  is representable as a value of type  index_type.
 
- extents_type::index-cast(pad)-  is greater than zero .
 
- If rank_ is greater than one,
then LEAST-MULTIPLE-AT-LEAST(pad, ext.extent(0))
is representable as a value of type index_type. 
- If  rank_-  is greater than one,
then the product of
 LEAST-MULTIPLE-AT-LEAST(pad, ext.extent(0))-  and
all values  ext.extent(k)- 
with  k-  in the range of [ 1, rank_- )
is representable as a value of type  index_type.
- If  padding_value-  is not equal to  dynamic_extent- ,
 padding_value-  equals  extents_type::index-cast(pad).
 Effects: Direct-non-list-initializes 
extents_ with 
ext, and
if 
rank_ is greater than one,
direct-non-list-initializes 
stride-1 with
LEAST-MULTIPLE-AT-LEAST(pad, ext.extent(0)). template<class OtherExtents>
  constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
    mapping(const layout_left::mapping<OtherExtents>& other);
Constraints: 
is_constructible_v<extents_type, OtherExtents> is 
true. Mandates: If 
OtherExtents::rank() is greater than 
1, then
(static-padding-stride == dynamic_extent) ||
(OtherExtents::static_extent(0) == dynamic_extent) ||
(static-padding-stride == OtherExtents::static_extent(0))
is 
true. Preconditions: 
- If extents_type::rank() > 1 is true and
padding_value == dynamic_extent is false,
then other.stride(1) equals
LEAST-MULTIPLE-AT-LEAST(padding_value,
                        extents_type::index-cast(other.extents().extent(0)))
and
- other.required_span_size() is representable as
a value of type index_type.
 Effects: Equivalent to 
mapping(other.extents()). template<class OtherExtents>
  constexpr explicit(rank_ > 0)
    mapping(const layout_stride::mapping<OtherExtents>& other);
Constraints: 
is_constructible_v<extents_type, OtherExtents> is 
true. Preconditions: 
- If rank_ is greater than 1 and
padding_value does not equal dynamic_extent,
then other.stride(1) equals
LEAST-MULTIPLE-AT-LEAST(padding_value,
                        extents_type::index-cast(other.extents().extent(0)))
 
- If  rank_-  is greater than 0,
then  other.stride(0)-  equals 1 .
- If rank_ is greater than 2,
then for all r in the range [2, rank_),
other.stride(r) equals
(other.extents().fwd-prod-of-extents(r) / other.extents().extent(0)) * other.stride(1)
 
- other.required_span_size()-  is representable as
a value of type  index_type.
 
 Effects: 
- Direct-non-list-initializes extents_ with other.extents() and
- if rank_ is greater than one,
direct-non-list-initializes stride-1 with
other.stride(1).
 template<class LayoutLeftPaddedMapping>
  constexpr explicit(see below)
    mapping(const LayoutLeftPaddedMapping& other);
Constraints: 
- is-layout-left-padded-mapping-of<LayoutLeftPaddedMapping>- 
is  true.
 
- is_constructible_v<extents_type, typename LayoutLeftPaddedMapping::extents_type>
- is  true.
 
 Mandates: If 
rank_ is greater than 1,
then
padding_value == dynamic_extent ||
LayoutLeftPaddedMapping::padding_value == dynamic_extent ||
padding_value == LayoutLeftPaddedMapping::padding_value
is 
true. Preconditions: 
- If rank_ is greater than 1 and
padding_value does not equal dynamic_extent,
then other.stride(1) equals
LEAST-MULTIPLE-AT-LEAST(padding_value,
                        extents_type::index-cast(other.extent(0)))
- other.required_span_size() is representable as
a value of type index_type.
 Effects: 
- Direct-non-list-initializes extents_ with other.extents() and
- if rank_ is greater than one,
direct-non-list-initializes stride-1 with other.stride(1).
 Remarks: The expression inside explicit is equivalent to:
rank_> 1 &&
(padding_value != dynamic_extent ||
 LayoutLeftPaddedMapping::padding_value == dynamic_extent)
template<class LayoutRightPaddedMapping>
  constexpr explicit(see below)
    mapping(const LayoutRightPaddedMapping& other) noexcept;
Constraints: 
- is-layout-right-padded-mapping-of<LayoutRightPaddedMapping>- 
is  true-  or is-mapping-of<layout_right, LayoutRightPaddedMapping>- 
is  true.
 
- rank_-  equals zero or one .
 
- is_constructible_v<extents_type, typename LayoutRightPaddedMapping::extents_-
 type>- 
is  true.
 
 Preconditions: 
other.required_span_size() is representable as
a value of type 
index_type. Effects: Direct-non-list-initializes 
extents_ with 
other.extents(). Remarks: The expression inside explicit is equivalent to:
!is_convertible_v<typename LayoutRightPaddedMapping::extents_type, extents_type>
[
Note 1: 
Neither the input mapping nor the mapping to be constructed
uses the padding stride in the rank-0 or rank-1 case,
so the padding stride does not affect
either the constraints or the preconditions
. — 
end note]
constexpr array<index_type, rank_> strides() const noexcept;
Returns: 
array<index_type, rank_>({stride(P_rank)...}). constexpr index_type required_span_size() const noexcept;
Returns: 
- 0 if the multidimensional index space extents_ is empty,
- otherwise, *this(((extents_(P_rank) - index_type(1))...)) + 1.
 template<class... Indices>
constexpr size_t operator()(Indices... idxs) const noexcept;
Constraints: 
- sizeof...(Indices) == rank_-  is  true.
 
- (is_convertible_v<Indices, index_type> && ...)-  is  true.
 
- (is_nothrow_constructible_v<index_type, Indices> && ...)-  is  true.
 
 Preconditions: 
extents_type::index-cast(idxs) is
a multidimensional index in 
extents() (
[mdspan.overview])
. Returns: 
((static_cast<index_type>(idxs) * stride(P_rank)) + ... + 0). static constexpr bool is_always_exhaustive() noexcept;
Returns: 
- If rank_ equals zero or one, then true;
- otherwise, if
neither static-padding-stride nor first-static-extent
equal dynamic_extent,
then static-padding-stride == first-static-extent;
- otherwise, false.
 constexpr bool is_exhaustive() const noexcept;
Returns: 
true if 
rank_ equals zero or one;
otherwise, 
extents_.extent(0) == stride(1). constexpr index_type stride(rank_type r) const noexcept;
Preconditions: 
r is smaller than 
rank_. Returns: 
- If r equals zero: 1;
- otherwise, if r equals one: stride-1;
- otherwise, the product of stride-1 and
all values extents_.extent(k) with k in the range [1, r).
 template<class LayoutLeftPaddedMapping>
  friend constexpr bool operator==(const mapping& x, const LayoutLeftPaddedMapping& y) noexcept;
Constraints: 
- is-layout-left-padded-mapping-of<LayoutLeftPaddedMapping>- 
is  true.
 
- LayoutLeftPaddedMapping::extents_type::rank() == rank_-  is  true.
 
 Returns: 
true if 
x.extents() == y.extents() is 
true and
rank_ < 2 || x.stride(1) == y.
stride(1) is 
true.  layout_right_padded provides a layout mapping
that behaves like 
layout_right::mapping,
except that the padding stride 
stride(extents_type::rank() - 2)
can be greater than or equal to
extents_type::extent(extents_type::rank() - 1). namespace std {
  template<size_t PaddingValue>
  template<class Extents>
  class layout_right_padded<PaddingValue>::mapping {
  public:
    static constexpr size_t padding_value = PaddingValue;
    using extents_type = Extents;
    using index_type = typename extents_type::index_type;
    using size_type = typename extents_type::size_type;
    using rank_type = typename extents_type::rank_type;
    using layout_type = layout_right_padded<PaddingValue>;
  private:
    static constexpr size_t rank_ = extents_type::rank();    
    static constexpr size_t last-static-extent =             
      extents_type::static_extent(rank_ - 1);
    
    static constexpr size_t static-padding-stride = see below; 
  public:
    
    constexpr mapping() noexcept : mapping(extents_type{}) {}
    constexpr mapping(const mapping&) noexcept = default;
    constexpr mapping(const extents_type&);
    template<class OtherIndexType>
      constexpr mapping(const extents_type&, OtherIndexType);
    template<class OtherExtents>
      constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
        mapping(const layout_right::mapping<OtherExtents>&);
    template<class OtherExtents>
      constexpr explicit(rank_ > 0)
        mapping(const layout_stride::mapping<OtherExtents>&);
    template<class LayoutRightPaddedMapping>
      constexpr explicit(see below)
        mapping(const LayoutRightPaddedMapping&);
    template<class LayoutLeftPaddedMapping>
      constexpr explicit(see below)
        mapping(const LayoutLeftPaddedMapping&) noexcept;
    constexpr mapping& operator=(const mapping&) noexcept = default;
    
    constexpr const extents_type& extents() const noexcept { return extents_; }
    constexpr array<index_type, rank_> strides() const noexcept;
    constexpr index_type required_span_size() const noexcept;
    template<class... Indices>
      constexpr index_type operator()(Indices...) const noexcept;
    static constexpr bool is_always_unique() noexcept { return true; }
    static constexpr bool is_always_exhaustive() noexcept;
    static constexpr bool is_always_strided() noexcept { return true; }
    static constexpr bool is_unique() noexcept { return true; }
    constexpr bool is_exhaustive() const noexcept;
    static constexpr bool is_strided() noexcept { return true; }
    constexpr index_type stride(rank_type) const noexcept;
    template<class LayoutRightPaddedMapping>
      friend constexpr bool operator==(const mapping&, const LayoutRightPaddedMapping&) noexcept;
  private:
    
    index_type stride-rm2 = static-padding-stride;                         
    extents_type extents_{};                                               
    
    template<class... SliceSpecifiers>
      constexpr auto submdspan-mapping-impl(SliceSpecifiers...) const     
        -> see below;
    template<class... SliceSpecifiers>
      friend constexpr auto submdspan_mapping(const mapping& src, SliceSpecifiers... slices) {
      return src.submdspan-mapping-impl(slices...);
    }
  };
}
If 
Extents is not a specialization of 
extents,
then the program is ill-formed
.layout_right_padded::mapping<E> is a trivially copyable type
that models 
regular for each 
E. Throughout 
[mdspan.layout.rightpad],
let 
P_rank be the following
size 
rank_ parameter pack of 
size_t values:
- the empty parameter pack, if rank_ equals zero;
- otherwise, 0zu, if rank_ equals one;
- otherwise, the parameter pack 0zu, 1zu, …, rank_- 1.
Mandates: 
- If  rank_dynamic() == 0-  is  true- ,
then the size of the multidimensional index space  Extents()- 
is representable as a value of type  index_type.
- padding_value-  is representable as a value of type  index_type.
 
- If
 - rank_ is greater than one,
- padding_value does not equal dynamic_extent, and
- last-static-extent does not equal dynamic_extent,
 - 
then  LEAST-MULTIPLE-AT-LEAST(padding_value, last-static-extent)- 
is representable as a value of type  size_t- , and
is representable as a value of type  index_type.
- If
 - rank_ is greater than one,
- padding_value does not equal dynamic_extent, and
- extents_type::static_extent(k) does not equal dynamic_extent
for all k in the range [0, rank_),
 - 
then the product of
 LEAST-MULTIPLE-AT-LEAST(padding_value, ext.static_extent(rank_ - 1))-  and
all values  ext.static_extent(k)- 
with  k-  in the range of [ 0, rank_ - 1- )
is representable as a value of type  size_t- , and
is representable as a value of type  index_type.
 static constexpr size_t static-padding-stride = see below;
The value is
- 0, if rank_ equals zero or one;
- otherwise, dynamic_extent,
if padding_value or last-static-extent equals
dynamic_extent;
- otherwise, the size_t value which is
LEAST-MULTIPLE-AT-LEAST(padding_value, last-static-extent).
index_type stride-rm2 = static-padding-stride;
Recommended practice: Implementations should not store this value
if 
static-padding-stride is not 
dynamic_extent.  [
Note 1: 
Using 
extents<index_type, static-padding-stride>
instead of 
index_type as the type of 
stride-rm2
would achieve this
. — 
end note]
constexpr mapping(const extents_type& ext);
Preconditions: 
- The size of the multidimensional index space  ext- 
is representable as a value of type  index_type.
- If  rank_-  is greater than one and
 padding_value-  does not equal  dynamic_extent- ,
then  LEAST-MULTIPLE-AT-LEAST(padding_value, ext.extent(rank_ - 1))- 
is representable as a value of type  index_type.
- If  rank_-  is greater than one and
 padding_value-  does not equal  dynamic_extent- ,
then the product of
 LEAST-MULTIPLE-AT-LEAST(padding_value, ext.extent(rank_ - 1))-  and
all values  ext.extent(k)- 
with  k-  in the range of [ 0, rank_ - 1- )
is representable as a value of type  index_type.
 Effects: 
- Direct-non-list-initializes extents_ with ext; and
- if rank_ is greater than one,
direct-non-list-initializes stride-rm2
- with ext.extent(rank_ - 1)
if padding_value is dynamic_extent,
- otherwise with
LEAST-MULTIPLE-AT-LEAST(padding_value, ext.extent(rank_ - 1)).
 
 template<class OtherIndexType>
constexpr mapping(const extents_type& ext, OtherIndexType pad);
Constraints: 
- is_convertible_v<OtherIndexType, index_type>-  is  true.
 
- is_nothrow_constructible_v<index_type, OtherIndexType>-  is  true.
 
 Preconditions: 
- pad-  is representable as a value of type  index_type.
 
- extents_type::index-cast(pad)-  is greater than zero .
 
- If  rank_-  is greater than one,
then  LEAST-MULTIPLE-AT-LEAST(pad, ext.extent(rank_ - 1))- 
is representable as a value of type  index_type.
- If  rank_-  is greater than one,
then the product of
 LEAST-MULTIPLE-AT-LEAST(pad, ext.extent(rank_ - 1))-  and
all values  ext.extent(k)- 
with  k-  in the range of [ 0, rank_ - 1- )
is representable as a value of type  index_type.
- If  padding_value-  is not equal to  dynamic_extent- ,
 padding_value-  equals  extents_type::index-cast(pad).
 Effects: Direct-non-list-initializes 
extents_ with 
ext, and
if 
rank_ is greater than one,
direct-non-list-initializes 
stride-rm2 with
LEAST-MULTIPLE-AT-LEAST(pad, ext.extent(rank_ - 1)). template<class OtherExtents>
  constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
    mapping(const layout_right::mapping<OtherExtents>& other);
Constraints: 
is_constructible_v<extents_type, OtherExtents> is 
true. Mandates: If 
OtherExtents::rank() is greater than 1, then
(static-padding-stride == dynamic_extent) ||
(OtherExtents::static_extent(rank_ - 1) == dynamic_extent) ||
(static-padding-stride == OtherExtents::static_extent(rank_ - 1))
is 
true. Preconditions: 
- If rank_ > 1 is true and
padding_value == dynamic_extent is false, then
other.stride(
 rank_ - 2) equals
LEAST-MULTIPLE-AT-LEAST(padding_value,
                        extents_type::index-cast(other.extents().extent(rank_ - 1)))
and
- other.required_span_size() is representable as
a value of type index_type.
 Effects: Equivalent to 
mapping(other.extents()). template<class OtherExtents>
  constexpr explicit(rank_ > 0)
    mapping(const layout_stride::mapping<OtherExtents>& other);
Constraints: 
is_constructible_v<extents_type, OtherExtents> is 
true. Preconditions: 
- If rank_ is greater than 1 and
padding_value does not equal dynamic_extent,
then other.stride(rank_ - 2) equals
LEAST-MULTIPLE-AT-LEAST(padding_value,
                        extents_type::index-cast(other.extents().extent(rank_ - 1)))
 
- If  rank_-  is greater than 0,
then other.stride( rank_-  - 1) equals 1 .
- If rank_ is greater than 2,
then for all r in the range [0, rank_ - 2),
other.stride(r) equals
(other.extents().rev-prod-of-extents(r) / other.extents().extent(rank_ - 1)) *
  other.stride(rank_ - 2)
 
- other.required_span_size()-  is representable as
a value of type  index_type.
 
 Effects: 
- Direct-non-list-initializes extents_ with other.extents(); and
- if rank_ is greater than one,
direct-non-list-initializes stride-rm2
with other.stride(rank_ - 2).
 template<class LayoutRightPaddedMapping>
  constexpr explicit(see below)
    mapping(const LayoutRightPaddedMapping& other);
Constraints: 
- is-layout-right-padded-mapping-of<LayoutRightPaddedMapping>- 
is  true.
 
- is_constructible_v<extents_type, typename LayoutRightPaddedMapping::extents_-
 type>- 
is  true.
 
 Mandates: If 
rank_ is greater than 1, then
padding_value == dynamic_extent ||
LayoutRightPaddedMapping::padding_value == dynamic_extent ||
padding_value == LayoutRightPaddedMapping::padding_value
is 
true. Preconditions: 
- If rank_ is greater than 1 and
padding_value does not equal dynamic_extent,
then other.stride(rank_ - 2) equals
LEAST-MULTIPLE-AT-LEAST(padding_value,
                        extents_type::index-cast(other.extent(rank_ - 1)))
- other.required_span_size() is representable as
a value of type index_type.
 Effects: 
- Direct-non-list-initializes extents_ with other.extents(); and
- if rank_ is greater than one,
direct-non-list-initializes stride-rm2
with other.stride(rank_ - 2).
 Remarks: The expression inside explicit is equivalent to:
rank_ > 1 &&
(padding_value != dynamic_extent ||
 LayoutRightPaddedMapping::padding_value == dynamic_extent)
template<class LayoutLeftPaddedMapping>
  constexpr explicit(see below)
    mapping(const LayoutLeftPaddedMapping& other) noexcept;
Constraints: 
- is-layout-left-padded-mapping-of<LayoutLeftPaddedMapping>- 
is  true-  or is-mapping-of<layout_left, LayoutLeftPaddedMapping>- 
is  true.
 
- rank_-  equals zero or one .
 
- is_constructible_v<extents_type, typename LayoutLeftPaddedMapping::extents_type>- is  true.
 
 Preconditions: 
other.required_span_size() is representable as
a value of type 
index_type. Effects: Direct-non-list-initializes 
extents_ with 
other.extents(). Remarks: The expression inside 
explicit is equivalent to:
!is_convertible_v<typename LayoutLeftPaddedMapping::extents_type, extents_type>
[
Note 1: 
Neither the input mapping nor the mapping to be constructed
uses the padding stride in the rank-0 or rank-1 case,
so the padding stride affects neither the constraints nor the preconditions
. — 
end note]
 constexpr array<index_type, rank_> strides() const noexcept;
Returns: 
array<index_type, rank_>(stride(P_rank)...). constexpr index_type required_span_size() const noexcept;
Returns: 
0 if the multidimensional index space 
extents_ is empty,
otherwise 
*this(((extents_(P_rank) - index_type(1))...)) + 1. template<class... Indices>
constexpr size_t operator()(Indices... idxs) const noexcept;
Constraints: 
- sizeof...(Indices) == rank_-  is  true.
 
- (is_convertible_v<Indices, index_type> && ...)-  is  true.
 
- (is_nothrow_constructible_v<index_type, Indices> && ...)-  is  true.
 
 Preconditions: 
extents_type::index-cast(idxs) is
a multidimensional index in 
extents() (
[mdspan.overview])
. Returns: 
((static_cast<index_type>(idxs) * stride(P_rank)) + ... + 0). static constexpr bool is_always_exhaustive() noexcept;
Returns: 
- If rank_ equals zero or one, then true;
- otherwise,
if neither static-padding-stride nor last-static-extent
equal dynamic_extent,
then static-padding-stride == last-static-extent;
- otherwise, false.
 constexpr bool is_exhaustive() const noexcept;
Returns: true if rank_ equals zero or one;
otherwise,
extents_.extent(rank_ - 1) == stride(rank_ - 2)
constexpr index_type stride(rank_type r) const noexcept;
Preconditions: 
r is smaller than 
rank_. Returns: 
- If r equals rank_ - 1: 1;
- otherwise, if r equals rank_ - 2: stride-rm2;
- otherwise,
the product of stride-rm2 and
all values extents_.extent(k)
with k in the range of [r + 1, rank_ - 1).
 template<class LayoutRightPaddedMapping>
  friend constexpr bool operator==(const mapping& x, const LayoutRightPaddedMapping& y) noexcept;
Constraints: 
- is-layout-right-padded-mapping-of<LayoutRightPaddedMapping>- 
is  true.
 
- LayoutRightPaddedMapping::extents_type::rank() == rank_- 
is  true.
 
 Returns: 
true if 
x.extents() == y.extents() is 
true and
rank_ < 2 || x.stride(rank_ - 2) == y.stride(rank_ - 2) is 
true.  An 
accessor policy defines types and operations by which
a reference to a single object is created
from an abstract data handle to a number of such objects and an index
.A range of indices 
[0,N) is an 
accessible range of
a given data handle and an accessor
if, for each 
i in the range,
the accessor policy's 
access function produces a valid reference to an object
.- A-  denotes an accessor policy .
 
- a-  denotes a value of type  A-  or  const A.
 
- p-  denotes a value of type  A::data_handle_type-  or  const A::data_handle_type.
 - [ Note 1- :  - The type  A::data_handle_type-  need not be dereferenceable .
-  —  end note- ] 
- n- ,  i- , and  j-  each denote values of type  size_t.
 
A type 
A meets the accessor policy requirements if
- A models copyable,
- is_nothrow_move_constructible_v<A> is true,
- is_nothrow_move_assignable_v<A> is true,
- is_nothrow_swappable_v<A> is true, and
- the following types and expressions
are well-formed and have the specified semantics.
Result: A complete object type that is not an abstract class type
. typename A::data_handle_type
Result: A type that models 
copyable, and
for which 
is_nothrow_move_constructible_v<A::data_handle_type> is 
true,
is_nothrow_move_assignable_v<A::data_handle_type> is 
true, and
is_nothrow_swappable_v<A::data_handle_type> is 
true.  [
Note 1: 
The type of 
data_handle_type need not be 
element_type*. — 
end note]
 [
Note 2: 
The type of 
reference need not be 
element_type&. — 
end note]
 typename A::offset_policy
Result: A type 
OP such that:
- OP meets the accessor policy requirements,
- constructible_from<OP, const A&> is modeled, and
- is_same_v<typename OP::element_type, typename A::element_type> is true.
 Remarks: The expression is equality preserving
. [
Note 3: 
Concrete accessor policies can impose preconditions for their 
access function
.For example, an accessor where
p is 
span<A::element_type, dynamic_extent> and
access(p, i) returns 
p[i % p.size()]
does not need to impose a precondition on 
i. — 
end note]
Result: A::offset_policy::data_handle_type
Returns: 
q such that for 
b being 
A::offset_policy(a), and
any integer 
n for which 
[0, n) is
an accessible range of 
p and 
a:
- [0,n−i) is an accessible range of q and b; and
- b.access(q, j) provides access to
the same element as a.access(p, i + j),
for every j in the range [0,n−i).
 Remarks: The expression is equality-preserving
. namespace std {
  template<class ElementType>
  struct default_accessor {
    using offset_policy = default_accessor;
    using element_type = ElementType;
    using reference = ElementType&;
    using data_handle_type = ElementType*;
    constexpr default_accessor() noexcept = default;
    template<class OtherElementType>
      constexpr default_accessor(default_accessor<OtherElementType>) noexcept;
    constexpr reference access(data_handle_type p, size_t i) const noexcept;
    constexpr data_handle_type offset(data_handle_type p, size_t i) const noexcept;
  };
}
default_accessor meets the accessor policy requirements
. ElementType is required to be a complete object type
that is neither an abstract class type nor an array type
. Each specialization of 
default_accessor is
a trivially copyable type that models 
semiregular.[0,n) is an accessible range for
an object 
p of type 
data_handle_type and
an object of type 
default_accessor
if and only if [
p, p + n) is a valid range
. template<class OtherElementType>
  constexpr default_accessor(default_accessor<OtherElementType>) noexcept {}
Constraints: 
is_convertible_v<OtherElementType(*)[], element_type(*)[]>
is 
true. constexpr reference access(data_handle_type p, size_t i) const noexcept;
Effects: Equivalent to: return p[i];
constexpr data_handle_type offset(data_handle_type p, size_t i) const noexcept;
Effects: Equivalent to: return p + i;
namespace std {
  template<class ElementType, size_t ByteAlignment>
  struct aligned_accessor {
    using offset_policy = default_accessor<ElementType>;
    using element_type = ElementType;
    using reference = ElementType&;
    using data_handle_type = ElementType*;
    static constexpr size_t byte_alignment = ByteAlignment;
    constexpr aligned_accessor() noexcept = default;
    template<class OtherElementType, size_t OtherByteAlignment>
      constexpr aligned_accessor(
        aligned_accessor<OtherElementType, OtherByteAlignment>) noexcept;
    template<class OtherElementType>
      constexpr explicit aligned_accessor(default_accessor<OtherElementType>) noexcept;
    template<class OtherElementType>
      constexpr operator default_accessor<OtherElementType>() const noexcept;
    constexpr reference access(data_handle_type p, size_t i) const noexcept;
    constexpr typename offset_policy::data_handle_type offset(
      data_handle_type p, size_t i) const noexcept;
  };
}
 Mandates: 
- byte_alignment is a power of two, and
- byte_alignment >= alignof(ElementType) is true.
 aligned_accessor meets the accessor policy requirements
. ElementType is required to be a complete object type
that is neither an abstract class type nor an array type
. Each specialization of 
aligned_accessor is
a trivially copyable type that models 
semiregular.[
0, n) is an accessible range
for an object 
p of type 
data_handle_type and
an object of type 
aligned_accessor if and only if
- [p, p + n) is a valid range, and,
- if n is greater than zero,
then is_sufficiently_aligned<byte_alignment>(p) is true.
[
Example 1: 
The following function 
compute
uses 
is_sufficiently_aligned to check
whether a given 
mdspan with 
default_accessor has
a data handle with sufficient alignment
to be used with 
aligned_accessor<float, 4 * sizeof(float)>.If so, the function dispatches to
a function 
compute_using_fourfold_overalignment
that requires fourfold over-alignment of arrays,
but can therefore use hardware-specific instructions,
such as four-wide SIMD (Single Instruction Multiple Data) instructions
.Otherwise, 
compute dispatches to a
possibly less optimized function 
compute_without_requiring_overalignment
that has no over-alignment requirement
. — 
end example]
template<class OtherElementType, size_t OtherByteAlignment>
  constexpr aligned_accessor(aligned_accessor<OtherElementType, OtherByteAlignment>) noexcept;
Constraints: 
- is_convertible_v<OtherElementType(*)[], element_type(*)[]>- 
is  true.
 
- OtherByteAlignment >= byte_alignment-  is  true.
 
 template<class OtherElementType>
  constexpr explicit aligned_accessor(default_accessor<OtherElementType>) noexcept;
Constraints: 
is_convertible_v<OtherElementType(*)[], element_type(*)[]>
is 
true. constexpr reference access(data_handle_type p, size_t i) const noexcept;
Preconditions: [
0, i + 1) is an accessible range for 
p and 
*this. Effects: Equivalent to: return assume_aligned<byte_alignment>(p)[i];
template<class OtherElementType>
  constexpr operator default_accessor<OtherElementType>() const noexcept;
Constraints: 
is_convertible_v<element_type(*)[], OtherElementType(*)[]>
is 
true. Effects: Equivalent to: return {};
constexpr typename offset_policy::data_handle_type
  offset(data_handle_type p, size_t i) const noexcept;
Preconditions: [
0, i + 1) is an accessible range for 
p and 
*this. Effects: Equivalent to: return assume_aligned<byte_alignment>(p) + i;
mdspan is a view of a multidimensional array of elements
. namespace std {
  template<class ElementType, class Extents, class LayoutPolicy = layout_right,
           class AccessorPolicy = default_accessor<ElementType>>
  class mdspan {
  public:
    using extents_type = Extents;
    using layout_type = LayoutPolicy;
    using accessor_type = AccessorPolicy;
    using mapping_type = typename layout_type::template mapping<extents_type>;
    using element_type = ElementType;
    using value_type = remove_cv_t<element_type>;
    using index_type = typename extents_type::index_type;
    using size_type = typename extents_type::size_type;
    using rank_type = typename extents_type::rank_type;
    using data_handle_type = typename accessor_type::data_handle_type;
    using reference = typename accessor_type::reference;
    static constexpr rank_type rank() noexcept { return extents_type::rank(); }
    static constexpr rank_type rank_dynamic() noexcept { return extents_type::rank_dynamic(); }
    static constexpr size_t static_extent(rank_type r) noexcept
      { return extents_type::static_extent(r); }
    constexpr index_type extent(rank_type r) const noexcept { return extents().extent(r); }
    
    constexpr mdspan();
    constexpr mdspan(const mdspan& rhs) = default;
    constexpr mdspan(mdspan&& rhs) = default;
    template<class... OtherIndexTypes>
      constexpr explicit mdspan(data_handle_type ptr, OtherIndexTypes... exts);
    template<class OtherIndexType, size_t N>
      constexpr explicit(N != rank_dynamic())
        mdspan(data_handle_type p, span<OtherIndexType, N> exts);
    template<class OtherIndexType, size_t N>
      constexpr explicit(N != rank_dynamic())
        mdspan(data_handle_type p, const array<OtherIndexType, N>& exts);
    constexpr mdspan(data_handle_type p, const extents_type& ext);
    constexpr mdspan(data_handle_type p, const mapping_type& m);
    constexpr mdspan(data_handle_type p, const mapping_type& m, const accessor_type& a);
    template<class OtherElementType, class OtherExtents,
             class OtherLayoutPolicy, class OtherAccessorPolicy>
      constexpr explicit(see below)
        mdspan(const mdspan<OtherElementType, OtherExtents,
                            OtherLayoutPolicy, OtherAccessorPolicy>& other);
    constexpr mdspan& operator=(const mdspan& rhs) = default;
    constexpr mdspan& operator=(mdspan&& rhs) = default;
    
    template<class... OtherIndexTypes>
      constexpr reference operator[](OtherIndexTypes... indices) const;
    template<class OtherIndexType>
      constexpr reference operator[](span<OtherIndexType, rank()> indices) const;
    template<class OtherIndexType>
      constexpr reference operator[](const array<OtherIndexType, rank()>& indices) const;
    template<class... OtherIndexTypes>
      constexpr reference
        at(OtherIndexTypes... indices) const;                           
    template<class OtherIndexType>
      constexpr reference
        at(span<OtherIndexType, rank()> indices) const;                 
    template<class OtherIndexType>
      constexpr reference
        at(const array<OtherIndexType, rank()>& indices) const;         
    constexpr size_type size() const noexcept;
    constexpr bool empty() const noexcept;
    friend constexpr void swap(mdspan& x, mdspan& y) noexcept;
    constexpr const extents_type& extents() const noexcept { return map_.extents(); }
    constexpr const data_handle_type& data_handle() const noexcept { return ptr_; }
    constexpr const mapping_type& mapping() const noexcept { return map_; }
    constexpr const accessor_type& accessor() const noexcept { return acc_; }
    static constexpr bool is_always_unique()
      { return mapping_type::is_always_unique(); }
    static constexpr bool is_always_exhaustive()
      { return mapping_type::is_always_exhaustive(); }
    static constexpr bool is_always_strided()
      { return mapping_type::is_always_strided(); }
    constexpr bool is_unique() const
      { return map_.is_unique(); }
    constexpr bool is_exhaustive() const
      { return map_.is_exhaustive(); }
    constexpr bool is_strided() const
      { return map_.is_strided(); }
    constexpr index_type stride(rank_type r) const
      { return map_.stride(r); }
  private:
    accessor_type acc_;         
    mapping_type map_;          
    data_handle_type ptr_;      
  };
  template<class CArray>
    requires (is_array_v<CArray> && rank_v<CArray> == 1)
    mdspan(CArray&)
      -> mdspan<remove_all_extents_t<CArray>, extents<size_t, extent_v<CArray, 0>>>;
  template<class Pointer>
    requires (is_pointer_v<remove_reference_t<Pointer>>)
    mdspan(Pointer&&)
      -> mdspan<remove_pointer_t<remove_reference_t<Pointer>>, extents<size_t>>;
  template<class ElementType, class... Integrals>
    requires ((is_convertible_v<Integrals, size_t> && ...) && sizeof...(Integrals) > 0)
    explicit mdspan(ElementType*, Integrals...)
      -> mdspan<ElementType, extents<size_t, maybe-static-ext<Integrals>...>>;
  template<class ElementType, class OtherIndexType, size_t N>
    mdspan(ElementType*, span<OtherIndexType, N>)
      -> mdspan<ElementType, dextents<size_t, N>>;
  template<class ElementType, class OtherIndexType, size_t N>
    mdspan(ElementType*, const array<OtherIndexType, N>&)
      -> mdspan<ElementType, dextents<size_t, N>>;
  template<class ElementType, class IndexType, size_t... ExtentsPack>
    mdspan(ElementType*, const extents<IndexType, ExtentsPack...>&)
      -> mdspan<ElementType, extents<IndexType, ExtentsPack...>>;
  template<class ElementType, class MappingType>
    mdspan(ElementType*, const MappingType&)
      -> mdspan<ElementType, typename MappingType::extents_type,
                typename MappingType::layout_type>;
  template<class MappingType, class AccessorType>
    mdspan(const typename AccessorType::data_handle_type&, const MappingType&,
           const AccessorType&)
      -> mdspan<typename AccessorType::element_type, typename MappingType::extents_type,
                typename MappingType::layout_type, AccessorType>;
}
 Mandates: 
- ElementType is a complete object type
that is neither an abstract class type nor an array type,
- Extents is a specialization of extents, and
- is_same_v<ElementType, typename AccessorPolicy::element_type>
is true.
 Each specialization 
MDS of 
mdspan models 
copyable and
- is_nothrow_move_constructible_v<MDS> is true,
- is_nothrow_move_assignable_v<MDS> is true, and
- is_nothrow_swappable_v<MDS> is true.
A specialization of 
mdspan is a trivially copyable type if
its 
accessor_type, 
mapping_type, and 
data_handle_type
are trivially copyable types
.Constraints: 
- rank_dynamic() > 0-  is  true.
 
- is_default_constructible_v<data_handle_type>-  is  true.
 
- is_default_constructible_v<mapping_type>-  is  true.
 
- is_default_constructible_v<accessor_type>-  is  true.
 
 Preconditions: 
[0, map_.required_span_size()) is
an accessible range of 
ptr_ and 
acc_
for the values of 
map_ and 
acc_
after the invocation of this constructor
. Effects: Value-initializes 
ptr_, 
map_, and 
acc_. template<class... OtherIndexTypes>
  constexpr explicit mdspan(data_handle_type p, OtherIndexTypes... exts);
Let 
N be 
sizeof...(OtherIndexTypes).Constraints: 
- (is_convertible_v<OtherIndexTypes, index_type> && ...) is true,
- (is_nothrow_constructible<index_type, OtherIndexTypes> && ...) is true,
- N == rank() || N == rank_dynamic() is true,
- is_constructible_v<mapping_type, extents_type> is true, and
- is_default_constructible_v<accessor_type> is true.
 Preconditions: 
[0, map_.required_span_size()) is
an accessible range of 
p and 
acc_
for the values of 
map_ and 
acc_
after the invocation of this constructor
. Effects: 
- Direct-non-list-initializes ptr_ with std::move(p),
- direct-non-list-initializes map_ with
extents_type(static_cast<index_type>(std::move(exts))...), and
- value-initializes acc_.
 template<class OtherIndexType, size_t N>
  constexpr explicit(N != rank_dynamic())
    mdspan(data_handle_type p, span<OtherIndexType, N> exts);
template<class OtherIndexType, size_t N>
  constexpr explicit(N != rank_dynamic())
    mdspan(data_handle_type p, const array<OtherIndexType, N>& exts);
Constraints: 
- is_convertible_v<const OtherIndexType&, index_type> is true,
- is_nothrow_constructible_v<index_type, const OtherIndexType&> is true,
- N == rank() || N == rank_dynamic() is true,
- is_constructible_v<mapping_type, extents_type> is true, and
- is_default_constructible_v<accessor_type> is true.
 Preconditions: 
[0, map_.required_span_size()) is
an accessible range of 
p and 
acc_
for the values of 
map_ and 
acc_
after the invocation of this constructor
. Effects: 
- Direct-non-list-initializes ptr_ with std::move(p),
- direct-non-list-initializes map_ with extents_type(exts), and
- value-initializes acc_.
 constexpr mdspan(data_handle_type p, const extents_type& ext);
Constraints: 
- is_constructible_v<mapping_type, const extents_type&> is true, and
- is_default_constructible_v<accessor_type> is true.
 Preconditions: 
[0, map_.required_span_size()) is
an accessible range of 
p and 
acc_
for the values of 
map_ and 
acc_
after the invocation of this constructor
. Effects: 
- Direct-non-list-initializes ptr_ with std::move(p),
- direct-non-list-initializes map_ with ext, and
- value-initializes acc_.
 constexpr mdspan(data_handle_type p, const mapping_type& m);
Constraints: 
is_default_constructible_v<accessor_type> is 
true. Preconditions: 
[0, m.required_span_size()) is
an accessible range of 
p and 
acc_
for the value of 
acc_ after the invocation of this constructor
. Effects: 
- Direct-non-list-initializes ptr_ with std::move(p),
- direct-non-list-initializes map_ with m, and
- value-initializes acc_.
 constexpr mdspan(data_handle_type p, const mapping_type& m, const accessor_type& a);
Preconditions: 
[0, m.required_span_size()) is
an accessible range of 
p and 
a. Effects: 
- Direct-non-list-initializes ptr_ with std::move(p),
- direct-non-list-initializes map_ with m, and
- direct-non-list-initializes acc_ with a.
 template<class OtherElementType, class OtherExtents,
         class OtherLayoutPolicy, class OtherAccessor>
  constexpr explicit(see below)
    mdspan(const mdspan<OtherElementType, OtherExtents,
                        OtherLayoutPolicy, OtherAccessor>& other);
Constraints: 
- is_constructible_v<mapping_type, const OtherLayoutPolicy::template mapping<Oth-
 erExtents>&>
is true, and
- is_constructible_v<accessor_type, const OtherAccessor&> is true.
 Mandates: 
- is_constructible_v<data_handle_type, const OtherAccessor::data_handle_type&> is
 true, and
- is_constructible_v<extents_type, OtherExtents> is true.
 Preconditions: 
[0, map_.required_span_size()) is
an accessible range of 
ptr_ and 
acc_
for values of 
ptr_, 
map_, and 
acc_
after the invocation of this constructor
. Hardened preconditions: For each rank index 
r of 
extents_type,
static_extent(r) == dynamic_extent || static_extent(r) == other.extent(r)
is 
true. Effects: 
- Direct-non-list-initializes ptr_ with other.ptr_,
- direct-non-list-initializes map_ with other.map_, and
- direct-non-list-initializes acc_ with other.acc_.
 Remarks: The expression inside explicit is equivalent to:
!is_convertible_v<const OtherLayoutPolicy::template mapping<OtherExtents>&, mapping_type>
|| !is_convertible_v<const OtherAccessor&, accessor_type>
template<class... OtherIndexTypes>
  constexpr reference operator[](OtherIndexTypes... indices) const;
Constraints: 
- (is_convertible_v<OtherIndexTypes, index_type> && ...) is true,
- (is_nothrow_constructible_v<index_type, OtherIndexTypes> && ...) is true, and
- sizeof...(OtherIndexTypes) == rank() is true.
 Let 
I be 
extents_type::index-cast(std::move(indices)).Hardened preconditions: 
I is a multidimensional index in 
extents().  [
Note 1: 
This implies that
map_(I) < map_.required_span_size()
is 
true. — 
end note]
Effects: Equivalent to:
return acc_.access(ptr_, map_(static_cast<index_type>(std::move(indices))...));
template<class OtherIndexType>
  constexpr reference operator[](span<OtherIndexType, rank()> indices) const;
template<class OtherIndexType>
  constexpr reference operator[](const array<OtherIndexType, rank()>& indices) const;
Constraints: 
- is_convertible_v<const OtherIndexType&, index_type> is true, and
- is_nothrow_constructible_v<index_type, const OtherIndexType&> is true.
 Effects: Let 
P be a parameter pack such that
is_same_v<make_index_sequence<rank()>, index_sequence<P...>>
is 
true.  Equivalent to:
return operator[](extents_type::index-cast(as_const(indices[P]))...);
template<class... OtherIndexTypes>
  constexpr reference at(OtherIndexTypes... indices) const;
Constraints: 
- (is_convertible_v<OtherIndexTypes, index_type> && ...) is true,
- (is_nothrow_constructible_v<index_type, OtherIndexTypes> && ...) is true, and
- sizeof...(OtherIndexTypes) == rank()  is true.
 Let 
I be 
extents_type::index-cast(std::move(indices)).Throws: 
out_of_range if 
I is not a multidimensional index in 
extents(). template<class OtherIndexType>
  constexpr reference at(span<OtherIndexType, rank()> indices) const;
template<class OtherIndexType>
  constexpr reference at(const array<OtherIndexType, rank()>& indices) const;
Constraints: 
- is_convertible_v<const OtherIndexType&, index_type> is true, and
- is_nothrow_constructible_v<index_type, const OtherIndexType&> is true.
 Effects: Let 
P be a parameter pack such that
is_same_v<make_index_sequence<rank()>, index_sequence<P...>>
is 
true.  Equivalent to:
return at(extents_type::index-cast(as_const(indices[P]))...);
constexpr size_type size() const noexcept;
Preconditions: The size of the multidimensional index space 
extents()
is representable as a value of type 
size_type (
[basic.fundamental])
. Returns: 
extents().fwd-prod-of-extents(rank()). constexpr bool empty() const noexcept;
Returns: 
true
if the size of the multidimensional index space 
extents() is 0,
otherwise 
false. friend constexpr void swap(mdspan& x, mdspan& y) noexcept;
Effects: Equivalent to:
swap(x.ptr_, y.ptr_);
swap(x.map_, y.map_);
swap(x.acc_, y.acc_);
The 
submdspan facilities create a new 
mdspan
viewing a subset of elements of an existing input 
mdspan.The subset viewed by the created 
mdspan is determined by
the 
SliceSpecifier arguments
.For each function defined in 
[mdspan.sub] that
takes a parameter pack named 
slices as an argument:
- let index_type be
  - M::index_type
  if the function is a member of a class M,
- otherwise,
  remove_reference_t<decltype(src)>::index_type
  if the function has a parameter named src,
- otherwise,
  the same type as the function's template argument IndexType;
 
- let rank be the number of elements in slices;
- let sk be the kth element of slices;
- let Sk be the type of sk; and
- let map-rank be an array<size_t, rank> such that
for each k in the range [0, rank),
map-rank[k] equals:
  
strided_slice represents a set of
extent regularly spaced integer indices
.  The indices start at 
offset, and
increase by increments of 
stride.namespace std {
  template<class OffsetType, class ExtentType, class StrideType>
  struct strided_slice {
    using offset_type = OffsetType;
    using extent_type = ExtentType;
    using stride_type = StrideType;
    [[no_unique_address]] offset_type offset{};
    [[no_unique_address]] extent_type extent{};
    [[no_unique_address]] stride_type stride{};
  };
}
 strided_slice has the data members and special members specified above
.  It has no base classes or members other than those specified
.Mandates: 
OffsetType, 
ExtentType, and 
StrideType
are signed or unsigned integer types, or
model 
integral-constant-like.  [
Note 1: 
strided_slice{.offset = 1, .extent = 10, .stride = 3}
indicates the indices 
1, 
4, 
7, and 
10.  Indices are selected from the half-open interval [
1, 1 + 10)
. — 
end note]
Specializations of 
submdspan_mapping_result
are returned by overloads of 
submdspan_mapping.namespace std {
  template<class LayoutMapping>
  struct submdspan_mapping_result {
    [[no_unique_address]] LayoutMapping mapping = LayoutMapping();
    size_t offset{};
  };
}
 submdspan_mapping_result has
the data members and special members specified above
.  It has no base classes or members other than those specified
.template<class T>
  constexpr T de-ice(T val) { return val; }
template<integral-constant-like T>
  constexpr auto de-ice(T) { return T::value; }
template<class IndexType, size_t k, class... SliceSpecifiers>
  constexpr IndexType first_(SliceSpecifiers... slices);
Mandates: 
IndexType is a signed or unsigned integer type
. Let 
ϕk denote the following value:
- sk if Sk models convertible_to<IndexType>;
- otherwise,
get<0>(sk)
if Sk models index-pair-like<IndexType>;
- otherwise,
de-ice(sk.offset)
if Sk is a specialization of strided_slice;
- otherwise,
0.
Preconditions: 
ϕk is representable as a value of type 
IndexType. Returns: 
extents<IndexType>::index-cast(ϕk). template<size_t k, class Extents, class... SliceSpecifiers>
  constexpr auto last_(const Extents& src, SliceSpecifiers... slices);
Mandates: 
Extents is a specialization of 
extents. Let 
index_type be 
typename Extents::index_type.Let 
λk denote the following value:
- de-ice(sk) + 1
if Sk models convertible_to<index_type>; otherwise
- get<1>(sk)
if Sk models index-pair-like<index_type>; otherwise
- de-ice(sk.offset) +
de-ice(sk.extent)
if Sk is a specialization of strided_slice; otherwise
- src.extent(k).
Preconditions: 
λk is representable as a value of type 
index_type. Returns: 
Extents::index-cast(λk). template<class IndexType, size_t N, class... SliceSpecifiers>
  constexpr array<IndexType, sizeof...(SliceSpecifiers)>
    src-indices(const array<IndexType, N>& indices, SliceSpecifiers... slices);
Mandates: 
IndexType is a signed or unsigned integer type
. Returns: An array<IndexType, sizeof...(SliceSpecifiers)> src_idx such that
for each k in the range [0, sizeof...(SliceSpecifiers)),
src_idx[k] equals
- first_<IndexType, k>(slices...) for each k
where map-rank[k] equals
dynamic_extent,
- otherwise,
first_<IndexType, k>(slices...) +
indices[map-rank[k]].
template<class IndexType, size_t... Extents, class... SliceSpecifiers>
  constexpr auto submdspan_extents(const extents<IndexType, Extents...>& src,
                                   SliceSpecifiers... slices);
Constraints: 
sizeof...(slices) equals 
sizeof...(Extents). Mandates: For each rank index 
k of 
src.extents(),
exactly one of the following is true:
- Sk models convertible_to<IndexType>,
- Sk models index-pair-like<IndexType>,
- is_convertible_v<Sk, full_extent_t> is true, or
- Sk is a specialization of strided_slice.
 Preconditions: For each rank index 
k of 
src.extents(),
all of the following are 
true:
- if Sk is a specialization of strided_slice
  - sk.extent=0, or
- sk.stride>0
 
- 0  ≤ first_<IndexType, k>(slices...)
 ≤ last_<k>(src, slices...)
 ≤ src.extent(k)
 Let 
SubExtents be a specialization of 
extents such that:
- SubExtents::rank() equals the number of k such that
Sk does not model convertible_to<IndexType>; and
- for each rank index k of Extents such that
map-rank[k] != dynamic_extent is true,
SubExtents::static_extent(map-rank[k]) equals:
  - Extents::static_extent(k)
  if is_convertible_v<Sk, full_extent_t> is true;
  otherwise
- de-ice(tuple_element_t<1, Sk>()) -
  de-ice(tuple_element_t<0, Sk>())
  if Sk models index-pair-like<IndexType>, and
  both tuple_element_t<0, Sk> and
  tuple_element_t<1, Sk>
  model integral-constant-like; otherwise
- 0,
  if Sk is a specialization of strided_slice, whose
  extent_type models integral-constant-like,
  for which extent_type() equals zero; otherwise
- 1 + (de-ice(Sk::extent_type()) - 1) /
  de-ice(Sk::stride_type()),
  if Sk is a specialization of strided_slice whose
  extent_type and stride_type
  model integral-constant-like;
- otherwise,
  dynamic_extent.
 
Returns: A value 
ext of type 
SubExtents such that
for each 
k
for which 
map-rank[k] != dynamic_extent is 
true,
ext.extent(map-rank[k]) equals:
- sk.extent == 0 ? 0 : 1 + (de-ice(sk.extent) - 1) / de-ice(sk.stride)
if Sk is a specialization of strided_slice,
- otherwise,
last_<k>(src, slices...) - first_<IndexType, k>(slices...).
 Constraints: 
sizeof...(slices) equals 
extents_type::rank(). Mandates: For each rank index 
k of 
extents(),
exactly one of the following is true:
- Sk models convertible_to<index_type>,
- Sk models index-pair-like<index_type>,
- is_convertible_v<Sk, full_extent_t> is true, or
- Sk is a specialization of strided_slice.
 Preconditions: For each rank index 
k of 
extents(),
all of the following are 
true:
- if Sk is a specialization of strided_slice,
sk.extent is equal to zero or
sk.stride is greater than zero; and
- 0             ≤ first_<index_type, k>(slices...) 
 0   ≤ last_<k>(extents(), slices...)
 0   ≤ extents().extent(k)
 Let 
sub_ext be
the result of 
submdspan_extents(extents(), slices...) and
let 
SubExtents be 
decltype(sub_ext).Let 
sub_strides be
an 
array<SubExtents::index_type, SubExtents::rank()>
such that for each rank index 
k of 
extents()
for which 
map-rank[k] is not 
dynamic_extent,
sub_strides[map-rank[k]] equals:
- stride(k) * de-ice(sk.stride)
if Sk is a specialization of strided_slice and
sk.stride < sk.extent is true;
- otherwise, stride(k).
Let 
P be a parameter pack
such that 
is_same_v<make_index_sequence<rank()>, index_sequence<P...>>
is 
true.If 
first_<index_type, k>(slices...)
equals 
extents().extent(k)
for any rank index 
k of 
extents(), then
let 
offset be a value of type 
size_t equal to
(*this).required_span_size().Otherwise,
let 
offset be a value of type 
size_t equal to
(*this)(first_<index_type, P>(slices...)...).template<class Extents>
template<class... SliceSpecifiers>
constexpr auto layout_left::mapping<Extents>::submdspan-mapping-impl(
      SliceSpecifiers... slices) const -> see below;
Returns: 
- submdspan_mapping_result{*this, 0},
if Extents::rank() == 0 is true;
- otherwise,
submdspan_mapping_result{layout_left::mapping(sub_ext), offset},
if SubExtents::rank() == 0 is true;
- otherwise,
submdspan_mapping_result{layout_left::mapping(sub_ext), offset},
if
  - for each k in the range [0, SubExtents::rank() - 1)),
  is_convertible_v<Sk, full_extent_t> is true; and
- for k equal to SubExtents::rank() - 1,
  Sk is a unit-stride slice for mapping;
 [ Note 1:  If the above conditions are true,
all  Sk with  k larger than  SubExtents::rank() - 1
are convertible to  index_type.
 —  end note] 
- otherwise,
submdspan_mapping_result{layout_left_padded<S_static>::mapping(sub_ext, stride(u + 1)),
                         offset}
if for a value u for which u+1 is
the smallest value p larger than zero
for which Sp is a unit-stride slice for mapping,
the following conditions are met:
- S0 is a unit-stride slice for mapping; and
- for each k in the range [u + 1, u + SubExtents::rank() - 1),
is_convertible_v<Sk, full_extent_t> is true; and
- for k equal to u + SubExtents::rank() - 1,
Sk is a unit-stride slice for mapping;
 and where S_static is:- dynamic_extent,
if static_extent(k) is dynamic_extent
for any k in the range [0, u + 1),
- otherwise, the product of all values
static_extent(k) for k in the range [0, u + 1);
 
- otherwise,
submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}
 template<class Extents>
template<class... SliceSpecifiers>
constexpr auto layout_right::mapping<Extents>::submdspan-mapping-impl(
      SliceSpecifiers... slices) const -> see below;
Returns: 
- submdspan_mapping_result{*this, 0},
if Extents::rank() == 0 is true;
- otherwise,
submdspan_mapping_result{layout_right::mapping(sub_ext), offset},
if SubExtents::rank() == 0 is true;
- otherwise,
submdspan_mapping_result{layout_left::mapping(sub_ext), offset},
if
  - for each k in the range [rank_ - SubExtents::rank() + 1, rank_),
  is_convertible_v<Sk, full_extent_t> is true; and
- for k equal to _rank - SubExtents::rank(),
  Sk is a unit-stride slice for mapping;
 [ Note 1:  If the above conditions are true,
all  Sk with  k<_rank - SubExtents::rank()
are convertible to  index_type.
 —  end note] 
- otherwise,
submdspan_mapping_result{layout_right_padded<S_static>::mapping(sub_ext,
                             stride(rank_ - u - 2)), offset}
if for a value u for which rank_−u−2 is
the largest value p smaller than rank_ - 1
for which Sp is a unit-stride slice for mapping,
the following conditions are met:
- for k equal to rank_ - 1,
Sk is a unit-stride slice for mapping; and
- for each k in the range
[rank_ - SubExtents::rank() - u + 1, rank_ - u - 1),
is_convertible_v<Sk, full_extent_t> is true; and
- for k equal to rank_ - SubExtents::rank() - u,
 Sk is a unit-stride slice for mapping;
 and where S_static is:- dynamic_extent,
if static_extent(k) is dynamic_extent
for any k in the range [rank_ - u - 1, rank_),
- otherwise, the product of all values
static_extent(k)
for k in the range [rank_ - u - 1, rank_);
 
- otherwise,
submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}
 template<class Extents>
template<class... SliceSpecifiers>
constexpr auto layout_stride::mapping<Extents>::submdspan-mapping-impl(
      SliceSpecifiers... slices) const -> see below;
Returns: 
- submdspan_mapping_result{*this, 0},
if Extents::rank() == 0 is true;
- otherwise,
submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}
 template<class Extents>
template<class... SliceSpecifiers>
constexpr auto layout_left_padded::mapping<Extents>::submdspan-mapping-impl(
    SliceSpecifiers... slices) const -> see below;
Returns: 
- submdspan_mapping_result{*this, 0},
if Extents::rank() == 0 is true;
- otherwise,
submdspan_mapping_result{layout_left::mapping(sub_ext), offset},
if rank_ == 1 is true or
SubExtents::rank() == 0 is true;
- otherwise,
submdspan_mapping_result{layout_left::mapping(sub_ext), offset},
if
- SubExtents::rank() == 1 is true and
- S0 is a unit-stride slice for mapping;
 
- otherwise,
submdspan_mapping_result{layout_left_padded<S_static>::mapping(sub_ext, stride(u + 1)),
                         offset}
if for a value u
for which u + 1 is the smallest value p larger than zero
for which Sp is a unit-stride slice for mapping,
the following conditions are met:
- S0 is a unit-stride slice for mapping; and
- for each k in the range [u + 1, u + SubExtents::rank() - 1),
is_convertible_v<Sk, full_extent_t> is true; and
- for k equal to u + SubExtents::rank() - 1,
Sk is a unit-stride slice for mapping;
 where S_static is:- dynamic_extent,
if static-padding-stride is dynamic_extent or
static_extent(k) is dynamic_extent
for any k in the range [1, u + 1),
- otherwise, the product of static-padding-stride and
all values static_extent(k) for k in the range [1, u + 1);
 
- otherwise,
submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}
 template<class Extents>
template<class... SliceSpecifiers>
constexpr auto layout_right_padded::mapping<Extents>::submdspan-mapping-impl(
    SliceSpecifiers... slices) const -> see below;
Returns: 
- submdspan_mapping_result{*this, 0},
if rank_ == 0 is true;
- otherwise,
submdspan_mapping_result{layout_right::mapping(sub_ext), offset},
 if rank_ == 1 is true or
SubExtents::rank() == 0 is true;
- otherwise,
submdspan_mapping_result{layout_right::mapping(sub_ext), offset},
if
- SubExtents::rank() == 1 is true and
- for k equal to rank_ - 1,
Sk is a unit-stride slice for mapping;
 
- otherwise,
submdspan_mapping_result{layout_right_padded<S_static>::mapping(sub_ext,
                             stride(rank_ - u - 2)), offset}
if for a value u
for which rank_ - u - 2
is the largest value p smaller than rank_ - 1
for which Sp is a unit-stride slice for mapping,
the following conditions are met:
- for k equal to rank_ - 1,
Sk is a unit-stride slice for mapping; and
- for each k in the range
[rank_ - SubExtents::rank() - u + 1, rank_ - u - 1)),
is_convertible_v<Sk, full_extent_t> is true; and
- for k equal to rank_ - SubExtents::rank() - u,
 Sk is a unit-stride slice for mapping;
 and where S_static is:- dynamic_extent
if static-padding-stride is dynamic_extent or
for any k in the range [rank_ - u - 1, rank_ - 1)
static_extent(k) is dynamic_extent,
- otherwise, the product of static-padding-stride and
all values static_extent(k)
with k in the range [rank_ - u - 1, rank_ - 1);
 
- otherwise,
submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}
 template<class ElementType, class Extents, class LayoutPolicy,
         class AccessorPolicy, class... SliceSpecifiers>
  constexpr auto submdspan(
    const mdspan<ElementType, Extents, LayoutPolicy, AccessorPolicy>& src,
    SliceSpecifiers... slices) -> see below;
Let 
index_type be 
typename Extents::index_type.Let 
sub_map_offset be the result of
submdspan_mapping(src.mapping(), slices...).[
Note 1: 
This invocation of 
submdspan_mapping
selects a function call via overload resolution
on a candidate set that includes the lookup set
found by argument-dependent lookup (
[basic.lookup.argdep])
. — 
end note]
Constraints: 
- sizeof...(slices) equals Extents::rank(), and
- the expression submdspan_mapping(src.mapping(), slices...)
is well-formed when treated as an unevaluated operand.
 Mandates: 
- decltype(submdspan_mapping(src.mapping(), slices...))- 
is a specialization of  submdspan_mapping_result.
 
- is_same_v<remove_cvref_t<decltype(sub_map_offset.mapping.extents())>,
decltype(submdspan_extents(src.mapping(), slices...))>- 
is  true.
 
- For each rank index  k-  of  src.extents()- ,
exactly one of the following is true:
   - Sk models convertible_to<index_type>,
- Sk models index-pair-like<index_type>,
- is_convertible_v<Sk, full_extent_t> is true, or
- Sk is a specialization of strided_slice.
 
 Preconditions: 
- For each rank index k of src.extents(),
all of the following are true:
  - if Sk is a specialization of strided_slice
    - sk.extent=0, or
- sk.stride>0
 
- 0  ≤ first_<index_type, k>(slices...)
   ≤ last_<k>(src.extents(), slices...)
   ≤ src.extent(k)
 
- sub_map_offset.mapping.extents() == submdspan_extents(src.mapping(), slices...)
is true; and
- for each integer pack I which is a multidimensional index
in sub_map_offset.mapping.extents(),
sub_map_offset.mapping(I...) + sub_map_offset.offset ==
  src.mapping()(src-indices(array{I...}, slices...))
is true.
 [
Note 2: 
These conditions ensure that the mapping returned by 
submdspan_mapping
matches the algorithmically expected index-mapping given the slice specifiers
. — 
end note]
Effects: Equivalent to:
auto sub_map_result = submdspan_mapping(src.mapping(), slices...);
return mdspan(src.accessor().offset(src.data_handle(), sub_map_result.offset),
              sub_map_result.mapping,
              typename AccessorPolicy::offset_policy(src.accessor()));
[
Example 1: 
Given a rank-3 
mdspan grid3d representing a three-dimensional grid
of regularly spaced points in a rectangular prism,
the function 
zero_surface sets all elements on
the surface of the 3-dimensional shape to zero
.It does so by reusing a function 
zero_2d
that takes a rank-2 
mdspan.
template<class T, class E, class L, class A>
void zero_2d(mdspan<T, E, L, A> a) {
  static_assert(a.rank() == 2);
  for (int i = 0; i < a.extent(0); i++)
    for (int j = 0; j < a.extent(1); j++)
      a[i, j] = 0;
}
template<class T, class E, class L, class A>
void zero_surface(mdspan<T, E, L, A> grid3d) {
  static_assert(grid3d.rank() == 3);
  zero_2d(submdspan(grid3d, 0, full_extent, full_extent));
  zero_2d(submdspan(grid3d, full_extent, 0, full_extent));
  zero_2d(submdspan(grid3d, full_extent, full_extent, 0));
  zero_2d(submdspan(grid3d, grid3d.extent(0) - 1, full_extent, full_extent));
  zero_2d(submdspan(grid3d, full_extent, grid3d.extent(1) - 1, full_extent));
  zero_2d(submdspan(grid3d, full_extent, full_extent, grid3d.extent(2) - 1));
}
 — end example]