[utility.requirements] (original) (raw)

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]

16.4.4.2 Template argument requirements [utility.arg.requirements]

16.4.4.3 Swappable requirements [swappable.requirements]

16.4.4.4 Cpp17NullablePointer requirements [nullablepointer.requirements]

16.4.4.5 Cpp17Hash requirements [hash.requirements]

16.4.4.6 Cpp17Allocator requirements [allocator.requirements]

16.4.4.6.1 General [allocator.requirements.general]

16.4.4.6.2 Allocator completeness requirements [allocator.requirements.completeness]


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

In these tables,

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 28Cpp17EqualityComparable requirements [tab:cpp17.equalitycomparable]

decltype(a == b) models boolean-testable == is an equivalence relation, that is, it has the following properties:If a == b and b == c, then a == c.

Table 30Cpp17DefaultConstructible requirements [tab:cpp17.defaultconstructible]

object t is default-initialized
object u is value-initialized or aggregate-initialized
an object of type T is value-initialized or aggregate-initialized

Table 31Cpp17MoveConstructible requirements [tab:cpp17.moveconstructible]

u is equivalent to the value of rv before the construction
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 32Cpp17CopyConstructible requirements (in addition to Cpp17MoveConstructible) [tab:cpp17.copyconstructible]

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

Table 33Cpp17MoveAssignable 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 35Cpp17Destructible requirements [tab:cpp17.destructible]

All resources owned by a 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 udenote an expression of type U.

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

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 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) orstd​::​swap(u, t) as appropriate.

— _end note_]

[Note 2:

It is unspecified whether a library component that has a swappable requirement includes the header 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 meets the Cpp17Swappable requirements if lvalues of type X are swappable.

A type X meeting any of the iterator requirements ([iterator.requirements]) meets the Cpp17ValueSwappable requirements if, for any dereferenceable objectx 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 <cassert> #include <utility> template<class T, class U> void value_swap(T&& t, U&& u) { using std::swap; swap(std::forward<T>(t), std::forward<U>(u)); } template<class T> void lv_swap(T& t1, T& t2) { using std::swap; swap(t1, t2); } 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); } void swap(Proxy p, A& x) { swap(x, p); } } 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

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:

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

— _end note_]

The effect shall be as if p != nullptrhad been evaluated in place of p.

No operation which is part of the Cpp17NullablePointer requirements shall exit via an exception.

In Table 36, u denotes an identifier, tdenotes a non-const lvalue of type P, a and bdenote values of type (possibly const) P, and np denotes a value of type (possibly const) std​::​nullptr_t.

Table 36Cpp17NullablePointer 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 decltype(a == np) and decltype(np == a) each model boolean-testable a == P()
🔗np == a
🔗a != np decltype(a != np) and decltype(np != a) each model boolean-testable !(a == np)
🔗np != a

16.4.4.5 Cpp17Hash requirements [hash.requirements]

A type H meets the Cpp17Hash requirements if

Given Key is an argument type for function objects of type H, in Table 37 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 37Cpp17Hash requirements [tab:cpp17.hash]

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().

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 ([strings]), containers ([containers]) (except array and inplace_vector), string buffers and string streams ([input.output]), andmatch_results are parameterized in terms of allocators.

In [allocator.requirements],

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_traitstemplate, an optional requirement that is not supplied by an allocator is replaced by the specified default type or expression.

[Note 1:

There are no program-defined specializations of allocator_traits.

— _end note_]

typename X::const_pointer

Mandates: XX​::​pointer is convertible to XX​::​const_pointer.

Remarks: Default: pointer_traits<XX​::​pointer>​::​rebind<const T>

typename X::void_pointertypename Y::void_pointer

Mandates: XX​::​pointer is convertible to XX​::​void_pointer.

XX​::​void_pointer and YY​::​void_pointer are the same type.

Remarks: Default:pointer_traits<XX​::​pointer>​::​rebind<void>

typename X::const_void_pointertypename Y::const_void_pointer

Mandates: XX​::​pointer, XX​::​const_pointer, and XX​::​void_pointerare convertible to XX​::​const_void_pointer.

XX​::​const_void_pointer and YY​::​const_void_pointerare the same type.

Remarks: Default:pointer_traits<XX​::​pointer>​::​rebind<const void>

Result: An unsigned integer type that can represent the size of the largest object in the allocation model.

Remarks: Default:make_unsigned_t<XX​::​difference_type>

typename X::difference_type

Result: A signed integer type that can represent the difference between any two pointers in the allocation model.

Remarks: Default:pointer_traits<XX​::​pointer>​::​difference_type

typename X::rebind<U>::other

Postconditions: For all U (including T),YY​::​rebind_alloc<T> is X.

Remarks: If Allocator is a class template instantiation of the formSomeAllocator<T, Args>, where Args is zero or more type arguments, and Allocator does not supply a rebind member template, the standard allocator_traits template usesSomeAllocator<U, Args> in place of Allocator​::​rebind<U>​::​otherby default.

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

[Note 2:

The member class template rebind of X is effectively a typedef template.

In general, if the name Allocator is bound to SomeAllocator<T>, thenAllocator​::​rebind<U>​::​other is the same type asSomeAllocator<U>, whereSomeAllocator<T>​::​value_type is T andSomeAllocator<U>​::​value_type is U.

— _end note_]

Postconditions: *q refers to the same object as *p.

Preconditions: (*p).m is well-defined.

Effects: Equivalent to (*p).m.

Preconditions: (*q).m is well-defined.

Effects: Equivalent to (*q).m.

static_cast<XX::pointer>(w)

Postconditions: static_cast<XX​::​pointer>(w) == p.

static_cast<XX::const_pointer>(x)

Result: XX​::​const_pointer

Postconditions: static_cast<XX​::​const_pointer>(x) == q.

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

Postconditions: Same as p.

Effects: Memory is allocated for an array of n Tand 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_]

Throws: allocate may throw an appropriate exception.

[Note 3:

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.

— _end note_]

Remarks: If n == 0, the return value is unspecified.

Effects: Same as a.allocate(n).

The use of y is unspecified, but it is intended as an aid to locality.

Remarks: Default: a.allocate(n)

Result: allocation_result<XX​::​pointer, XX​::​size_type>

Returns: allocation_result<XX​::​pointer, XX​::​size_type>{ptr, count}where ptr is memory allocated for an array of count Tand such an object is created but array elements are not constructed, such that count ≥ n.

If n == 0, the return value is unspecified.

Throws: allocate_at_least may throw an appropriate exception.

Remarks: Default: {a.allocate(n), n}.

Preconditions:

p has not been invalidated by an intervening call to deallocate.

Returns: The largest value n that can meaningfully be passed to a.allocate(n).

Remarks: Default:numeric_limits<size_type>​::​max() / sizeof(value_type)

Returns: true only if storage allocated from each can be deallocated via the other.

Remarks: operator== shall be reflexive, symmetric, and transitive.

Returns: a == YY​::​rebind_alloc<T>(b).

Postconditions: Y(u) == b and u == X(b).

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

Postconditions: The value of a is unchanged and is equal to u.

Postconditions: u is equal to the prior value of X(b).

Effects: Constructs an object of type C at c.

Remarks: Default:construct_at(c, std​::​forward<Args>(args)...)

Effects: Destroys the object at c.

Remarks: Default: destroy_at(c)

a.select_on_container_copy_construction()

Returns: Typically returns either a or X().

Remarks: Default: return a;

typename X::propagate_on_container_copy_assignment

Result: Identical to or derived from true_type or false_type.

Returns: true_type only if an allocator of type X should be copied when the client container is copy-assigned; if so, X shall meet the Cpp17CopyAssignable requirements (Table 34) and the copy operation shall not throw exceptions.

Remarks: Default: false_type

typename X::propagate_on_container_move_assignment

Result: Identical to or derived from true_type or false_type.

Returns: true_type only if an allocator of type X should be moved when the client container is move-assigned; if so, X shall meet the Cpp17MoveAssignable requirements (Table 33) and the move operation shall not throw exceptions.

Remarks: Default: false_type

typename X::propagate_on_container_swap

Result: Identical to or derived from true_type or false_type.

Returns: true_type only if an allocator of type X should be swapped when the client container is swapped; if so,X shall meet the Cpp17Swappable requirements ([swappable.requirements]) and the swap operation shall not throw exceptions.

Remarks: Default: false_type

typename X::is_always_equal

Result: Identical to or derived from true_type or false_type.

Returns: true_type only if the expression a1 == a2 is guaranteed to be true for any two (possibly const) valuesa1, a2 of type X.

Remarks: Default: is_empty<X>​::​type

An allocator type X shall meet theCpp17CopyConstructible requirements (Table 32).

The XX​::​pointer, XX​::​const_pointer, XX​::​void_pointer, andXX​::​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) + nis true.

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

Then, x1 and x2 areequivalently-valued pointer values, if and only if both x1 and x2can be explicitly converted to the two corresponding objects px1 and px2of type XX​::​const_pointer, using a sequence of static_casts using only these four types, and the expression px1 == px2evaluates to true.

Let w1 and w2 denote objects of type XX​::​void_pointer.

Then for the expressionsw1 == w2 w1 != w2either or both objects may be replaced by an equivalently-valued object of typeXX​::​const_void_pointer with no change in semantics.

Let p1 and p2 denote objects of type XX​::​pointer.

Then for the expressionsp1 == p2 p1 != p2 p1 < p2 p1 <= p2 p1 >= p2 p1 > p2 p1 - p2either or both objects may be replaced by an equivalently-valued object of typeXX​::​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 4:

Additionally, the member function allocatefor that type can fail by throwing an object of typebad_alloc.

— _end note_]

[Example 2:

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;};

— _end example_]

The following exposition-only concept defines the minimal requirements on an Allocator type.

namespace std { template<class Alloc> concept simple-allocator = requires(Alloc alloc, size_t n) { { *alloc.allocate(n) } -> same_as<typename Alloc::value_type&>;{ alloc.deallocate(alloc.allocate(n), n) };} && copy_constructible<Alloc> && equality_comparable<Alloc>;}

A type Alloc models simple-allocatorif it meets the requirements of [allocator.requirements.general].

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: