[utility.arg.requirements]
describes requirements on types and expressions used to instantiate templates
defined in the C++ standard library.

[swappable.requirements] describes the requirements on swappable types and
swappable expressions.

[nullablepointer.requirements] describes the requirements on pointer-like
types that support null values.

[hash.requirements] describes the requirements on hash function objects.

[allocator.requirements] describes the requirements on storage
allocators.

The template definitions in the C++ standard library
refer to various named requirements whose details are set out in
Tables 28β35.

In these tables,

- T denotes an object or reference type to be supplied by a C++ program instantiating a template,
- a, b, and c denote values of type (possibly const) T,
- s and t denote modifiable lvalues of type T,
- u denotes an identifier,
- rv denotes an rvalue of type T, and
- v denotes an lvalue of type (possibly const) T or an rvalue of type const T.

In general, a default constructor is not required.

Certain container class
member function signatures specify T() as a default argument.

T() shall be a well-defined expression ([dcl.init]) if one of those
signatures is called using the default argument.

Table 28: *Cpp17EqualityComparable* requirements [tab:cpp17.equalitycomparable]

Expression | Return type | Requirement | |

a == b | decltype(a == b) models boolean-testable |

Table 29: *Cpp17LessThanComparable* requirements [tab:cpp17.lessthancomparable]

Expression | Return type | Requirement | |

a < b | decltype(a < b) models boolean-testable | < is a strict weak ordering relation ([alg.sorting]) |

Table 31: *Cpp17MoveConstructible* requirements [tab:cpp17.moveconstructible]

Expression | Post-condition | |

T u = rv; | u is equivalent to the value of rv before the construction | |

T(rv) | T(rv) is equivalent to the value of rv before the construction | |

Table 32: *Cpp17CopyConstructible* requirements (in addition to *Cpp17MoveConstructible*) [tab:cpp17.copyconstructible]

Expression | Post-condition | |

T u = v; | the value of v is unchanged and is equivalent to u | |

T(v) | the value of v is unchanged and is equivalent to T(v) |

Table 33: *Cpp17MoveAssignable* requirements [tab:cpp17.moveassignable]

Expression | Return type | Return value | Post-condition | |

t = rv | T& | t | If t and rv do not refer to the same object,
t is equivalent to the value of rv before the assignment | |

Table 34: *Cpp17CopyAssignable* requirements (in addition to *Cpp17MoveAssignable*) [tab:cpp17.copyassignable]

Expression | Return type | Return value | Post-condition | |

t = v | T& | t | t is equivalent to v, the value of v is unchanged |

An object t is *swappable with* an object u if and only if:

- the expressions swap(t, u) and swap(u, t) are valid when evaluated in the context described below, and
- these expressions have the following effects:
- the object referred to by t has the value originally held by u and
- the object referred to by u has the value originally held by t.

The context in which swap(t, u) and swap(u, t) are evaluated shall
ensure that a binary non-member function named βswapβ is selected via overload
resolution on a candidate set that includes:

- the two swap function templates defined in <utility> and
- the lookup set produced by argument-dependent lookup.

[*Note 1*: *end note*]

If T and U are both fundamental types or arrays of
fundamental types and the declarations from the header <utility> are in
scope, the overall lookup set described above is equivalent to that of the
qualified name lookup applied to the expression std::swap(t, u) or
std::swap(u, t) as appropriate.

β A type X meeting any of the iterator requirements ([iterator.requirements])
meets the *Cpp17ValueSwappable* requirements if,
for any dereferenceable object
x of type X,
*x is swappable.

[*Example 1*: *end example*]

User code can ensure that the evaluation of swap calls
is performed in an appropriate context under the various conditions as follows:
#include <cassert>
#include <utility>
// Preconditions: std::forward<T>(t) is swappable with std::forward<U>(u).
template<class T, class U>
void value_swap(T&& t, U&& u) {
using std::swap;
swap(std::forward<T>(t), std::forward<U>(u)); // OK, uses βswappable with'' conditions
// for rvalues and lvalues
}
// Preconditions: T meets the *Cpp17Swappable* requirements.
template<class T>
void lv_swap(T& t1, T& t2) {
using std::swap;
swap(t1, t2); // OK, uses swappable conditions for lvalues of type T
}
namespace N {
struct A { int m; };
struct Proxy { A* a; };
Proxy proxy(A& a) { return Proxy{ &a }; }
void swap(A& x, Proxy p) {
std::swap(x.m, p.a->m); // OK, uses context equivalent to swappable
// conditions for fundamental types
}
void swap(Proxy p, A& x) { swap(x, p); } // satisfy symmetry constraint
}
int main() {
int i = 1, j = 2;
lv_swap(i, j);
assert(i == 2 && j == 1);
N::A a1 = { 5 }, a2 = { -5 };
value_swap(a1, proxy(a2));
assert(a1.m == -5 && a2.m == 5);
}

β A *Cpp17NullablePointer* type is a pointer-like type that supports null values.

A type P meets the *Cpp17NullablePointer* requirements if:

A value-initialized object of type P produces the null value of the type.

The null value shall be equivalent only to itself.

A default-initialized object
of type P may have an indeterminate or erroneous value.

[*Note 1*: *end note*]

Operations involving indeterminate values can cause undefined behavior, and
operations involving erroneous values can cause erroneous behavior ([basic.indet]).

β Table 36: *Cpp17NullablePointer* requirements [tab:cpp17.nullablepointer]

Expression | Return type | Operational semantics | |

P u(np); | Postconditions: u == nullptr | ||

P u = np; | |||

P(np) | Postconditions: P(np) == nullptr | ||

t = np | P& | Postconditions: t == nullptr | |

a != b | decltype(a != b) models boolean-testable | !(a == b) | |

a == np | a == P() | ||

np == a | |||

a != np | !(a == np) | ||

np != a |

Table 37: *Cpp17Hash* requirements [tab:cpp17.hash]

Expression | Return type | Requirement | |

h(k) | size_t | ||

h(u) | size_t | Shall not modify u. |

The library describes a standard set of requirements for *allocators*,
which are class-type objects that encapsulate the information about an allocation model.

This information includes the knowledge of pointer types, the type of their
difference, the type of the size of objects in this allocation model, as well
as the memory allocation and deallocation primitives for it.

All of the
string types,
containers (except array),
string buffers and string streams ([input.output]), and
match_results are parameterized in terms of
allocators.

In subclause [allocator.requirements],

- T, U, C denote any cv-unqualified object type ([basic.types.general]),
- X denotes an allocator class for type T,
- Y denotes the corresponding allocator class for type U,
- XX denotes the type allocator_traits<X>,
- YY denotes the type allocator_traits<Y>,
- a, a1, a2 denote lvalues of type X,
- u denotes the name of a variable being declared,
- b denotes a value of type Y,
- c denotes a pointer of type C* through which indirection is valid,
- p denotes a value of type XX::pointer obtained by calling a1.allocate, where a1 == a,
- q denotes a value of type XX::const_pointer obtained by conversion from a value p,
- r denotes a value of type T& obtained by the expression *p,
- w denotes a value of type XX::void_pointer obtained by conversion from a value p,
- x denotes a value of type XX::const_void_pointer obtained by conversion from a value q or a value w,
- y denotes a value of type XX::const_void_pointer obtained by conversion from a result value of YY::allocate, or else a value of type (possibly const) std::nullptr_t,
- n denotes a value of type XX::size_type,
- Args denotes a template parameter pack, and
- args denotes a function parameter pack with the pattern Args&&.

The class template allocator_traits ([allocator.traits]) supplies
a uniform interface to all allocator types.

This subclause
describes the requirements on allocator types
and thus on types used to instantiate allocator_traits.

A requirement is optional if a default for a
given type or expression is specified.

Within the standard library allocator_traits
template, an optional requirement that is not supplied by an allocator is
replaced by the specified default type or expression.

```
typename X::pointer
```

```
typename X::const_pointer
```

```
typename X::void_pointer
typename Y::void_pointer
```

```
typename X::const_void_pointer
typename Y::const_void_pointer
```

```
typename X::value_type
```

```
typename X::size_type
```

```
typename X::difference_type
```

```
typename X::template rebind<U>::other
```

For allocator types that are not template instantiations of the
above form, no default is provided.

```
*p
```

```
*q
```

```
p->m
```

```
q->m
```

```
static_cast<XX::pointer>(w)
```

```
static_cast<XX::const_pointer>(x)
```

```
pointer_traits<XX::pointer>::pointer_to(r)
```

```
a.allocate(n)
```

```
a.allocate(n, y)
```

```
a.allocate_at_least(n)
```

```
a.deallocate(p, n)
```

```
a.max_size()
```

```
a1 == a2
```

```
a1 != a2
```

```
a == b
```

```
a != b
```

```
X u(a);
X u = a;
```

```
X u(b);
```

```
X u(std::move(a));
X u = std::move(a);
```

```
X u(std::move(b));
```

```
a.construct(c, args...)
```

```
a.destroy(c)
```

```
a.select_on_container_copy_construction()
```

```
typename X::propagate_on_container_copy_assignment
```

```
typename X::propagate_on_container_move_assignment
```

```
typename X::propagate_on_container_swap
```

```
typename X::is_always_equal
```

The XX::pointer, XX::const_pointer, XX::void_pointer, and
XX::const_void_pointer types shall meet the
*Cpp17NullablePointer* requirements (Table 36).

No constructor,
comparison operator function, copy operation, move operation, or swap operation on
these pointer types shall exit via an exception.

XX::pointer and XX::const_pointer shall also
meet the requirements for
a *Cpp17RandomAccessIterator* ([random.access.iterators]) and
the additional requirement that, when p and (p + n) are
dereferenceable pointer values for some integral value n,
addressof(*(p + n)) == addressof(*p) + n
is true.

Let x1 and x2 denote objects of (possibly different) types
XX::void_pointer, XX::const_void_pointer, XX::pointer,
or XX::const_pointer.

Then, x1 and x2 are
*equivalently-valued* pointer values, if and only if both x1 and x2
can be explicitly converted to the two corresponding objects px1 and px2
of type XX::const_pointer, using a sequence of static_casts
using only these four types, and the expression px1 == px2
evaluates to true.

[*Example 2*: *end example*]

The following is an allocator class template supporting the minimal
interface that meets the requirements of [allocator.requirements.general]:
template<class T>
struct SimpleAllocator {
using value_type = T;
SimpleAllocator(*ctor args*);
template<class U> SimpleAllocator(const SimpleAllocator<U>& other);
T* allocate(std::size_t n);
void deallocate(T* p, std::size_t n);
template<class U> bool operator==(const SimpleAllocator<U>& rhs) const;
};

β