16 Library introduction [library]

16.4 Library-wide requirements [requirements]

16.4.4 Requirements on types and expressions [utility.requirements]

16.4.4.1 General [utility.requirements.general]

[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.

16.4.4.2 Template argument requirements [utility.arg.requirements]

The template definitions in the C++ standard library refer to various named requirements whose details are set out in Tables 25โ€“32.
In these tables, T is an object or reference type to be supplied by a C++ program instantiating a template; a, b, and c are values of type (possibly const) T; s and t are modifiable lvalues of type T; u denotes an identifier; rv is an rvalue of type T; and v is 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 25: Cpp17EqualityComparable requirements [tab:cpp17.equalitycomparable]
Expression
Return type
Requirement
a == b
convertible to bool
== is an equivalence relation, that is, it has the following properties:
  • For all a, a == a.
  • If a == b, then b == a.
  • If a == b and b == c, then a == c.
Table 26: Cpp17LessThanComparable requirements [tab:cpp17.lessthancomparable]
Expression
Return type
Requirement
a < b
convertible to bool
< is a strict weak ordering relation ([alg.sorting])
Table 27: Cpp17DefaultConstructible requirements [tab:cpp17.defaultconstructible]
Expression
Post-condition
T t;
object t is default-initialized
T u{};
object u is value-initialized or aggregate-initialized
T()
T{}
an object of type T is value-initialized or aggregate-initialized
Table 28: 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
rv's state is unspecified
[Note 1:
rv must still meet the requirements of the library component that is using it.
The operations listed in those requirements must work as specified whether rv has been moved from or not.
โ€” end note]
Table 29: 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 30: 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
rv's state is unspecified.
[Note 2:
rv must still meet the requirements of the library component that is using it, whether or not t and rv refer to the same object.
The operations listed in those requirements must work as specified whether rv has been moved from or not.
โ€” end note]
Table 31: 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
Table 32: Cpp17Destructible requirements [tab:cpp17.destructible]
Expression
Post-condition
u.~T()
All resources owned by u are reclaimed, no exception is propagated.
[Note 3:
Array types and non-object types are not Cpp17Destructible.
โ€” end note]

16.4.4.3 Swappable requirements [swappable.requirements]

This subclause provides definitions for swappable types and expressions.
In these definitions, let t denote an expression of type T, and let u denote an expression of type U.
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:
[Note 1:
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.
โ€” end note]
[Note 2:
It is unspecified whether a library component that has a swappable requirement includes the header <utility> to ensure an appropriate evaluation context.
โ€” end note]
An rvalue or lvalue t is swappable if and only if t is swappable with any rvalue or lvalue, respectively, of type T.
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:
User code can ensure that the evaluation of swap calls is performed in an appropriate context under the various conditions as follows: #include <utility> // Requires: std​::​forward<T>(t) shall be 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 } // Requires: lvalues of T shall be swappable. 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); }
โ€” end example]

16.4.4.4 Cpp17NullablePointer requirements [nullablepointer.requirements]

A Cpp17NullablePointer type is a pointer-like type that supports null values.
A type P meets the Cpp17NullablePointer requirements if:
  • P meets the Cpp17EqualityComparable, Cpp17DefaultConstructible, Cpp17CopyConstructible, Cpp17CopyAssignable, and Cpp17Destructible requirements,
  • lvalues of type P are swappable,
  • the expressions shown in Table 33 are valid and have the indicated semantics, and
  • P meets all the other requirements of this subclause.
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 value.
[Note 1:
Operations involving indeterminate values might cause undefined behavior.
โ€” end note]
An object p of type P can be contextually converted to bool.
The effect shall be as if p != nullptr had been evaluated in place of p.
No operation which is part of the Cpp17NullablePointer requirements shall exit via an exception.
In Table 33, u denotes an identifier, t denotes a non-const lvalue of type P, a and b denote values of type (possibly const) P, and np denotes a value of type (possibly const) std​::​nullptr_­t.
Table 33: 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
contextually convertible to bool
!(a == b)
a == np
contextually convertible to bool
a == P()
np == a
a != np
contextually convertible to bool
!(a == np)
np != a

16.4.4.5 Cpp17Hash requirements [hash.requirements]

A type H meets the Cpp17Hash requirements if:
  • it is a function object type ([function.objects]),
  • it meets the Cpp17CopyConstructible (Table 29) and Cpp17Destructible (Table 32) requirements, and
  • the expressions shown in Table 34 are valid and have the indicated semantics.
Given Key is an argument type for function objects of type H, in Table 34 h is a value of type (possibly const) H, u is an lvalue of type Key, and k is a value of a type convertible to (possibly const) Key.
Table 34: Cpp17Hash requirements [tab:cpp17.hash]
Expression
Return type
Requirement
h(k)
size_­t
The value returned shall depend only on the argument k for the duration of the program.
[Note 1:
Thus all evaluations of the expression h(k) with the same value for k yield the same result for a given execution of the program.
โ€” end note]
For two different values t1 and t2, the probability that h(t1) and h(t2) compare equal should be very small, approaching 1.0 / numeric_­limits<size_­t>​::​max().
h(u)
size_­t
Shall not modify u.

16.4.4.6 Cpp17Allocator requirements [allocator.requirements]

16.4.4.6.1 General [allocator.requirements.general]

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.
Table 35: Descriptive variable definitions [tab:allocator.req.var]
Variable
Definition
T, U, C
any cv-unqualified object type ([basic.types])
X
an allocator class for type T
Y
the corresponding allocator class for type U
XX
the type allocator_­traits<X>
YY
the type allocator_­traits<Y>
a, a1, a2
lvalues of type X
u
the name of a variable being declared
b
a value of type Y
c
a pointer of type C* through which indirection is valid
p
a value of type XX​::​pointer, obtained by calling a1.allocate, where a1 == a
q
a value of type XX​::​const_­pointer obtained by conversion from a value p
r
a value of type T& obtained by the expression *p
w
a value of type XX​::​void_­pointer obtained by conversion from a value p
x
a value of type XX​::​const_­void_­pointer obtained by conversion from a value q or a value w
y
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
a value of type XX​::​size_­type
Args
a template parameter pack
args
a function parameter pack with the pattern Args&&
The class template allocator_­traits ([allocator.traits]) supplies a uniform interface to all allocator types.
Table 35 describes the types manipulated through allocators.
Table 36 describes the requirements on allocator types and thus on types used to instantiate allocator_­traits.
A requirement is optional if the last column of Table 36 specifies a default for a given expression.
Within the standard library allocator_­traits template, an optional requirement that is not supplied by an allocator is replaced by the specified default expression.
A user specialization of allocator_­traits may provide different defaults and may provide defaults for different requirements than the primary template.
Within Tables 35 and 36, the use of move and forward always refers to std​::​move and std​::​forward, respectively.
Table 36: Cpp17Allocator requirements [tab:cpp17.allocator]
Expression
Return type
Assertion/note
Default
pre-/post-condition
X​::​pointer
T*
X​::​const_­pointer
X​::​pointer is convertible to X​::​const_­pointer
pointer_­traits<X​::​​pointer>​::​​rebind<const T>
X​::​void_­pointer
Y​::​void_­pointer
X​::​pointer is convertible to X​::​void_­pointer.
X​::​void_­pointer and Y​::​void_­pointer are the same type.
pointer_­traits<X​::​​pointer>​::​​rebind<void>
X​::​const_­void_­pointer
Y​::​const_­void_­pointer
X​::​pointer, X​::​const_­pointer, and X​::​void_­pointer are convertible to X​::​const_­void_­pointer.
X​::​const_­void_­pointer and Y​::​const_­void_­pointer are the same type.
pointer_­traits<X​::​​pointer>​::​​rebind<const void>
X​::​value_­type
Identical to T
X​::​size_­type
unsigned integer type
a type that can represent the size of the largest object in the allocation model
make_­unsigned_­t<X​::​​difference_­type>
X​::​difference_­type
signed integer type
a type that can represent the difference between any two pointers in the allocation model
pointer_­traits<X​::​​pointer>​::​​difference_­type
typename X​::​template rebind<U>​::​other
Y
For all U (including T), Y​::​template rebind<T>​::​other is X.
See Note A, below.
*p
T&
*q
const T&
*q refers to the same object as *p.
p->m
type of T​::​m
Preconditions: (*p).m is well-defined.

equivalent to (*p).m
q->m
type of T​::​m
Preconditions: (*q).m is well-defined.

equivalent to (*q).m
static_­cast<​X​::​pointer​>(w)
X​::​pointer
static_­cast<X​::​pointer>(w) == p
static_­cast<​X​::​const_­pointer​>(x)
X​::​const_­pointer
static_­cast< X​::​const_­pointer​>(x) == q
pointer_­traits<​X​::​pointer​>​::​pointer_­to(r)
X​::​pointer
same as p
a.allocate(n)
X​::​pointer
Memory is allocated for an array of n T and such an object is created but array elements are not constructed.
[Example 1:
When reusing storage denoted by some pointer value p, launder(reinterpret_­cast<T*>(new (p) byte[n * sizeof(T)])) can be used to implicitly create a suitable array object and obtain a pointer to it.
โ€” end example]
allocate may throw an appropriate exception.176
[Note 1:
If n == 0, the return value is unspecified.
โ€” end note]
a.allocate(n, y)
X​::​pointer
Same as a.allocate(n).
The use of y is unspecified, but it is intended as an aid to locality.
a.allocate(n)
a.deallocate(p,n)
(not used)
Preconditions: p is a value returned by an earlier call to allocate that has not been invalidated by an intervening call to deallocate.
n matches the value passed to allocate to obtain this memory.

Throws: Nothing.
a.max_­size()
X​::​size_­type
the largest value that can meaningfully be passed to X​::​allocate()
numeric_­limits<size_­type>​::​max() / sizeof(value_­type)
a1 == a2
bool
Returns true only if storage allocated from each can be deallocated via the other.
operator== shall be reflexive, symmetric, and transitive, and shall not exit via an exception.
a1 != a2
bool
same as !(a1 == a2)
a == b
bool
same as a == Y​::​rebind<T>​::​other(b)
a != b
bool
same as !(a == b)
X u(a);
X u = a;
Shall not exit via an exception.

Postconditions: u == a
X u(b);
Shall not exit via an exception.

Postconditions: Y(u) == b, u == X(b)
X u(std​::​move(a));
X u = std​::​move(a);
Shall not exit via an exception.

Postconditions: The value of a is unchanged and is equal to u.
X u(std​::​move(b));
Shall not exit via an exception.

Postconditions: u is equal to the prior value of X(b).
a.construct(c, args)
(not used)
Effects: Constructs an object of type C at c.
construct_­at(c, std​::​​forward<Args>(args)...)
a.destroy(c)
(not used)
Effects: Destroys the object at c
destroy_­at(c)
a.select_­on_­container_­copy_­construction()
X
Typically returns either a or X().
return a;
X​::​propagate_­on_­container_­copy_­assignment
Identical to or derived from true_­type or false_­type
true_­type only if an allocator of type X should be copied when the client container is copy-assigned.
See Note B, below.
false_­type
X​::​propagate_­on_­container_­move_­assignment
Identical to or derived from true_­type or false_­type
true_­type only if an allocator of type X should be moved when the client container is move-assigned.
See Note B, below.
false_­type
X​::​propagate_­on_­- container_­swap
Identical to or derived from true_­type or false_­type
true_­type only if an allocator of type X should be swapped when the client container is swapped.
See Note B, below.
false_­type
X​::​is_­always_­equal
Identical to or derived from true_­type or false_­type
true_­type only if the expression a1 == a2 is guaranteed to be true for any two (possibly const) values a1, a2 of type X.
is_­empty<X>​::​​type
Note A: The member class template rebind in the table above is effectively a typedef template.
[Note 2:
In general, if the name Allocator is bound to SomeAllocator<T>, then Allocator​::​rebind<U>​::​other is the same type as SomeAllocator<U>, where SomeAllocator<T>​::​value_­type is T and SomeAllocator<U>​::​​value_­type is U.
โ€” end note]
If Allocator is a class template instantiation of the form SomeAllocator<T, Args>, where Args is zero or more type arguments, and Allocator does not supply a rebind member template, the standard allocator_­traits template uses SomeAllocator<U, Args> in place of Allocator​::​​rebind<U>​::​other by default.
For allocator types that are not template instantiations of the above form, no default is provided.
Note B: If X​::​propagate_­on_­container_­copy_­assignment​::​value is true, X shall meet the Cpp17CopyAssignable requirements (Table 31) and the copy operation shall not throw exceptions.
If X​::​propagate_­on_­container_­move_­assignment​::​value is true, X shall meet the Cpp17MoveAssignable requirements (Table 30) and the move operation shall not throw exceptions.
If X​::​propagate_­on_­container_­swap​::​value is true, lvalues of type X shall be swappable and the swap operation shall not throw exceptions.
An allocator type X shall meet the Cpp17CopyConstructible requirements (Table 29).
The X​::​pointer, X​::​const_­pointer, X​::​void_­pointer, and X​::​const_­void_­pointer types shall meet the Cpp17NullablePointer requirements (Table 33).
No constructor, comparison operator function, copy operation, move operation, or swap operation on these pointer types shall exit via an exception.
X​::​pointer and X​::​const_­pointer shall also meet the requirements for a Cpp17RandomAccessIterator ([random.access.iterators]) and the additional requirement that, when a and (a + n) are dereferenceable pointer values for some integral value n, addressof(*(a + n)) == addressof(*a) + n is true.
Let x1 and x2 denote objects of (possibly different) types X​::​void_­pointer, X​::​const_­void_­pointer, X​::​pointer, or X​::​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 X​::​const_­pointer, using a sequence of static_­casts using only these four types, and the expression px1 == px2 evaluates to true.
Let w1 and w2 denote objects of type X​::​void_­pointer.
Then for the expressions w1 == w2 w1 != w2 either or both objects may be replaced by an equivalently-valued object of type X​::​const_­void_­pointer with no change in semantics.
Let p1 and p2 denote objects of type X​::​pointer.
Then for the expressions p1 == p2 p1 != p2 p1 < p2 p1 <= p2 p1 >= p2 p1 > p2 p1 - p2 either or both objects may be replaced by an equivalently-valued object of type X​::​const_­pointer with no change in semantics.
An allocator may constrain the types on which it can be instantiated and the arguments for which its construct or destroy members may be called.
If a type cannot be used with a particular allocator, the allocator class or the call to construct or destroy may fail to instantiate.
If the alignment associated with a specific over-aligned type is not supported by an allocator, instantiation of the allocator for that type may fail.
The allocator also may silently ignore the requested alignment.
[Note 3:
Additionally, the member function allocate for that type can fail by throwing an object of type bad_­alloc.
โ€” end note]
[Example 2:
The following is an allocator class template supporting the minimal interface that meets the requirements of Table 36: template<class Tp> struct SimpleAllocator { typedef Tp value_type; SimpleAllocator(ctor args); template<class T> SimpleAllocator(const SimpleAllocator<T>& other); [[nodiscard]] Tp* allocate(std::size_t n); void deallocate(Tp* p, std::size_t n); }; template<class T, class U> bool operator==(const SimpleAllocator<T>&, const SimpleAllocator<U>&); template<class T, class U> bool operator!=(const SimpleAllocator<T>&, const SimpleAllocator<U>&);
โ€” end example]
It is intended that a.allocate be an efficient means of allocating a single object of type T, even when sizeof(T) is small.
That is, there is no need for a container to maintain its own free list.
 โฎฅ

16.4.4.6.2 Allocator completeness requirements [allocator.requirements.completeness]

If X is an allocator class for type T, X additionally meets the allocator completeness requirements if, whether or not T is a complete type: