diff --git a/source/atomics.tex b/source/atomics.tex deleted file mode 100644 index a68674b232..0000000000 --- a/source/atomics.tex +++ /dev/null @@ -1,3851 +0,0 @@ -%!TEX root = std.tex -\rSec0[atomics]{Atomic operations library} - -\rSec1[atomics.general]{General} - -\pnum -This Clause describes components for fine-grained atomic access. This access is -provided via operations on atomic objects. - -\pnum -The following subclauses describe atomics requirements and components for types -and operations, as summarized in \tref{atomics.summary}. - -\begin{libsumtab}{Atomics library summary}{atomics.summary} -\ref{atomics.alias} & Type aliases & \tcode{} \\ -\ref{atomics.order} & Order and consistency & \\ -\ref{atomics.lockfree} & Lock-free property & \\ -\ref{atomics.wait} & Waiting and notifying & \\ -\ref{atomics.ref.generic} & Class template \tcode{atomic_ref} & \\ -\ref{atomics.types.generic} & Class template \tcode{atomic} & \\ -\ref{atomics.nonmembers} & Non-member functions & \\ -\ref{atomics.flag} & Flag type and operations & \\ -\ref{atomics.fences} & Fences & \\ \rowsep -\ref{stdatomic.h.syn} & C compatibility & \tcode{} \\ -\end{libsumtab} - -\rSec1[atomics.syn]{Header \tcode{} synopsis} - -\indexheader{atomic}% -\begin{codeblock} -namespace std { - // \ref{atomics.order}, order and consistency - enum class memory_order : @\unspec@; - template - T kill_dependency(T y) noexcept; -} - -// \ref{atomics.lockfree}, lock-free property -#define ATOMIC_BOOL_LOCK_FREE @\unspec@ -#define ATOMIC_CHAR_LOCK_FREE @\unspec@ -#define ATOMIC_CHAR8_T_LOCK_FREE @\unspec@ -#define ATOMIC_CHAR16_T_LOCK_FREE @\unspec@ -#define ATOMIC_CHAR32_T_LOCK_FREE @\unspec@ -#define ATOMIC_WCHAR_T_LOCK_FREE @\unspec@ -#define ATOMIC_SHORT_LOCK_FREE @\unspec@ -#define ATOMIC_INT_LOCK_FREE @\unspec@ -#define ATOMIC_LONG_LOCK_FREE @\unspec@ -#define ATOMIC_LLONG_LOCK_FREE @\unspec@ -#define ATOMIC_POINTER_LOCK_FREE @\unspec@ - -namespace std { - // \ref{atomics.ref.generic}, class template \tcode{atomic_ref} - template struct atomic_ref; - // \ref{atomics.ref.pointer}, partial specialization for pointers - template struct atomic_ref; - - // \ref{atomics.types.generic}, class template \tcode{atomic} - template struct atomic; - // \ref{atomics.types.pointer}, partial specialization for pointers - template struct atomic; - - // \ref{atomics.nonmembers}, non-member functions - template - bool atomic_is_lock_free(const volatile atomic*) noexcept; - template - bool atomic_is_lock_free(const atomic*) noexcept; - template - void atomic_store(volatile atomic*, typename atomic::value_type) noexcept; - template - void atomic_store(atomic*, typename atomic::value_type) noexcept; - template - void atomic_store_explicit(volatile atomic*, typename atomic::value_type, - memory_order) noexcept; - template - void atomic_store_explicit(atomic*, typename atomic::value_type, - memory_order) noexcept; - template - T atomic_load(const volatile atomic*) noexcept; - template - T atomic_load(const atomic*) noexcept; - template - T atomic_load_explicit(const volatile atomic*, memory_order) noexcept; - template - T atomic_load_explicit(const atomic*, memory_order) noexcept; - template - T atomic_exchange(volatile atomic*, typename atomic::value_type) noexcept; - template - T atomic_exchange(atomic*, typename atomic::value_type) noexcept; - template - T atomic_exchange_explicit(volatile atomic*, typename atomic::value_type, - memory_order) noexcept; - template - T atomic_exchange_explicit(atomic*, typename atomic::value_type, - memory_order) noexcept; - template - bool atomic_compare_exchange_weak(volatile atomic*, - typename atomic::value_type*, - typename atomic::value_type) noexcept; - template - bool atomic_compare_exchange_weak(atomic*, - typename atomic::value_type*, - typename atomic::value_type) noexcept; - template - bool atomic_compare_exchange_strong(volatile atomic*, - typename atomic::value_type*, - typename atomic::value_type) noexcept; - template - bool atomic_compare_exchange_strong(atomic*, - typename atomic::value_type*, - typename atomic::value_type) noexcept; - template - bool atomic_compare_exchange_weak_explicit(volatile atomic*, - typename atomic::value_type*, - typename atomic::value_type, - memory_order, memory_order) noexcept; - template - bool atomic_compare_exchange_weak_explicit(atomic*, - typename atomic::value_type*, - typename atomic::value_type, - memory_order, memory_order) noexcept; - template - bool atomic_compare_exchange_strong_explicit(volatile atomic*, - typename atomic::value_type*, - typename atomic::value_type, - memory_order, memory_order) noexcept; - template - bool atomic_compare_exchange_strong_explicit(atomic*, - typename atomic::value_type*, - typename atomic::value_type, - memory_order, memory_order) noexcept; - - template - T atomic_fetch_add(volatile atomic*, typename atomic::difference_type) noexcept; - template - T atomic_fetch_add(atomic*, typename atomic::difference_type) noexcept; - template - T atomic_fetch_add_explicit(volatile atomic*, typename atomic::difference_type, - memory_order) noexcept; - template - T atomic_fetch_add_explicit(atomic*, typename atomic::difference_type, - memory_order) noexcept; - template - T atomic_fetch_sub(volatile atomic*, typename atomic::difference_type) noexcept; - template - T atomic_fetch_sub(atomic*, typename atomic::difference_type) noexcept; - template - T atomic_fetch_sub_explicit(volatile atomic*, typename atomic::difference_type, - memory_order) noexcept; - template - T atomic_fetch_sub_explicit(atomic*, typename atomic::difference_type, - memory_order) noexcept; - template - T atomic_fetch_and(volatile atomic*, typename atomic::value_type) noexcept; - template - T atomic_fetch_and(atomic*, typename atomic::value_type) noexcept; - template - T atomic_fetch_and_explicit(volatile atomic*, typename atomic::value_type, - memory_order) noexcept; - template - T atomic_fetch_and_explicit(atomic*, typename atomic::value_type, - memory_order) noexcept; - template - T atomic_fetch_or(volatile atomic*, typename atomic::value_type) noexcept; - template - T atomic_fetch_or(atomic*, typename atomic::value_type) noexcept; - template - T atomic_fetch_or_explicit(volatile atomic*, typename atomic::value_type, - memory_order) noexcept; - template - T atomic_fetch_or_explicit(atomic*, typename atomic::value_type, - memory_order) noexcept; - template - T atomic_fetch_xor(volatile atomic*, typename atomic::value_type) noexcept; - template - T atomic_fetch_xor(atomic*, typename atomic::value_type) noexcept; - template - T atomic_fetch_xor_explicit(volatile atomic*, typename atomic::value_type, - memory_order) noexcept; - template - T atomic_fetch_xor_explicit(atomic*, typename atomic::value_type, - memory_order) noexcept; - - template - void atomic_wait(const volatile atomic*, typename atomic::value_type); - template - void atomic_wait(const atomic*, typename atomic::value_type); - template - void atomic_wait_explicit(const volatile atomic*, typename atomic::value_type, - memory_order); - template - void atomic_wait_explicit(const atomic*, typename atomic::value_type, - memory_order); - template - void atomic_notify_one(volatile atomic*); - template - void atomic_notify_one(atomic*); - template - void atomic_notify_all(volatile atomic*); - template - void atomic_notify_all(atomic*); - - // \ref{atomics.alias}, type aliases - using atomic_bool = atomic; - using atomic_char = atomic; - using atomic_schar = atomic; - using atomic_uchar = atomic; - using atomic_short = atomic; - using atomic_ushort = atomic; - using atomic_int = atomic; - using atomic_uint = atomic; - using atomic_long = atomic; - using atomic_ulong = atomic; - using atomic_llong = atomic; - using atomic_ullong = atomic; - using atomic_char8_t = atomic; - using atomic_char16_t = atomic; - using atomic_char32_t = atomic; - using atomic_wchar_t = atomic; - - using atomic_int8_t = atomic; - using atomic_uint8_t = atomic; - using atomic_int16_t = atomic; - using atomic_uint16_t = atomic; - using atomic_int32_t = atomic; - using atomic_uint32_t = atomic; - using atomic_int64_t = atomic; - using atomic_uint64_t = atomic; - - using atomic_int_least8_t = atomic; - using atomic_uint_least8_t = atomic; - using atomic_int_least16_t = atomic; - using atomic_uint_least16_t = atomic; - using atomic_int_least32_t = atomic; - using atomic_uint_least32_t = atomic; - using atomic_int_least64_t = atomic; - using atomic_uint_least64_t = atomic; - - using atomic_int_fast8_t = atomic; - using atomic_uint_fast8_t = atomic; - using atomic_int_fast16_t = atomic; - using atomic_uint_fast16_t = atomic; - using atomic_int_fast32_t = atomic; - using atomic_uint_fast32_t = atomic; - using atomic_int_fast64_t = atomic; - using atomic_uint_fast64_t = atomic; - - using atomic_intptr_t = atomic; - using atomic_uintptr_t = atomic; - using atomic_size_t = atomic; - using atomic_ptrdiff_t = atomic; - using atomic_intmax_t = atomic; - using atomic_uintmax_t = atomic; - - using atomic_signed_lock_free = @\seebelow@; - using atomic_unsigned_lock_free = @\seebelow@; - - // \ref{atomics.flag}, flag type and operations - struct atomic_flag; - - bool atomic_flag_test(const volatile atomic_flag*) noexcept; - bool atomic_flag_test(const atomic_flag*) noexcept; - bool atomic_flag_test_explicit(const volatile atomic_flag*, memory_order) noexcept; - bool atomic_flag_test_explicit(const atomic_flag*, memory_order) noexcept; - bool atomic_flag_test_and_set(volatile atomic_flag*) noexcept; - bool atomic_flag_test_and_set(atomic_flag*) noexcept; - bool atomic_flag_test_and_set_explicit(volatile atomic_flag*, memory_order) noexcept; - bool atomic_flag_test_and_set_explicit(atomic_flag*, memory_order) noexcept; - void atomic_flag_clear(volatile atomic_flag*) noexcept; - void atomic_flag_clear(atomic_flag*) noexcept; - void atomic_flag_clear_explicit(volatile atomic_flag*, memory_order) noexcept; - void atomic_flag_clear_explicit(atomic_flag*, memory_order) noexcept; - - void atomic_flag_wait(const volatile atomic_flag*, bool) noexcept; - void atomic_flag_wait(const atomic_flag*, bool) noexcept; - void atomic_flag_wait_explicit(const volatile atomic_flag*, - bool, memory_order) noexcept; - void atomic_flag_wait_explicit(const atomic_flag*, - bool, memory_order) noexcept; - void atomic_flag_notify_one(volatile atomic_flag*) noexcept; - void atomic_flag_notify_one(atomic_flag*) noexcept; - void atomic_flag_notify_all(volatile atomic_flag*) noexcept; - void atomic_flag_notify_all(atomic_flag*) noexcept; - - // \ref{atomics.fences}, fences - extern "C" void atomic_thread_fence(memory_order) noexcept; - extern "C" void atomic_signal_fence(memory_order) noexcept; -} -\end{codeblock} - -\rSec1[atomics.alias]{Type aliases} -\indexlibraryglobal{atomic_bool}% -\indexlibraryglobal{atomic_char}% -\indexlibraryglobal{atomic_schar}% -\indexlibraryglobal{atomic_uchar}% -\indexlibraryglobal{atomic_short}% -\indexlibraryglobal{atomic_ushort}% -\indexlibraryglobal{atomic_int}% -\indexlibraryglobal{atomic_uint}% -\indexlibraryglobal{atomic_long}% -\indexlibraryglobal{atomic_ulong}% -\indexlibraryglobal{atomic_llong}% -\indexlibraryglobal{atomic_ullong}% -\indexlibraryglobal{atomic_char8_t}% -\indexlibraryglobal{atomic_char16_t}% -\indexlibraryglobal{atomic_char32_t}% -\indexlibraryglobal{atomic_wchar_t}% -\indexlibraryglobal{atomic_int8_t}% -\indexlibraryglobal{atomic_uint8_t}% -\indexlibraryglobal{atomic_int16_t}% -\indexlibraryglobal{atomic_uint16_t}% -\indexlibraryglobal{atomic_int32_t}% -\indexlibraryglobal{atomic_uint32_t}% -\indexlibraryglobal{atomic_int64_t}% -\indexlibraryglobal{atomic_uint64_t}% -\indexlibraryglobal{atomic_int_least8_t}% -\indexlibraryglobal{atomic_uint_least8_t}% -\indexlibraryglobal{atomic_int_least16_t}% -\indexlibraryglobal{atomic_uint_least16_t}% -\indexlibraryglobal{atomic_int_least32_t}% -\indexlibraryglobal{atomic_uint_least32_t}% -\indexlibraryglobal{atomic_int_least64_t}% -\indexlibraryglobal{atomic_uint_least64_t}% -\indexlibraryglobal{atomic_int_fast8_t}% -\indexlibraryglobal{atomic_uint_fast8_t}% -\indexlibraryglobal{atomic_int_fast16_t}% -\indexlibraryglobal{atomic_uint_fast16_t}% -\indexlibraryglobal{atomic_int_fast32_t}% -\indexlibraryglobal{atomic_uint_fast32_t}% -\indexlibraryglobal{atomic_int_fast64_t}% -\indexlibraryglobal{atomic_uint_fast64_t}% -\indexlibraryglobal{atomic_intptr_t}% -\indexlibraryglobal{atomic_uintptr_t}% -\indexlibraryglobal{atomic_size_t}% -\indexlibraryglobal{atomic_ptrdiff_t}% -\indexlibraryglobal{atomic_intmax_t}% -\indexlibraryglobal{atomic_uintmax_t}% -\pnum -The type aliases \tcode{atomic_int$N$_t}, \tcode{atomic_uint$N$_t}, -\tcode{atomic_intptr_t}, and \tcode{atomic_uintptr_t} -are defined if and only if -\tcode{int$N$_t}, \tcode{uint$N$_t}, -\tcode{intptr_t}, and \tcode{uintptr_t} -are defined, respectively. - -\pnum -\indexlibraryglobal{atomic_signed_lock_free}% -\indexlibraryglobal{atomic_unsigned_lock_free}% -The type aliases -\tcode{atomic_signed_lock_free} and \tcode{atomic_unsigned_lock_free} -name specializations of \tcode{atomic} -whose template arguments are integral types, respectively signed and unsigned, -and whose \tcode{is_always_lock_free} property is \tcode{true}. -\begin{note} -\indextext{implementation!freestanding}% -These aliases are optional in freestanding implementations\iref{compliance}. -\end{note} -Implementations should choose for these aliases -the integral specializations of \tcode{atomic} -for which the atomic waiting and notifying operations\iref{atomics.wait} -are most efficient. - -\rSec1[atomics.order]{Order and consistency} -\indexlibraryglobal{memory_order}% -\indexlibrarymember{relaxed}{memory_order}% -\indexlibrarymember{consume}{memory_order}% -\indexlibrarymember{acquire}{memory_order}% -\indexlibrarymember{release}{memory_order}% -\indexlibrarymember{acq_rel}{memory_order}% -\indexlibrarymember{seq_cst}{memory_order}% -\indexlibraryglobal{memory_order_relaxed}% -\indexlibraryglobal{memory_order_consume}% -\indexlibraryglobal{memory_order_acquire}% -\indexlibraryglobal{memory_order_release}% -\indexlibraryglobal{memory_order_acq_rel}% -\indexlibraryglobal{memory_order_seq_cst}% - -\begin{codeblock} -namespace std { - enum class memory_order : @\unspec@ { - relaxed, consume, acquire, release, acq_rel, seq_cst - }; - inline constexpr memory_order memory_order_relaxed = memory_order::relaxed; - inline constexpr memory_order memory_order_consume = memory_order::consume; - inline constexpr memory_order memory_order_acquire = memory_order::acquire; - inline constexpr memory_order memory_order_release = memory_order::release; - inline constexpr memory_order memory_order_acq_rel = memory_order::acq_rel; - inline constexpr memory_order memory_order_seq_cst = memory_order::seq_cst; -} -\end{codeblock} - -\pnum -The enumeration \tcode{memory_order} specifies the detailed regular -(non-atomic) memory synchronization order as defined in -\ref{intro.multithread} and may provide for operation ordering. Its -enumerated values and their meanings are as follows: - -\begin{itemize} -\item \tcode{memory_order::relaxed}: no operation orders memory. - -\item \tcode{memory_order::release}, \tcode{memory_order::acq_rel}, and -\tcode{memory_order::seq_cst}: a store operation performs a release operation on the -affected memory location. - -\item \tcode{memory_order::consume}: a load operation performs a consume operation on the -affected memory location. -\begin{note} -Prefer \tcode{memory_order::acquire}, which provides stronger guarantees -than \tcode{memory_order::consume}. Implementations have found it infeasible -to provide performance better than that of \tcode{memory_order::acquire}. -Specification revisions are under consideration. -\end{note} - -\item \tcode{memory_order::acquire}, \tcode{memory_order::acq_rel}, and -\tcode{memory_order::seq_cst}: a load operation performs an acquire operation on the -affected memory location. -\end{itemize} - -\begin{note} -Atomic operations specifying \tcode{memory_order::relaxed} are relaxed -with respect to memory ordering. Implementations must still guarantee that any -given atomic access to a particular atomic object be indivisible with respect -to all other atomic accesses to that object. -\end{note} - -\pnum -An atomic operation $A$ that performs a release operation on an atomic -object $M$ synchronizes with an atomic operation $B$ that performs -an acquire operation on $M$ and takes its value from any side effect in the -release sequence headed by $A$. - -\pnum -An atomic operation $A$ on some atomic object $M$ is -\defn{coherence-ordered before} -another atomic operation $B$ on $M$ if -\begin{itemize} -\item $A$ is a modification, and -$B$ reads the value stored by $A$, or -\item $A$ precedes $B$ -in the modification order of $M$, or -\item $A$ and $B$ are not -the same atomic read-modify-write operation, and -there exists an atomic modification $X$ of $M$ -such that $A$ reads the value stored by $X$ and -$X$ precedes $B$ -in the modification order of $M$, or -\item there exists an atomic modification $X$ of $M$ -such that $A$ is coherence-ordered before $X$ and -$X$ is coherence-ordered before $B$. -\end{itemize} - -\pnum -There is a single total order $S$ -on all \tcode{memory_order::seq_cst} operations, including fences, -that satisfies the following constraints. -First, if $A$ and $B$ are -\tcode{memory_order::seq_cst} operations and -$A$ strongly happens before $B$, -then $A$ precedes $B$ in $S$. -Second, for every pair of atomic operations $A$ and -$B$ on an object $M$, -where $A$ is coherence-ordered before $B$, -the following four conditions are required to be satisfied by $S$: -\begin{itemize} -\item if $A$ and $B$ are both -\tcode{memory_order::seq_cst} operations, -then $A$ precedes $B$ in $S$; and -\item if $A$ is a \tcode{memory_order::seq_cst} operation and -$B$ happens before -a \tcode{memory_order::seq_cst} fence $Y$, -then $A$ precedes $Y$ in $S$; and -\item if a \tcode{memory_order::seq_cst} fence $X$ -happens before $A$ and -$B$ is a \tcode{memory_order::seq_cst} operation, -then $X$ precedes $B$ in $S$; and -\item if a \tcode{memory_order::seq_cst} fence $X$ -happens before $A$ and -$B$ happens before -a \tcode{memory_order::seq_cst} fence $Y$, -then $X$ precedes $Y$ in $S$. -\end{itemize} - -\pnum -\begin{note} -This definition ensures that $S$ is consistent with -the modification order of any atomic object $M$. -It also ensures that -a \tcode{memory_order::seq_cst} load $A$ of $M$ -gets its value either from the last modification of $M$ -that precedes $A$ in $S$ or -from some non-\tcode{memory_order::seq_cst} modification of $M$ -that does not happen before any modification of $M$ -that precedes $A$ in $S$. -\end{note} - -\pnum -\begin{note} -We do not require that $S$ be consistent with -``happens before''\iref{intro.races}. -This allows more efficient implementation -of \tcode{memory_order::acquire} and \tcode{memory_order::release} -on some machine architectures. -It can produce surprising results -when these are mixed with \tcode{memory_order::seq_cst} accesses. -\end{note} - -\pnum -\begin{note} -\tcode{memory_order::seq_cst} ensures sequential consistency only -for a program that is free of data races and -uses exclusively \tcode{memory_order::seq_cst} atomic operations. -Any use of weaker ordering will invalidate this guarantee -unless extreme care is used. -In many cases, \tcode{memory_order::seq_cst} atomic operations are reorderable -with respect to other atomic operations performed by the same thread. -\end{note} - -\pnum -Implementations should ensure that no ``out-of-thin-air'' values are computed that -circularly depend on their own computation. - -\begin{note} -For example, with \tcode{x} and \tcode{y} initially zero, -\begin{codeblock} -// Thread 1: -r1 = y.load(memory_order::relaxed); -x.store(r1, memory_order::relaxed); -\end{codeblock} - -\begin{codeblock} -// Thread 2: -r2 = x.load(memory_order::relaxed); -y.store(r2, memory_order::relaxed); -\end{codeblock} -this recommendation discourages producing \tcode{r1 == r2 == 42}, since the store of 42 to \tcode{y} is only -possible if the store to \tcode{x} stores \tcode{42}, which circularly depends on the -store to \tcode{y} storing \tcode{42}. Note that without this restriction, such an -execution is possible. -\end{note} - -\pnum -\begin{note} -The recommendation similarly disallows \tcode{r1 == r2 == 42} in the -following example, with \tcode{x} and \tcode{y} again initially zero: - -\begin{codeblock} -// Thread 1: -r1 = x.load(memory_order::relaxed); -if (r1 == 42) y.store(42, memory_order::relaxed); -\end{codeblock} - -\begin{codeblock} -// Thread 2: -r2 = y.load(memory_order::relaxed); -if (r2 == 42) x.store(42, memory_order::relaxed); -\end{codeblock} -\end{note} - -\pnum -Atomic read-modify-write operations shall always read the last value -(in the modification order) written before the write associated with -the read-modify-write operation. - -\pnum -Implementations should make atomic stores visible to atomic loads within a reasonable -amount of time. - -\indexlibraryglobal{kill_dependency}% -\begin{itemdecl} -template - T kill_dependency(T y) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -The argument does not carry a dependency to the return -value\iref{intro.multithread}. - -\pnum -\returns -\tcode{y}. -\end{itemdescr} - - -\rSec1[atomics.lockfree]{Lock-free property} - -\indexlibraryglobal{ATOMIC_BOOL_LOCK_FREE}% -\indexlibraryglobal{ATOMIC_CHAR_LOCK_FREE}% -\indexlibraryglobal{ATOMIC_CHAR8_T_LOCK_FREE}% -\indexlibraryglobal{ATOMIC_CHAR16_T_LOCK_FREE}% -\indexlibraryglobal{ATOMIC_CHAR32_T_LOCK_FREE}% -\indexlibraryglobal{ATOMIC_WCHAR_T_LOCK_FREE}% -\indexlibraryglobal{ATOMIC_SHORT_LOCK_FREE}% -\indexlibraryglobal{ATOMIC_INT_LOCK_FREE}% -\indexlibraryglobal{ATOMIC_LONG_LOCK_FREE}% -\indexlibraryglobal{ATOMIC_LLONG_LOCK_FREE}% -\indexlibraryglobal{ATOMIC_POINTER_LOCK_FREE}% -\indeximpldef{values of various \tcode{ATOMIC_..._LOCK_FREE} macros} -\begin{codeblock} -#define ATOMIC_BOOL_LOCK_FREE @\unspec@ -#define ATOMIC_CHAR_LOCK_FREE @\unspec@ -#define ATOMIC_CHAR8_T_LOCK_FREE @\unspec@ -#define ATOMIC_CHAR16_T_LOCK_FREE @\unspec@ -#define ATOMIC_CHAR32_T_LOCK_FREE @\unspec@ -#define ATOMIC_WCHAR_T_LOCK_FREE @\unspec@ -#define ATOMIC_SHORT_LOCK_FREE @\unspec@ -#define ATOMIC_INT_LOCK_FREE @\unspec@ -#define ATOMIC_LONG_LOCK_FREE @\unspec@ -#define ATOMIC_LLONG_LOCK_FREE @\unspec@ -#define ATOMIC_POINTER_LOCK_FREE @\unspec@ -\end{codeblock} - -\pnum -The \tcode{ATOMIC_..._LOCK_FREE} macros indicate the lock-free property of the -corresponding atomic types, with the signed and unsigned variants grouped -together. The properties also apply to the corresponding (partial) specializations of the -\tcode{atomic} template. A value of 0 indicates that the types are never -lock-free. A value of 1 indicates that the types are sometimes lock-free. A -value of 2 indicates that the types are always lock-free. - -\pnum -At least one signed integral specialization of the \tcode{atomic} template, -along with the specialization -for the corresponding unsigned type\iref{basic.fundamental}, -is always lock-free. -\begin{note} -\indextext{implementation!freestanding}% -This requirement is optional in freestanding implementations\iref{compliance}. -\end{note} - -\pnum -The functions \tcode{atomic::is_lock_free} and -\tcode{atomic_is_lock_free}\iref{atomics.types.operations} -indicate whether the object is lock-free. In any given program execution, the -result of the lock-free query -is the same for all atomic objects of the same type. - -\pnum -Atomic operations that are not lock-free are considered to potentially -block\iref{intro.progress}. - -\pnum -\recommended -Operations that are lock-free should also be address-free. -\begin{footnote} -That is, -atomic operations on the same memory location via two different addresses will -communicate atomically. -\end{footnote} -The implementation of these operations should not depend on any per-process state. -\begin{note} -This restriction enables communication by memory that is -mapped into a process more than once and by memory that is shared between two -processes. -\end{note} - -\rSec1[atomics.wait]{Waiting and notifying} - -\pnum -\defnx{Atomic waiting operations}{atomic!waiting operation} -and \defnx{atomic notifying operations}{atomic!notifying operation} -provide a mechanism to wait for the value of an atomic object to change -more efficiently than can be achieved with polling. -An atomic waiting operation may block until it is unblocked -by an atomic notifying operation, according to each function's effects. -\begin{note} -Programs are not guaranteed to observe transient atomic values, -an issue known as the A-B-A problem, -resulting in continued blocking if a condition is only temporarily met. -\end{note} - -\pnum -\begin{note} -The following functions are atomic waiting operations: -\begin{itemize} -\item \tcode{atomic::wait}, -\item \tcode{atomic_flag::wait}, -\item \tcode{atomic_wait} and \tcode{atomic_wait_explicit}, -\item \tcode{atomic_flag_wait} and \tcode{atomic_flag_wait_explicit}, and -\item \tcode{atomic_ref::wait}. -\end{itemize} -\end{note} - -\pnum -\begin{note} -The following functions are atomic notifying operations: -\begin{itemize} -\item \tcode{atomic::notify_one} and \tcode{atomic::notify_all}, -\item \tcode{atomic_flag::notify_one} and \tcode{atomic_flag::notify_all}, -\item \tcode{atomic_notify_one} and \tcode{atomic_notify_all}, -\item \tcode{atomic_flag_notify_one} and \tcode{atomic_flag_notify_all}, and -\item \tcode{atomic_ref::notify_one} and \tcode{atomic_ref::notify_all}. -\end{itemize} -\end{note} - -\indextext{atomic!waiting operation!eligible to be unblocked}% -\pnum -A call to an atomic waiting operation on an atomic object \tcode{M} -is \defn{eligible to be unblocked} -by a call to an atomic notifying operation on \tcode{M} -if there exist side effects \tcode{X} and \tcode{Y} on \tcode{M} such that: -\begin{itemize} -\item the atomic waiting operation has blocked after observing the result of \tcode{X}, -\item \tcode{X} precedes \tcode{Y} in the modification order of \tcode{M}, and -\item \tcode{Y} happens before the call to the atomic notifying operation. -\end{itemize} - -\rSec1[atomics.ref.generic]{Class template \tcode{atomic_ref}} - -\rSec2[atomics.ref.generic.general]{General} - -\indexlibraryglobal{atomic_ref}% -\indexlibrarymember{value_type}{atomic_ref}% -\begin{codeblock} -namespace std { - template struct atomic_ref { - private: - T* ptr; // \expos - public: - using value_type = T; - static constexpr size_t required_alignment = @\impdefx{required alignment for \tcode{atomic_ref} type's operations}@; - - static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic_ref} type's operations are always lock free}@; - bool is_lock_free() const noexcept; - - explicit atomic_ref(T&); - atomic_ref(const atomic_ref&) noexcept; - atomic_ref& operator=(const atomic_ref&) = delete; - - void store(T, memory_order = memory_order::seq_cst) const noexcept; - T operator=(T) const noexcept; - T load(memory_order = memory_order::seq_cst) const noexcept; - operator T() const noexcept; - - T exchange(T, memory_order = memory_order::seq_cst) const noexcept; - bool compare_exchange_weak(T&, T, - memory_order, memory_order) const noexcept; - bool compare_exchange_strong(T&, T, - memory_order, memory_order) const noexcept; - bool compare_exchange_weak(T&, T, - memory_order = memory_order::seq_cst) const noexcept; - bool compare_exchange_strong(T&, T, - memory_order = memory_order::seq_cst) const noexcept; - - void wait(T, memory_order = memory_order::seq_cst) const noexcept; - void notify_one() const noexcept; - void notify_all() const noexcept; - }; -} -\end{codeblock} - -\pnum -An \tcode{atomic_ref} object applies atomic operations\iref{atomics.general} to -the object referenced by \tcode{*ptr} such that, -for the lifetime\iref{basic.life} of the \tcode{atomic_ref} object, -the object referenced by \tcode{*ptr} is an atomic object\iref{intro.races}. - -\pnum -The program is ill-formed if \tcode{is_trivially_copyable_v} is \tcode{false}. - -\pnum -The lifetime\iref{basic.life} of an object referenced by \tcode{*ptr} -shall exceed the lifetime of all \tcode{atomic_ref}s that reference the object. -While any \tcode{atomic_ref} instances exist -that reference the \tcode{*ptr} object, -all accesses to that object shall exclusively occur -through those \tcode{atomic_ref} instances. -No subobject of the object referenced by \tcode{atomic_ref} -shall be concurrently referenced by any other \tcode{atomic_ref} object. - -\pnum -Atomic operations applied to an object -through a referencing \tcode{atomic_ref} are atomic with respect to -atomic operations applied through any other \tcode{atomic_ref} -referencing the same object. -\begin{note} -Atomic operations or the \tcode{atomic_ref} constructor can acquire -a shared resource, such as a lock associated with the referenced object, -to enable atomic operations to be applied to the referenced object. -\end{note} - -\rSec2[atomics.ref.ops]{Operations} - -\indexlibrarymember{required_alignment}{atomic_ref}% -\indexlibrarymember{required_alignment}{atomic_ref}% -\indexlibrarymember{required_alignment}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{required_alignment}{atomic_ref<\placeholder{floating-point}>}% -\begin{itemdecl} -static constexpr size_t required_alignment; -\end{itemdecl} - -\begin{itemdescr} -\pnum -The alignment required for an object to be referenced by an atomic reference, -which is at least \tcode{alignof(T)}. - -\pnum -\begin{note} -Hardware could require an object -referenced by an \tcode{atomic_ref} -to have stricter alignment\iref{basic.align} -than other objects of type \tcode{T}. -Further, whether operations on an \tcode{atomic_ref} -are lock-free could depend on the alignment of the referenced object. -For example, lock-free operations on \tcode{std::complex} -could be supported only if aligned to \tcode{2*alignof(double)}. -\end{note} -\end{itemdescr} - -\indexlibrarymember{is_always_lock_free}{atomic_ref}% -\indexlibrarymember{is_always_lock_free}{atomic_ref}% -\indexlibrarymember{is_always_lock_free}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{is_always_lock_free}{atomic_ref<\placeholder{floating-point}>}% -\begin{itemdecl} -static constexpr bool is_always_lock_free; -\end{itemdecl} - -\begin{itemdescr} -\pnum -The static data member \tcode{is_always_lock_free} is \tcode{true} -if the \tcode{atomic_ref} type's operations are always lock-free, -and \tcode{false} otherwise. -\end{itemdescr} - -\indexlibrarymember{is_lock_free}{atomic_ref}% -\indexlibrarymember{is_lock_free}{atomic_ref}% -\indexlibrarymember{is_lock_free}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{is_lock_free}{atomic_ref<\placeholder{floating-point}>}% -\begin{itemdecl} -bool is_lock_free() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true} if operations on all objects of the type \tcode{atomic_ref} -are lock-free, -\tcode{false} otherwise. -\end{itemdescr} - -\indexlibraryctor{atomic_ref}% -\indexlibraryctor{atomic_ref}% -\indexlibrary{\idxcode{atomic_ref<\placeholder{integral}>}!constructor}% -\indexlibrary{\idxcode{atomic_ref<\placeholder{floating-point}>}!constructor}% -\begin{itemdecl} -atomic_ref(T& obj); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -The referenced object is aligned to \tcode{required_alignment}. - -\pnum -\ensures -\tcode{*this} references \tcode{obj}. - -\pnum -\throws -Nothing. -\end{itemdescr} - -\indexlibraryctor{atomic_ref}% -\indexlibraryctor{atomic_ref}% -\indexlibrary{\idxcode{atomic_ref<\placeholder{integral}>}!constructor}% -\indexlibrary{\idxcode{atomic_ref<\placeholder{floating-point}>}!constructor}% -\begin{itemdecl} -atomic_ref(const atomic_ref& ref) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -\tcode{*this} references the object referenced by \tcode{ref}. -\end{itemdescr} - -\indexlibrarymember{store}{atomic_ref}% -\indexlibrarymember{store}{atomic_ref}% -\indexlibrarymember{store}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{store}{atomic_ref<\placeholder{floating-point}>}% -\begin{itemdecl} -void store(T desired, memory_order order = memory_order::seq_cst) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -The \tcode{order} argument is neither -\tcode{memory_order::consume}, -\tcode{memory_order::acquire}, nor -\tcode{memory_order::acq_rel}. - -\pnum -\effects -Atomically replaces the value referenced by \tcode{*ptr} -with the value of \tcode{desired}. -Memory is affected according to the value of \tcode{order}. -\end{itemdescr} - -\indexlibrarymember{operator=}{atomic_ref}% -\indexlibrarymember{operator=}{atomic_ref}% -\indexlibrarymember{operator=}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{operator=}{atomic_ref<\placeholder{floating-point}>}% -\begin{itemdecl} -T operator=(T desired) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -store(desired); -return desired; -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{load}{atomic_ref}% -\indexlibrarymember{load}{atomic_ref}% -\indexlibrarymember{load}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{load}{atomic_ref<\placeholder{floating-point}>}% -\begin{itemdecl} -T load(memory_order order = memory_order::seq_cst) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -The \tcode{order} argument is neither -\tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. - -\pnum -\effects -Memory is affected according to the value of \tcode{order}. - -\pnum -\returns -Atomically returns the value referenced by \tcode{*ptr}. -\end{itemdescr} - -\indexlibrarymember{operator \placeholder{type}}{atomic_ref}% -\indexlibrarymember{operator T*}{atomic_ref}% -\indexlibrarymember{operator \placeholder{integral}}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{operator \placeholder{floating-point}}{atomic_ref<\placeholder{floating-point}>}% -\begin{itemdecl} -operator T() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return load();} -\end{itemdescr} - -\indexlibrarymember{exchange}{atomic_ref}% -\indexlibrarymember{exchange}{atomic_ref}% -\indexlibrarymember{exchange}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{exchange}{atomic_ref<\placeholder{floating-point}>}% -\begin{itemdecl} -T exchange(T desired, memory_order order = memory_order::seq_cst) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Atomically replaces the value referenced by \tcode{*ptr} -with \tcode{desired}. -Memory is affected according to the value of \tcode{order}. -This operation is an atomic read-modify-write operation\iref{intro.multithread}. - -\pnum -\returns -Atomically returns the value referenced by \tcode{*ptr} -immediately before the effects. -\end{itemdescr} - -\indexlibrarymember{compare_exchange_weak}{atomic_ref}% -\indexlibrarymember{compare_exchange_weak}{atomic_ref}% -\indexlibrarymember{compare_exchange_weak}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{compare_exchange_weak}{atomic_ref<\placeholder{floating-point}>}% -\indexlibrarymember{compare_exchange_strong}{atomic_ref}% -\indexlibrarymember{compare_exchange_strong}{atomic_ref}% -\indexlibrarymember{compare_exchange_strong}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{compare_exchange_strong}{atomic_ref<\placeholder{floating-point}>}% -\begin{itemdecl} -bool compare_exchange_weak(T& expected, T desired, - memory_order success, memory_order failure) const noexcept; - -bool compare_exchange_strong(T& expected, T desired, - memory_order success, memory_order failure) const noexcept; - -bool compare_exchange_weak(T& expected, T desired, - memory_order order = memory_order::seq_cst) const noexcept; - -bool compare_exchange_strong(T& expected, T desired, - memory_order order = memory_order::seq_cst) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -The \tcode{failure} argument is neither -\tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. - -\pnum -\effects -Retrieves the value in \tcode{expected}. -It then atomically compares the value representation of -the value referenced by \tcode{*ptr} for equality -with that previously retrieved from \tcode{expected}, -and if \tcode{true}, replaces the value referenced by \tcode{*ptr} -with that in \tcode{desired}. -If and only if the comparison is \tcode{true}, -memory is affected according to the value of \tcode{success}, and -if the comparison is \tcode{false}, -memory is affected according to the value of \tcode{failure}. -When only one \tcode{memory_order} argument is supplied, -the value of \tcode{success} is \tcode{order}, and -the value of \tcode{failure} is \tcode{order} -except that a value of \tcode{memory_order::acq_rel} shall be replaced by -the value \tcode{memory_order::acquire} and -a value of \tcode{memory_order::release} shall be replaced by -the value \tcode{memory_order::relaxed}. -If and only if the comparison is \tcode{false} then, -after the atomic operation, -the value in \tcode{expected} is replaced by -the value read from the value referenced by \tcode{*ptr} -during the atomic comparison. -If the operation returns \tcode{true}, -these operations are atomic read-modify-write operations\iref{intro.races} -on the value referenced by \tcode{*ptr}. -Otherwise, these operations are atomic load operations on that memory. - -\pnum -\returns -The result of the comparison. - -\pnum -\remarks -A weak compare-and-exchange operation may fail spuriously. -That is, even when the contents of memory referred to -by \tcode{expected} and \tcode{ptr} are equal, -it may return \tcode{false} and -store back to \tcode{expected} the same memory contents -that were originally there. -\begin{note} -This spurious failure enables implementation of compare-and-exchange -on a broader class of machines, e.g., load-locked store-conditional machines. -A consequence of spurious failure is -that nearly all uses of weak compare-and-exchange will be in a loop. -When a compare-and-exchange is in a loop, -the weak version will yield better performance on some platforms. -When a weak compare-and-exchange would require a loop and -a strong one would not, the strong one is preferable. -\end{note} -\end{itemdescr} - -\indexlibrarymember{wait}{atomic_ref}% -\begin{itemdecl} -void wait(T old, memory_order order = memory_order::seq_cst) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{order} is -neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. - -\pnum -\effects -Repeatedly performs the following steps, in order: -\begin{itemize} -\item - Evaluates \tcode{load(order)} and - compares its value representation for equality against that of \tcode{old}. -\item - If they compare unequal, returns. -\item - Blocks until it - is unblocked by an atomic notifying operation or is unblocked spuriously. -\end{itemize} - -\pnum -\remarks -This function is an atomic waiting operation\iref{atomics.wait} -on atomic object \tcode{*ptr}. -\end{itemdescr} - -\indexlibrarymember{notify_one}{atomic_ref}% -\begin{itemdecl} -void notify_one() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Unblocks the execution of at least one atomic waiting operation on \tcode{*ptr} -that is eligible to be unblocked\iref{atomics.wait} by this call, -if any such atomic waiting operations exist. - -\pnum -\remarks -This function is an atomic notifying operation\iref{atomics.wait} -on atomic object \tcode{*ptr}. -\end{itemdescr} - -\indexlibrarymember{notify_all}{atomic_ref}% -\begin{itemdecl} -void notify_all() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Unblocks the execution of all atomic waiting operations on \tcode{*ptr} -that are eligible to be unblocked\iref{atomics.wait} by this call. - -\pnum -\remarks - This function is an atomic notifying operation\iref{atomics.wait} - on atomic object \tcode{*ptr}. -\end{itemdescr} - -\rSec2[atomics.ref.int]{Specializations for integral types} - -\pnum -\indexlibrary{\idxcode{atomic_ref<\placeholder{integral}>}}% -There are specializations of the \tcode{atomic_ref} class template -for the integral types -\tcode{char}, -\tcode{signed char}, -\tcode{unsigned char}, -\tcode{short}, -\tcode{unsigned short}, -\tcode{int}, -\tcode{unsigned int}, -\tcode{long}, -\tcode{unsigned long}, -\tcode{long long}, -\tcode{unsigned long long}, -\keyword{char8_t}, -\keyword{char16_t}, -\keyword{char32_t}, -\keyword{wchar_t}, -and any other types needed by the typedefs in the header \libheaderref{cstdint}. -For each such type \tcode{\placeholder{integral}}, -the specialization \tcode{atomic_ref<\placeholder{integral}>} provides -additional atomic operations appropriate to integral types. -\begin{note} -The specialization \tcode{atomic_ref} -uses the primary template\iref{atomics.ref.generic}. -\end{note} - -\begin{codeblock} -namespace std { - template<> struct atomic_ref<@\placeholder{integral}@> { - private: - @\placeholder{integral}@* ptr; // \expos - public: - using value_type = @\placeholder{integral}@; - using difference_type = value_type; - static constexpr size_t required_alignment = @\impdefx{required alignment for \tcode{atomic_ref} type's operations}@; - - static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic_ref} type's operations are always lock free}@; - bool is_lock_free() const noexcept; - - explicit atomic_ref(@\placeholder{integral}@&); - atomic_ref(const atomic_ref&) noexcept; - atomic_ref& operator=(const atomic_ref&) = delete; - - void store(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) const noexcept; - @\placeholdernc{integral}@ operator=(@\placeholder{integral}@) const noexcept; - @\placeholdernc{integral}@ load(memory_order = memory_order::seq_cst) const noexcept; - operator @\placeholdernc{integral}@() const noexcept; - - @\placeholdernc{integral}@ exchange(@\placeholdernc{integral}@, - memory_order = memory_order::seq_cst) const noexcept; - bool compare_exchange_weak(@\placeholder{integral}@&, @\placeholder{integral}@, - memory_order, memory_order) const noexcept; - bool compare_exchange_strong(@\placeholder{integral}@&, @\placeholder{integral}@, - memory_order, memory_order) const noexcept; - bool compare_exchange_weak(@\placeholder{integral}@&, @\placeholder{integral}@, - memory_order = memory_order::seq_cst) const noexcept; - bool compare_exchange_strong(@\placeholder{integral}@&, @\placeholder{integral}@, - memory_order = memory_order::seq_cst) const noexcept; - - @\placeholdernc{integral}@ fetch_add(@\placeholdernc{integral}@, - memory_order = memory_order::seq_cst) const noexcept; - @\placeholdernc{integral}@ fetch_sub(@\placeholdernc{integral}@, - memory_order = memory_order::seq_cst) const noexcept; - @\placeholdernc{integral}@ fetch_and(@\placeholdernc{integral}@, - memory_order = memory_order::seq_cst) const noexcept; - @\placeholdernc{integral}@ fetch_or(@\placeholdernc{integral}@, - memory_order = memory_order::seq_cst) const noexcept; - @\placeholdernc{integral}@ fetch_xor(@\placeholdernc{integral}@, - memory_order = memory_order::seq_cst) const noexcept; - - @\placeholdernc{integral}@ operator++(int) const noexcept; - @\placeholdernc{integral}@ operator--(int) const noexcept; - @\placeholdernc{integral}@ operator++() const noexcept; - @\placeholdernc{integral}@ operator--() const noexcept; - @\placeholdernc{integral}@ operator+=(@\placeholdernc{integral}@) const noexcept; - @\placeholdernc{integral}@ operator-=(@\placeholdernc{integral}@) const noexcept; - @\placeholdernc{integral}@ operator&=(@\placeholdernc{integral}@) const noexcept; - @\placeholdernc{integral}@ operator|=(@\placeholdernc{integral}@) const noexcept; - @\placeholdernc{integral}@ operator^=(@\placeholdernc{integral}@) const noexcept; - - void wait(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) const noexcept; - void notify_one() const noexcept; - void notify_all() const noexcept; - }; -} -\end{codeblock} - -\pnum -Descriptions are provided below only for members -that differ from the primary template. - -\pnum -The following operations perform arithmetic computations. -The correspondence among key, operator, and computation is specified -in \tref{atomic.types.int.comp}. - -\indexlibrarymember{fetch_add}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{fetch_and}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{fetch_or}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{fetch_sub}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{fetch_xor}{atomic_ref<\placeholder{integral}>}% -\begin{itemdecl} -@\placeholdernc{integral}@ fetch_@\placeholdernc{key}@(@\placeholdernc{integral}@ operand, memory_order order = memory_order::seq_cst) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Atomically replaces the value referenced by \tcode{*ptr} with -the result of the computation applied to the value referenced by \tcode{*ptr} -and the given operand. -Memory is affected according to the value of \tcode{order}. -These operations are atomic read-modify-write operations\iref{intro.races}. - -\pnum -\returns -Atomically, the value referenced by \tcode{*ptr} -immediately before the effects. - -\pnum -\indextext{signed integer representation!two's complement}% -\remarks -For signed integer types, -the result is as if the object value and parameters -were converted to their corresponding unsigned types, -the computation performed on those types, and -the result converted back to the signed type. -\begin{note} -There are no undefined results arising from the computation. -\end{note} -\end{itemdescr} - -\indexlibrarymember{operator+=}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{operator-=}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{operator\&=}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{operator"|=}{atomic_ref<\placeholder{integral}>}% -\indexlibrarymember{operator\caret=}{atomic_ref<\placeholder{integral}>}% -\begin{itemdecl} -@\placeholdernc{integral}@ operator @\placeholder{op}@=(@\placeholdernc{integral}@ operand) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\tcode{return fetch_\placeholdernc{key}(operand) \placeholder{op} operand;} -\end{itemdescr} - -\rSec2[atomics.ref.float]{Specializations for floating-point types} - -\pnum -\indexlibrary{\idxcode{atomic_ref<\placeholder{floating-point}>}}% -There are specializations of the \tcode{atomic_ref} class template -for the floating-point types -\tcode{float}, -\tcode{double}, and -\tcode{long double}. -For each such type \tcode{\placeholder{floating-point}}, -the specialization \tcode{atomic_ref<\placeholder{floating-\-point}>} provides -additional atomic operations appropriate to floating-point types. - -\begin{codeblock} -namespace std { - template<> struct atomic_ref<@\placeholder{floating-point}@> { - private: - @\placeholder{floating-point}@* ptr; // \expos - public: - using value_type = @\placeholder{floating-point}@; - using difference_type = value_type; - static constexpr size_t required_alignment = @\impdefx{required alignment for \tcode{atomic_ref} type's operations}@; - - static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic_ref} type's operations are always lock free}@; - bool is_lock_free() const noexcept; - - explicit atomic_ref(@\placeholder{floating-point}@&); - atomic_ref(const atomic_ref&) noexcept; - atomic_ref& operator=(const atomic_ref&) = delete; - - void store(@\placeholdernc{floating-point}@, memory_order = memory_order::seq_cst) const noexcept; - @\placeholder{floating-point}@ operator=(@\placeholder{floating-point}@) const noexcept; - @\placeholder{floating-point}@ load(memory_order = memory_order::seq_cst) const noexcept; - operator @\placeholdernc{floating-point}@() const noexcept; - - @\placeholder{floating-point}@ exchange(@\placeholdernc{floating-point}@, - memory_order = memory_order::seq_cst) const noexcept; - bool compare_exchange_weak(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, - memory_order, memory_order) const noexcept; - bool compare_exchange_strong(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, - memory_order, memory_order) const noexcept; - bool compare_exchange_weak(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, - memory_order = memory_order::seq_cst) const noexcept; - bool compare_exchange_strong(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, - memory_order = memory_order::seq_cst) const noexcept; - - @\placeholder{floating-point}@ fetch_add(@\placeholdernc{floating-point}@, - memory_order = memory_order::seq_cst) const noexcept; - @\placeholder{floating-point}@ fetch_sub(@\placeholdernc{floating-point}@, - memory_order = memory_order::seq_cst) const noexcept; - - @\placeholder{floating-point}@ operator+=(@\placeholder{floating-point}@) const noexcept; - @\placeholder{floating-point}@ operator-=(@\placeholder{floating-point}@) const noexcept; - - void wait(@\placeholdernc{floating-point}@, memory_order = memory_order::seq_cst) const noexcept; - void notify_one() const noexcept; - void notify_all() const noexcept; - }; -} -\end{codeblock} - -\pnum -Descriptions are provided below only for members -that differ from the primary template. - -\pnum -The following operations perform arithmetic computations. -The correspondence among key, operator, and computation is specified -in \tref{atomic.types.int.comp}. - -\indexlibrarymember{fetch_add}{atomic_ref<\placeholder{floating-point}>}% -\indexlibrarymember{fetch_sub}{atomic_ref<\placeholder{floating-point}>}% -\begin{itemdecl} -@\placeholder{floating-point}@ fetch_@\placeholdernc{key}@(@\placeholder{floating-point}@ operand, - memory_order order = memory_order::seq_cst) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Atomically replaces the value referenced by \tcode{*ptr} with -the result of the computation applied to the value referenced by \tcode{*ptr} -and the given operand. -Memory is affected according to the value of \tcode{order}. -These operations are atomic read-modify-write operations\iref{intro.races}. - -\pnum -\returns -Atomically, the value referenced by \tcode{*ptr} -immediately before the effects. - -\pnum -\remarks -If the result is not a representable value for its type\iref{expr.pre}, -the result is unspecified, -but the operations otherwise have no undefined behavior. -Atomic arithmetic operations on \tcode{\placeholder{floating-point}} should conform to -the \tcode{std::numeric_limits<\placeholder{floating-point}>} traits -associated with the floating-point type\iref{limits.syn}. -The floating-point environment\iref{cfenv} -for atomic arithmetic operations on \tcode{\placeholder{floating-point}} -may be different than the calling thread's floating-point environment. -\end{itemdescr} - -\indexlibrarymember{operator+=}{atomic_ref<\placeholder{floating-point}>}% -\indexlibrarymember{operator-=}{atomic_ref<\placeholder{floating-point}>}% -\begin{itemdecl} -@\placeholder{floating-point}@ operator @\placeholder{op}@=(@\placeholder{floating-point}@ operand) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\tcode{return fetch_\placeholder{key}(operand) \placeholdernc{op} operand;} -\end{itemdescr} - -\rSec2[atomics.ref.pointer]{Partial specialization for pointers} -\indexlibraryglobal{atomic_ref}% - -\begin{codeblock} -namespace std { - template struct atomic_ref { - private: - T** ptr; // \expos - public: - using value_type = T*; - using difference_type = ptrdiff_t; - static constexpr size_t required_alignment = @\impdefx{required alignment for \tcode{atomic_ref} type's operations}@; - - static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic_ref} type's operations are always lock free}@; - bool is_lock_free() const noexcept; - - explicit atomic_ref(T*&); - atomic_ref(const atomic_ref&) noexcept; - atomic_ref& operator=(const atomic_ref&) = delete; - - void store(T*, memory_order = memory_order::seq_cst) const noexcept; - T* operator=(T*) const noexcept; - T* load(memory_order = memory_order::seq_cst) const noexcept; - operator T*() const noexcept; - - T* exchange(T*, memory_order = memory_order::seq_cst) const noexcept; - bool compare_exchange_weak(T*&, T*, - memory_order, memory_order) const noexcept; - bool compare_exchange_strong(T*&, T*, - memory_order, memory_order) const noexcept; - bool compare_exchange_weak(T*&, T*, - memory_order = memory_order::seq_cst) const noexcept; - bool compare_exchange_strong(T*&, T*, - memory_order = memory_order::seq_cst) const noexcept; - - T* fetch_add(difference_type, memory_order = memory_order::seq_cst) const noexcept; - T* fetch_sub(difference_type, memory_order = memory_order::seq_cst) const noexcept; - - T* operator++(int) const noexcept; - T* operator--(int) const noexcept; - T* operator++() const noexcept; - T* operator--() const noexcept; - T* operator+=(difference_type) const noexcept; - T* operator-=(difference_type) const noexcept; - - void wait(T*, memory_order = memory_order::seq_cst) const noexcept; - void notify_one() const noexcept; - void notify_all() const noexcept; - }; -} -\end{codeblock} - -\pnum -Descriptions are provided below only for members -that differ from the primary template. - -\pnum -The following operations perform arithmetic computations. -The correspondence among key, operator, and computation is specified -in \tref{atomic.types.pointer.comp}. - -\indexlibrarymember{fetch_add}{atomic_ref}% -\indexlibrarymember{fetch_sub}{atomic_ref}% -\begin{itemdecl} -T* fetch_@\placeholdernc{key}@(difference_type operand, memory_order order = memory_order::seq_cst) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\mandates -\tcode{T} is a complete object type. - -\pnum -\effects -Atomically replaces the value referenced by \tcode{*ptr} with -the result of the computation applied to the value referenced by \tcode{*ptr} -and the given operand. -Memory is affected according to the value of \tcode{order}. -These operations are atomic read-modify-write operations\iref{intro.races}. - -\pnum -\returns -Atomically, the value referenced by \tcode{*ptr} -immediately before the effects. - -\pnum -\remarks -The result may be an undefined address, -but the operations otherwise have no undefined behavior. -\end{itemdescr} - -\indexlibrarymember{operator+=}{atomic_ref}% -\indexlibrarymember{operator-=}{atomic_ref}% -\begin{itemdecl} -T* operator @\placeholder{op}@=(difference_type operand) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\tcode{return fetch_\placeholder{key}(operand) \placeholdernc{op} operand;} -\end{itemdescr} - -\rSec2[atomics.ref.memop]{Member operators - common to integers and pointers to objects} - -\indexlibrarymember{operator++}{atomic_ref}% -\indexlibrarymember{operator++}{atomic_ref<\placeholder{integral}>}% -\begin{itemdecl} -value_type operator++(int) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return fetch_add(1);} -\end{itemdescr} - -\indexlibrarymember{operator--}{atomic_ref}% -\indexlibrarymember{operator--}{atomic_ref<\placeholder{integral}>}% -\begin{itemdecl} -value_type operator--(int) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return fetch_sub(1);} -\end{itemdescr} - -\indexlibrarymember{operator++}{atomic_ref}% -\indexlibrarymember{operator++}{atomic_ref<\placeholder{integral}>}% -\begin{itemdecl} -value_type operator++() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return fetch_add(1) + 1;} -\end{itemdescr} - -\indexlibrarymember{operator--}{atomic_ref}% -\indexlibrarymember{operator--}{atomic_ref<\placeholder{integral}>}% -\begin{itemdecl} -value_type operator--() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return fetch_sub(1) - 1;} -\end{itemdescr} - -\rSec1[atomics.types.generic]{Class template \tcode{atomic}} - -\rSec2[atomics.types.generic.general]{General} - -\indexlibraryglobal{atomic}% -\indexlibrarymember{value_type}{atomic}% -\begin{codeblock} -namespace std { - template struct atomic { - using value_type = T; - - static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; - bool is_lock_free() const volatile noexcept; - bool is_lock_free() const noexcept; - - // \ref{atomics.types.operations}, operations on atomic types - constexpr atomic() noexcept(is_nothrow_default_constructible_v); - constexpr atomic(T) noexcept; - atomic(const atomic&) = delete; - atomic& operator=(const atomic&) = delete; - atomic& operator=(const atomic&) volatile = delete; - - T load(memory_order = memory_order::seq_cst) const volatile noexcept; - T load(memory_order = memory_order::seq_cst) const noexcept; - operator T() const volatile noexcept; - operator T() const noexcept; - void store(T, memory_order = memory_order::seq_cst) volatile noexcept; - void store(T, memory_order = memory_order::seq_cst) noexcept; - T operator=(T) volatile noexcept; - T operator=(T) noexcept; - - T exchange(T, memory_order = memory_order::seq_cst) volatile noexcept; - T exchange(T, memory_order = memory_order::seq_cst) noexcept; - bool compare_exchange_weak(T&, T, memory_order, memory_order) volatile noexcept; - bool compare_exchange_weak(T&, T, memory_order, memory_order) noexcept; - bool compare_exchange_strong(T&, T, memory_order, memory_order) volatile noexcept; - bool compare_exchange_strong(T&, T, memory_order, memory_order) noexcept; - bool compare_exchange_weak(T&, T, memory_order = memory_order::seq_cst) volatile noexcept; - bool compare_exchange_weak(T&, T, memory_order = memory_order::seq_cst) noexcept; - bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) volatile noexcept; - bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) noexcept; - - void wait(T, memory_order = memory_order::seq_cst) const volatile noexcept; - void wait(T, memory_order = memory_order::seq_cst) const noexcept; - void notify_one() volatile noexcept; - void notify_one() noexcept; - void notify_all() volatile noexcept; - void notify_all() noexcept; - }; -} -\end{codeblock} - -\indexlibraryglobal{atomic}% -\pnum -The template argument for \tcode{T} shall meet the -\oldconcept{CopyConstructible} and \oldconcept{CopyAssignable} requirements. -The program is ill-formed if any of -\begin{itemize} -\item \tcode{is_trivially_copyable_v}, -\item \tcode{is_copy_constructible_v}, -\item \tcode{is_move_constructible_v}, -\item \tcode{is_copy_assignable_v}, or -\item \tcode{is_move_assignable_v} -\end{itemize} -is \tcode{false}. -\begin{note} -Type arguments that are -not also statically initializable can be difficult to use. -\end{note} - -\pnum -The specialization \tcode{atomic} is a standard-layout struct. - -\pnum -\begin{note} -The representation of an atomic specialization -need not have the same size and alignment requirement as -its corresponding argument type. -\end{note} - -\rSec2[atomics.types.operations]{Operations on atomic types} - -\indexlibraryctor{atomic}% -\indexlibraryctor{atomic}% -\indexlibrary{\idxcode{atomic<\placeholder{integral}>}!constructor}% -\indexlibrary{\idxcode{atomic<\placeholder{floating-point}>}!constructor}% -\begin{itemdecl} -constexpr atomic() noexcept(is_nothrow_default_constructible_v); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\mandates -\tcode{is_default_constructible_v} is \tcode{true}. - -\pnum -\effects -Initializes the atomic object with the value of \tcode{T()}. -Initialization is not an atomic operation\iref{intro.multithread}. -\end{itemdescr} - -\indexlibraryctor{atomic}% -\indexlibraryctor{atomic}% -\indexlibrary{\idxcode{atomic<\placeholder{integral}>}!constructor}% -\indexlibrary{\idxcode{atomic<\placeholder{floating-point}>}!constructor}% -\begin{itemdecl} -constexpr atomic(T desired) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes the object with the value \tcode{desired}. -Initialization is not an atomic operation\iref{intro.multithread}. -\begin{note} -It is possible to have an access to an atomic object \tcode{A} -race with its construction, for example by communicating the address of the -just-constructed object \tcode{A} to another thread via -\tcode{memory_order::relaxed} operations on a suitable atomic pointer -variable, and then immediately accessing \tcode{A} in the receiving thread. -This results in undefined behavior. -\end{note} -\end{itemdescr} - -\indexlibrarymember{is_always_lock_free}{atomic}% -\indexlibrarymember{is_always_lock_free}{atomic}% -\indexlibrarymember{is_always_lock_free}{atomic<\placeholder{integral}>}% -\indexlibrarymember{is_always_lock_free}{atomic<\placeholder{floating-point}>}% -\indexlibrarymember{is_always_lock_free}{atomic>}% -\indexlibrarymember{is_always_lock_free}{atomic>}% -\begin{itemdecl} -static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -The \keyword{static} data member \tcode{is_always_lock_free} is \tcode{true} -if the atomic type's operations are always lock-free, and \tcode{false} otherwise. -\begin{note} -The value of \tcode{is_always_lock_free} is consistent with the value of -the corresponding \tcode{ATOMIC_..._LOCK_FREE} macro, if defined. -\end{note} -\end{itemdescr} - -\indexlibraryglobal{atomic_is_lock_free}% -\indexlibrarymember{is_lock_free}{atomic}% -\indexlibrarymember{is_lock_free}{atomic}% -\indexlibrarymember{is_lock_free}{atomic<\placeholder{integral}>}% -\indexlibrarymember{is_lock_free}{atomic<\placeholder{floating-point}>}% -\indexlibrarymember{is_lock_free}{atomic>}% -\indexlibrarymember{is_lock_free}{atomic>}% -\begin{itemdecl} -bool is_lock_free() const volatile noexcept; -bool is_lock_free() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true} if the object's operations are lock-free, \tcode{false} otherwise. -\begin{note} -The return value of the \tcode{is_lock_free} member function -is consistent with the value of \tcode{is_always_lock_free} for the same type. -\end{note} -\end{itemdescr} - -\indexlibraryglobal{atomic_store}% -\indexlibraryglobal{atomic_store_explicit}% -\indexlibrarymember{store}{atomic}% -\indexlibrarymember{store}{atomic}% -\indexlibrarymember{store}{atomic<\placeholder{integral}>}% -\indexlibrarymember{store}{atomic<\placeholder{floating-point}>}% -\begin{itemdecl} -void store(T desired, memory_order order = memory_order::seq_cst) volatile noexcept; -void store(T desired, memory_order order = memory_order::seq_cst) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -For the \tcode{volatile} overload of this function, -\tcode{is_always_lock_free} is \tcode{true}. - -\pnum -\expects -The \tcode{order} argument is neither \tcode{memory_order::consume}, -\tcode{memory_order::acquire}, nor \tcode{memory_order::acq_rel}. - -\pnum -\effects -Atomically replaces the value pointed to by \keyword{this} -with the value of \tcode{desired}. Memory is affected according to the value of -\tcode{order}. -\end{itemdescr} - -\indexlibrarymember{operator=}{atomic}% -\indexlibrarymember{operator=}{atomic}% -\indexlibrarymember{operator=}{atomic<\placeholder{integral}>}% -\indexlibrarymember{operator=}{atomic<\placeholder{floating-point}>}% -\begin{itemdecl} -T operator=(T desired) volatile noexcept; -T operator=(T desired) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -For the \tcode{volatile} overload of this function, -\tcode{is_always_lock_free} is \tcode{true}. - -\pnum -\effects -Equivalent to \tcode{store(desired)}. - -\pnum -\returns -\tcode{desired}. -\end{itemdescr} - -\indexlibraryglobal{atomic_load}% -\indexlibraryglobal{atomic_load_explicit}% -\indexlibrarymember{load}{atomic}% -\indexlibrarymember{load}{atomic}% -\indexlibrarymember{load}{atomic<\placeholder{integral}>}% -\indexlibrarymember{load}{atomic<\placeholder{floating-point}>}% -\begin{itemdecl} -T load(memory_order order = memory_order::seq_cst) const volatile noexcept; -T load(memory_order order = memory_order::seq_cst) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -For the \tcode{volatile} overload of this function, -\tcode{is_always_lock_free} is \tcode{true}. - -\pnum -\expects -The \tcode{order} argument is neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. - -\pnum -\effects -Memory is affected according to the value of \tcode{order}. - -\pnum -\returns -Atomically returns the value pointed to by \keyword{this}. -\end{itemdescr} - -\indexlibrarymember{operator \placeholder{type}}{atomic}% -\indexlibrarymember{operator T*}{atomic}% -\indexlibrarymember{operator \placeholder{integral}}{atomic<\placeholder{integral}>}% -\indexlibrarymember{operator \placeholder{floating-point}}{atomic<\placeholder{floating-point}>}% -\begin{itemdecl} -operator T() const volatile noexcept; -operator T() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -For the \tcode{volatile} overload of this function, -\tcode{is_always_lock_free} is \tcode{true}. - -\pnum -\effects -Equivalent to: \tcode{return load();} -\end{itemdescr} - - -\indexlibraryglobal{atomic_exchange}% -\indexlibraryglobal{atomic_exchange_explicit}% -\indexlibrarymember{exchange}{atomic}% -\indexlibrarymember{exchange}{atomic}% -\indexlibrarymember{exchange}{atomic<\placeholder{integral}>}% -\indexlibrarymember{exchange}{atomic<\placeholder{floating-point}>}% -\begin{itemdecl} -T exchange(T desired, memory_order order = memory_order::seq_cst) volatile noexcept; -T exchange(T desired, memory_order order = memory_order::seq_cst) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -For the \tcode{volatile} overload of this function, -\tcode{is_always_lock_free} is \tcode{true}. - -\pnum -\effects -Atomically replaces the value pointed to by \keyword{this} -with \tcode{desired}. -Memory is affected according to the value of \tcode{order}. -These operations are atomic read-modify-write operations\iref{intro.multithread}. - -\pnum -\returns -Atomically returns the value pointed to by \keyword{this} immediately before the effects. -\end{itemdescr} - -\indexlibraryglobal{atomic_compare_exchange_weak}% -\indexlibraryglobal{atomic_compare_exchange_strong}% -\indexlibraryglobal{atomic_compare_exchange_weak_explicit}% -\indexlibraryglobal{atomic_compare_exchange_strong_explicit}% -\indexlibrarymember{compare_exchange_weak}{atomic}% -\indexlibrarymember{compare_exchange_weak}{atomic}% -\indexlibrarymember{compare_exchange_weak}{atomic<\placeholder{integral}>}% -\indexlibrarymember{compare_exchange_weak}{atomic<\placeholder{floating-point}>}% -\indexlibrarymember{compare_exchange_strong}{atomic}% -\indexlibrarymember{compare_exchange_strong}{atomic}% -\indexlibrarymember{compare_exchange_strong}{atomic<\placeholder{integral}>}% -\indexlibrarymember{compare_exchange_strong}{atomic<\placeholder{floating-point}>}% -\begin{itemdecl} -bool compare_exchange_weak(T& expected, T desired, - memory_order success, memory_order failure) volatile noexcept; -bool compare_exchange_weak(T& expected, T desired, - memory_order success, memory_order failure) noexcept; -bool compare_exchange_strong(T& expected, T desired, - memory_order success, memory_order failure) volatile noexcept; -bool compare_exchange_strong(T& expected, T desired, - memory_order success, memory_order failure) noexcept; -bool compare_exchange_weak(T& expected, T desired, - memory_order order = memory_order::seq_cst) volatile noexcept; -bool compare_exchange_weak(T& expected, T desired, - memory_order order = memory_order::seq_cst) noexcept; -bool compare_exchange_strong(T& expected, T desired, - memory_order order = memory_order::seq_cst) volatile noexcept; -bool compare_exchange_strong(T& expected, T desired, - memory_order order = memory_order::seq_cst) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -For the \tcode{volatile} overload of this function, -\tcode{is_always_lock_free} is \tcode{true}. - -\pnum -\expects -The \tcode{failure} argument is neither \tcode{memory_order::release} nor -\tcode{memory_order::acq_rel}. - -\pnum -\effects -Retrieves the value in \tcode{expected}. It then atomically -compares the value representation of the value pointed to by \keyword{this} -for equality with that previously retrieved from \tcode{expected}, -and if true, replaces the value pointed to -by \keyword{this} with that in \tcode{desired}. -If and only if the comparison is \tcode{true}, memory is affected according to the -value of \tcode{success}, and if the comparison is false, memory is affected according -to the value of \tcode{failure}. When only one \tcode{memory_order} argument is -supplied, the value of \tcode{success} is \tcode{order}, and the value of -\tcode{failure} is \tcode{order} except that a value of \tcode{memory_order::acq_rel} -shall be replaced by the value \tcode{memory_order::acquire} and a value of -\tcode{memory_order::release} shall be replaced by the value -\tcode{memory_order::relaxed}. -If and only if the comparison is false then, after the atomic operation, -the value in \tcode{expected} is replaced by the value -pointed to by \keyword{this} during the atomic comparison. -If the operation returns \tcode{true}, these -operations are atomic read-modify-write -operations\iref{intro.multithread} on the memory -pointed to by \keyword{this}. -Otherwise, these operations are atomic load operations on that memory. - -\pnum -\returns -The result of the comparison. - -\pnum -\begin{note} -For example, the effect of -\tcode{compare_exchange_strong} -on objects without padding bits\iref{term.padding.bits} is -\begin{codeblock} -if (memcmp(this, &expected, sizeof(*this)) == 0) - memcpy(this, &desired, sizeof(*this)); -else - memcpy(&expected, this, sizeof(*this)); -\end{codeblock} -\end{note} -\begin{example} -The expected use of the compare-and-exchange operations is as follows. The -compare-and-exchange operations will update \tcode{expected} when another iteration of -the loop is needed. -\begin{codeblock} -expected = current.load(); -do { - desired = function(expected); -} while (!current.compare_exchange_weak(expected, desired)); -\end{codeblock} -\end{example} -\begin{example} -Because the expected value is updated only on failure, -code releasing the memory containing the \tcode{expected} value on success will work. -For example, list head insertion will act atomically and would not introduce a -data race in the following code: -\begin{codeblock} -do { - p->next = head; // make new list node point to the current head -} while (!head.compare_exchange_weak(p->next, p)); // try to insert -\end{codeblock} -\end{example} - -\pnum -Implementations should ensure that weak compare-and-exchange operations do not -consistently return \tcode{false} unless either the atomic object has value -different from \tcode{expected} or there are concurrent modifications to the -atomic object. - -\pnum -\remarks -A weak compare-and-exchange operation may fail spuriously. That is, even when -the contents of memory referred to by \tcode{expected} and \keyword{this} are -equal, it may return \tcode{false} and store back to \tcode{expected} the same memory -contents that were originally there. -\begin{note} -This -spurious failure enables implementation of compare-and-exchange on a broader class of -machines, e.g., load-locked store-conditional machines. A -consequence of spurious failure is that nearly all uses of weak compare-and-exchange -will be in a loop. -When a compare-and-exchange is in a loop, the weak version will yield better performance -on some platforms. When a weak compare-and-exchange would require a loop and a strong one -would not, the strong one is preferable. -\end{note} - -\pnum -\begin{note} -Under cases where the \tcode{memcpy} and \tcode{memcmp} semantics of the compare-and-exchange -operations apply, the comparisons can fail for values that compare equal with -\tcode{operator==} if the value representation has trap bits or alternate -representations of the same value. Notably, on implementations conforming to -ISO/IEC/IEEE 60559, floating-point \tcode{-0.0} and \tcode{+0.0} -will not compare equal with \tcode{memcmp} but will compare equal with \tcode{operator==}, -and NaNs with the same payload will compare equal with \tcode{memcmp} but will not -compare equal with \tcode{operator==}. -\end{note} -\begin{note} -Because compare-and-exchange acts on an object's value representation, -padding bits that never participate in the object's value representation -are ignored. As a consequence, the following code is guaranteed to avoid -spurious failure: -\begin{codeblock} -struct padded { - char clank = 0x42; - // Padding here. - unsigned biff = 0xC0DEFEFE; -}; -atomic pad = {}; - -bool zap() { - padded expected, desired{0, 0}; - return pad.compare_exchange_strong(expected, desired); -} -\end{codeblock} -\end{note} -\begin{note} -For a union with bits that participate in the value representation -of some members but not others, compare-and-exchange might always fail. -This is because such padding bits have an indeterminate value when they -do not participate in the value representation of the active member. -As a consequence, the following code is not guaranteed to ever succeed: -\begin{codeblock} -union pony { - double celestia = 0.; - short luna; // padded -}; -atomic princesses = {}; - -bool party(pony desired) { - pony expected; - return princesses.compare_exchange_strong(expected, desired); -} -\end{codeblock} -\end{note} -\end{itemdescr} - -\indexlibrarymember{wait}{atomic}% -\indexlibrarymember{wait}{atomic}% -\indexlibrarymember{wait}{atomic<\placeholder{integral}>}% -\indexlibrarymember{wait}{atomic<\placeholder{floating-point}>}% -\begin{itemdecl} -void wait(T old, memory_order order = memory_order::seq_cst) const volatile noexcept; -void wait(T old, memory_order order = memory_order::seq_cst) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{order} is neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. - -\pnum -\effects -Repeatedly performs the following steps, in order: -\begin{itemize} -\item - Evaluates \tcode{load(order)} and - compares its value representation for equality against that of \tcode{old}. -\item - If they compare unequal, returns. -\item - Blocks until it - is unblocked by an atomic notifying operation or is unblocked spuriously. -\end{itemize} - -\pnum -\remarks -This function is an atomic waiting operation\iref{atomics.wait}. -\end{itemdescr} - -\indexlibrarymember{notify_one}{atomic}% -\indexlibrarymember{notify_one}{atomic}% -\indexlibrarymember{notify_one}{atomic<\placeholder{integral}>}% -\indexlibrarymember{notify_one}{atomic<\placeholder{floating-point}>}% -\begin{itemdecl} -void notify_one() volatile noexcept; -void notify_one() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Unblocks the execution of at least one atomic waiting operation -that is eligible to be unblocked\iref{atomics.wait} by this call, -if any such atomic waiting operations exist. - -\pnum -\remarks -This function is an atomic notifying operation\iref{atomics.wait}. -\end{itemdescr} - -\indexlibrarymember{notify_all}{atomic}% -\indexlibrarymember{notify_all}{atomic}% -\indexlibrarymember{notify_all}{atomic<\placeholder{integral}>}% -\indexlibrarymember{notify_all}{atomic<\placeholder{floating-point}>}% -\begin{itemdecl} -void notify_all() volatile noexcept; -void notify_all() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Unblocks the execution of all atomic waiting operations -that are eligible to be unblocked\iref{atomics.wait} by this call. - -\pnum -\remarks -This function is an atomic notifying operation\iref{atomics.wait}. -\end{itemdescr} - -\rSec2[atomics.types.int]{Specializations for integers} - -\indexlibrary{\idxcode{atomic<\placeholder{integral}>}}% -\pnum -There are specializations of the \tcode{atomic} -class template for the integral types -\tcode{char}, -\tcode{signed char}, -\tcode{unsigned char}, -\tcode{short}, -\tcode{unsigned short}, -\tcode{int}, -\tcode{unsigned int}, -\tcode{long}, -\tcode{unsigned long}, -\tcode{long long}, -\tcode{unsigned long long}, -\keyword{char8_t}, -\keyword{char16_t}, -\keyword{char32_t}, -\keyword{wchar_t}, -and any other types needed by the typedefs in the header \libheaderref{cstdint}. -For each such type \tcode{\placeholder{integral}}, the specialization -\tcode{atomic<\placeholder{integral}>} provides additional atomic operations appropriate to integral types. -\begin{note} -The specialization \tcode{atomic} -uses the primary template\iref{atomics.types.generic}. -\end{note} - -\begin{codeblock} -namespace std { - template<> struct atomic<@\placeholder{integral}@> { - using value_type = @\placeholder{integral}@; - using difference_type = value_type; - - static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; - bool is_lock_free() const volatile noexcept; - bool is_lock_free() const noexcept; - - constexpr atomic() noexcept; - constexpr atomic(@\placeholdernc{integral}@) noexcept; - atomic(const atomic&) = delete; - atomic& operator=(const atomic&) = delete; - atomic& operator=(const atomic&) volatile = delete; - - void store(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) volatile noexcept; - void store(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) noexcept; - @\placeholdernc{integral}@ operator=(@\placeholdernc{integral}@) volatile noexcept; - @\placeholdernc{integral}@ operator=(@\placeholdernc{integral}@) noexcept; - @\placeholdernc{integral}@ load(memory_order = memory_order::seq_cst) const volatile noexcept; - @\placeholdernc{integral}@ load(memory_order = memory_order::seq_cst) const noexcept; - operator @\placeholdernc{integral}@() const volatile noexcept; - operator @\placeholdernc{integral}@() const noexcept; - - @\placeholdernc{integral}@ exchange(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) volatile noexcept; - @\placeholdernc{integral}@ exchange(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) noexcept; - bool compare_exchange_weak(@\placeholder{integral}@&, @\placeholdernc{integral}@, - memory_order, memory_order) volatile noexcept; - bool compare_exchange_weak(@\placeholder{integral}@&, @\placeholdernc{integral}@, - memory_order, memory_order) noexcept; - bool compare_exchange_strong(@\placeholder{integral}@&, @\placeholdernc{integral}@, - memory_order, memory_order) volatile noexcept; - bool compare_exchange_strong(@\placeholder{integral}@&, @\placeholdernc{integral}@, - memory_order, memory_order) noexcept; - bool compare_exchange_weak(@\placeholder{integral}@&, @\placeholdernc{integral}@, - memory_order = memory_order::seq_cst) volatile noexcept; - bool compare_exchange_weak(@\placeholder{integral}@&, @\placeholdernc{integral}@, - memory_order = memory_order::seq_cst) noexcept; - bool compare_exchange_strong(@\placeholder{integral}@&, @\placeholdernc{integral}@, - memory_order = memory_order::seq_cst) volatile noexcept; - bool compare_exchange_strong(@\placeholder{integral}@&, @\placeholdernc{integral}@, - memory_order = memory_order::seq_cst) noexcept; - - @\placeholdernc{integral}@ fetch_add(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) volatile noexcept; - @\placeholdernc{integral}@ fetch_add(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) noexcept; - @\placeholdernc{integral}@ fetch_sub(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) volatile noexcept; - @\placeholdernc{integral}@ fetch_sub(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) noexcept; - @\placeholdernc{integral}@ fetch_and(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) volatile noexcept; - @\placeholdernc{integral}@ fetch_and(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) noexcept; - @\placeholdernc{integral}@ fetch_or(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) volatile noexcept; - @\placeholdernc{integral}@ fetch_or(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) noexcept; - @\placeholdernc{integral}@ fetch_xor(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) volatile noexcept; - @\placeholdernc{integral}@ fetch_xor(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) noexcept; - - @\placeholdernc{integral}@ operator++(int) volatile noexcept; - @\placeholdernc{integral}@ operator++(int) noexcept; - @\placeholdernc{integral}@ operator--(int) volatile noexcept; - @\placeholdernc{integral}@ operator--(int) noexcept; - @\placeholdernc{integral}@ operator++() volatile noexcept; - @\placeholdernc{integral}@ operator++() noexcept; - @\placeholdernc{integral}@ operator--() volatile noexcept; - @\placeholdernc{integral}@ operator--() noexcept; - @\placeholdernc{integral}@ operator+=(@\placeholdernc{integral}@) volatile noexcept; - @\placeholdernc{integral}@ operator+=(@\placeholdernc{integral}@) noexcept; - @\placeholdernc{integral}@ operator-=(@\placeholdernc{integral}@) volatile noexcept; - @\placeholdernc{integral}@ operator-=(@\placeholdernc{integral}@) noexcept; - @\placeholdernc{integral}@ operator&=(@\placeholdernc{integral}@) volatile noexcept; - @\placeholdernc{integral}@ operator&=(@\placeholdernc{integral}@) noexcept; - @\placeholdernc{integral}@ operator|=(@\placeholdernc{integral}@) volatile noexcept; - @\placeholdernc{integral}@ operator|=(@\placeholdernc{integral}@) noexcept; - @\placeholdernc{integral}@ operator^=(@\placeholdernc{integral}@) volatile noexcept; - @\placeholdernc{integral}@ operator^=(@\placeholdernc{integral}@) noexcept; - - void wait(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) const volatile noexcept; - void wait(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) const noexcept; - void notify_one() volatile noexcept; - void notify_one() noexcept; - void notify_all() volatile noexcept; - void notify_all() noexcept; - }; -} -\end{codeblock} - -\pnum -The atomic integral specializations -are standard-layout structs. -They each have -a trivial destructor. - -\pnum -Descriptions are provided below only for members that differ from the primary template. - -\pnum -The following operations perform arithmetic computations. -The correspondence among key, operator, and computation is specified -in \tref{atomic.types.int.comp}. - -\begin{floattable} -{Atomic arithmetic computations}{atomic.types.int.comp}{lll|lll} -\hline -\hdstyle{\tcode{\placeholder{key}}} & - \hdstyle{Op} & - \hdstyle{Computation} & -\hdstyle{\tcode{\placeholder{key}}} & - \hdstyle{Op} & - \hdstyle{Computation} \\ \hline -\tcode{add} & - \tcode{+} & - addition & -\tcode{sub} & - \tcode{-} & - subtraction \\ -\tcode{or} & - \tcode{|} & - bitwise inclusive or & -\tcode{xor} & - \tcode{\caret} & - bitwise exclusive or \\ -\tcode{and} & - \tcode{\&} & - bitwise and &&&\\ -\end{floattable} - -\indexlibraryglobal{atomic_fetch_add}% -\indexlibraryglobal{atomic_fetch_and}% -\indexlibraryglobal{atomic_fetch_or}% -\indexlibraryglobal{atomic_fetch_sub}% -\indexlibraryglobal{atomic_fetch_xor}% -\indexlibraryglobal{atomic_fetch_add_explicit}% -\indexlibraryglobal{atomic_fetch_and_explicit}% -\indexlibraryglobal{atomic_fetch_or_explicit}% -\indexlibraryglobal{atomic_fetch_sub_explicit}% -\indexlibraryglobal{atomic_fetch_xor_explicit}% -\indexlibrarymember{fetch_add}{atomic<\placeholder{integral}>}% -\indexlibrarymember{fetch_and}{atomic<\placeholder{integral}>}% -\indexlibrarymember{fetch_or}{atomic<\placeholder{integral}>}% -\indexlibrarymember{fetch_sub}{atomic<\placeholder{integral}>}% -\indexlibrarymember{fetch_xor}{atomic<\placeholder{integral}>}% -\begin{itemdecl} -T fetch_@\placeholdernc{key}@(T operand, memory_order order = memory_order::seq_cst) volatile noexcept; -T fetch_@\placeholdernc{key}@(T operand, memory_order order = memory_order::seq_cst) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -For the \tcode{volatile} overload of this function, -\tcode{is_always_lock_free} is \tcode{true}. - -\pnum -\effects -Atomically replaces the value pointed to by -\keyword{this} with the result of the computation applied to the -value pointed to by \keyword{this} and the given \tcode{operand}. -Memory is affected according to the value of \tcode{order}. -These operations are atomic read-modify-write operations\iref{intro.multithread}. - -\pnum -\returns -Atomically, the value pointed to by \keyword{this} immediately before the effects. - -\pnum -\indextext{signed integer representation!two's complement}% -\remarks -For signed integer types, -the result is as if the object value and parameters -were converted to their corresponding unsigned types, -the computation performed on those types, and -the result converted back to the signed type. -\begin{note} -There are no undefined results arising from the computation. -\end{note} - -\end{itemdescr} - -\indexlibrarymember{operator+=}{atomic}% -\indexlibrarymember{operator-=}{atomic}% -\indexlibrarymember{operator+=}{atomic<\placeholder{integral}>}% -\indexlibrarymember{operator-=}{atomic<\placeholder{integral}>}% -\indexlibrarymember{operator\&=}{atomic<\placeholder{integral}>}% -\indexlibrarymember{operator"|=}{atomic<\placeholder{integral}>}% -\indexlibrarymember{operator\caret=}{atomic<\placeholder{integral}>}% -\begin{itemdecl} -T operator @\placeholder{op}@=(T operand) volatile noexcept; -T operator @\placeholder{op}@=(T operand) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -For the \tcode{volatile} overload of this function, -\tcode{is_always_lock_free} is \tcode{true}. - -\pnum -\effects -Equivalent to: \tcode{return fetch_\placeholder{key}(operand) \placeholder{op} operand;} -\end{itemdescr} - -\rSec2[atomics.types.float]{Specializations for floating-point types} - -\indexlibrary{\idxcode{atomic<\placeholder{floating-point}>}}% -\pnum -There are specializations of the \tcode{atomic} -class template for the floating-point types -\tcode{float}, -\tcode{double}, and -\tcode{long double}. -For each such type \tcode{\placeholdernc{floating-point}}, -the specialization \tcode{atomic<\placeholder{floating-point}>} -provides additional atomic operations appropriate to floating-point types. - -\begin{codeblock} -namespace std { - template<> struct atomic<@\placeholder{floating-point}@> { - using value_type = @\placeholdernc{floating-point}@; - using difference_type = value_type; - - static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; - bool is_lock_free() const volatile noexcept; - bool is_lock_free() const noexcept; - - constexpr atomic() noexcept; - constexpr atomic(@\placeholder{floating-point}@) noexcept; - atomic(const atomic&) = delete; - atomic& operator=(const atomic&) = delete; - atomic& operator=(const atomic&) volatile = delete; - - void store(@\placeholdernc{floating-point}@, memory_order = memory_order::seq_cst) volatile noexcept; - void store(@\placeholdernc{floating-point}@, memory_order = memory_order::seq_cst) noexcept; - @\placeholdernc{floating-point}@ operator=(@\placeholder{floating-point}@) volatile noexcept; - @\placeholdernc{floating-point}@ operator=(@\placeholder{floating-point}@) noexcept; - @\placeholdernc{floating-point}@ load(memory_order = memory_order::seq_cst) volatile noexcept; - @\placeholdernc{floating-point}@ load(memory_order = memory_order::seq_cst) noexcept; - operator @\placeholdernc{floating-point}@() volatile noexcept; - operator @\placeholdernc{floating-point}@() noexcept; - - @\placeholdernc{floating-point}@ exchange(@\placeholdernc{floating-point}@, - memory_order = memory_order::seq_cst) volatile noexcept; - @\placeholdernc{floating-point}@ exchange(@\placeholdernc{floating-point}@, - memory_order = memory_order::seq_cst) noexcept; - bool compare_exchange_weak(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, - memory_order, memory_order) volatile noexcept; - bool compare_exchange_weak(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, - memory_order, memory_order) noexcept; - bool compare_exchange_strong(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, - memory_order, memory_order) volatile noexcept; - bool compare_exchange_strong(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, - memory_order, memory_order) noexcept; - bool compare_exchange_weak(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, - memory_order = memory_order::seq_cst) volatile noexcept; - bool compare_exchange_weak(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, - memory_order = memory_order::seq_cst) noexcept; - bool compare_exchange_strong(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, - memory_order = memory_order::seq_cst) volatile noexcept; - bool compare_exchange_strong(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, - memory_order = memory_order::seq_cst) noexcept; - - @\placeholdernc{floating-point}@ fetch_add(@\placeholdernc{floating-point}@, - memory_order = memory_order::seq_cst) volatile noexcept; - @\placeholdernc{floating-point}@ fetch_add(@\placeholdernc{floating-point}@, - memory_order = memory_order::seq_cst) noexcept; - @\placeholdernc{floating-point}@ fetch_sub(@\placeholdernc{floating-point}@, - memory_order = memory_order::seq_cst) volatile noexcept; - @\placeholdernc{floating-point}@ fetch_sub(@\placeholdernc{floating-point}@, - memory_order = memory_order::seq_cst) noexcept; - - @\placeholdernc{floating-point}@ operator+=(@\placeholder{floating-point}@) volatile noexcept; - @\placeholdernc{floating-point}@ operator+=(@\placeholder{floating-point}@) noexcept; - @\placeholdernc{floating-point}@ operator-=(@\placeholder{floating-point}@) volatile noexcept; - @\placeholdernc{floating-point}@ operator-=(@\placeholder{floating-point}@) noexcept; - - void wait(@\placeholdernc{floating-point}@, memory_order = memory_order::seq_cst) const volatile noexcept; - void wait(@\placeholdernc{floating-point}@, memory_order = memory_order::seq_cst) const noexcept; - void notify_one() volatile noexcept; - void notify_one() noexcept; - void notify_all() volatile noexcept; - void notify_all() noexcept; - }; -} -\end{codeblock} - -\pnum -The atomic floating-point specializations -are standard-layout structs. -They each have -a trivial destructor. - -\pnum -Descriptions are provided below only for members that differ from the primary template. - -\pnum -The following operations perform arithmetic addition and subtraction computations. -The correspondence among key, operator, and computation is specified -in \tref{atomic.types.int.comp}. - -\indexlibraryglobal{atomic_fetch_add}% -\indexlibraryglobal{atomic_fetch_sub}% -\indexlibraryglobal{atomic_fetch_add_explicit}% -\indexlibraryglobal{atomic_fetch_sub_explicit}% -\indexlibrarymember{fetch_add}{atomic<\placeholder{floating-point}>}% -\indexlibrarymember{fetch_sub}{atomic<\placeholder{floating-point}>}% -\begin{itemdecl} -T fetch_@\placeholdernc{key}@(T operand, memory_order order = memory_order::seq_cst) volatile noexcept; -T fetch_@\placeholdernc{key}@(T operand, memory_order order = memory_order::seq_cst) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -For the \tcode{volatile} overload of this function, -\tcode{is_always_lock_free} is \tcode{true}. - -\pnum -\effects -Atomically replaces the value pointed to by \keyword{this} -with the result of the computation applied to the value pointed -to by \keyword{this} and the given \tcode{operand}. -Memory is affected according to the value of \tcode{order}. -These operations are atomic read-modify-write operations\iref{intro.multithread}. - -\pnum -\returns -Atomically, the value pointed to by \keyword{this} immediately before the effects. - -\pnum -\remarks -If the result is not a representable value for its type\iref{expr.pre} -the result is unspecified, but the operations otherwise have no undefined -behavior. Atomic arithmetic operations on \tcode{\placeholder{floating-point}} -should conform to the \tcode{std::numeric_limits<\placeholder{floating-point}>} -traits associated with the floating-point type\iref{limits.syn}. -The floating-point environment\iref{cfenv} for atomic arithmetic operations -on \tcode{\placeholder{floating-point}} may be different than the -calling thread's floating-point environment. -\end{itemdescr} - -\indexlibrarymember{operator+=}{atomic}% -\indexlibrarymember{operator-=}{atomic}% -\indexlibrarymember{operator+=}{atomic<\placeholder{floating-point}>}% -\indexlibrarymember{operator-=}{atomic<\placeholder{floating-point}>}% -\begin{itemdecl} -T operator @\placeholder{op}@=(T operand) volatile noexcept; -T operator @\placeholder{op}@=(T operand) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -For the \tcode{volatile} overload of this function, -\tcode{is_always_lock_free} is \tcode{true}. - -\pnum -\effects -Equivalent to: \tcode{return fetch_\placeholder{key}(operand) \placeholder{op} operand;} - -\pnum -\remarks -If the result is not a representable value for its type\iref{expr.pre} -the result is unspecified, but the operations otherwise have no undefined -behavior. Atomic arithmetic operations on \tcode{\placeholder{floating-point}} -should conform to the \tcode{std::numeric_limits<\placeholder{floating-point}>} -traits associated with the floating-point type\iref{limits.syn}. -The floating-point environment\iref{cfenv} for atomic arithmetic operations -on \tcode{\placeholder{floating-point}} may be different than the -calling thread's floating-point environment. -\end{itemdescr} - -\rSec2[atomics.types.pointer]{Partial specialization for pointers} -\indexlibraryglobal{atomic}% - -\begin{codeblock} -namespace std { - template struct atomic { - using value_type = T*; - using difference_type = ptrdiff_t; - - static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; - bool is_lock_free() const volatile noexcept; - bool is_lock_free() const noexcept; - - constexpr atomic() noexcept; - constexpr atomic(T*) noexcept; - atomic(const atomic&) = delete; - atomic& operator=(const atomic&) = delete; - atomic& operator=(const atomic&) volatile = delete; - - void store(T*, memory_order = memory_order::seq_cst) volatile noexcept; - void store(T*, memory_order = memory_order::seq_cst) noexcept; - T* operator=(T*) volatile noexcept; - T* operator=(T*) noexcept; - T* load(memory_order = memory_order::seq_cst) const volatile noexcept; - T* load(memory_order = memory_order::seq_cst) const noexcept; - operator T*() const volatile noexcept; - operator T*() const noexcept; - - T* exchange(T*, memory_order = memory_order::seq_cst) volatile noexcept; - T* exchange(T*, memory_order = memory_order::seq_cst) noexcept; - bool compare_exchange_weak(T*&, T*, memory_order, memory_order) volatile noexcept; - bool compare_exchange_weak(T*&, T*, memory_order, memory_order) noexcept; - bool compare_exchange_strong(T*&, T*, memory_order, memory_order) volatile noexcept; - bool compare_exchange_strong(T*&, T*, memory_order, memory_order) noexcept; - bool compare_exchange_weak(T*&, T*, - memory_order = memory_order::seq_cst) volatile noexcept; - bool compare_exchange_weak(T*&, T*, - memory_order = memory_order::seq_cst) noexcept; - bool compare_exchange_strong(T*&, T*, - memory_order = memory_order::seq_cst) volatile noexcept; - bool compare_exchange_strong(T*&, T*, - memory_order = memory_order::seq_cst) noexcept; - - T* fetch_add(ptrdiff_t, memory_order = memory_order::seq_cst) volatile noexcept; - T* fetch_add(ptrdiff_t, memory_order = memory_order::seq_cst) noexcept; - T* fetch_sub(ptrdiff_t, memory_order = memory_order::seq_cst) volatile noexcept; - T* fetch_sub(ptrdiff_t, memory_order = memory_order::seq_cst) noexcept; - - T* operator++(int) volatile noexcept; - T* operator++(int) noexcept; - T* operator--(int) volatile noexcept; - T* operator--(int) noexcept; - T* operator++() volatile noexcept; - T* operator++() noexcept; - T* operator--() volatile noexcept; - T* operator--() noexcept; - T* operator+=(ptrdiff_t) volatile noexcept; - T* operator+=(ptrdiff_t) noexcept; - T* operator-=(ptrdiff_t) volatile noexcept; - T* operator-=(ptrdiff_t) noexcept; - - void wait(T*, memory_order = memory_order::seq_cst) const volatile noexcept; - void wait(T*, memory_order = memory_order::seq_cst) const noexcept; - void notify_one() volatile noexcept; - void notify_one() noexcept; - void notify_all() volatile noexcept; - void notify_all() noexcept; - }; -} -\end{codeblock} - -\indexlibraryglobal{atomic}% -\pnum -There is a partial specialization of the \tcode{atomic} class template for pointers. -Specializations of this partial specialization are standard-layout structs. -They each have a trivial destructor. - -\pnum -Descriptions are provided below only for members that differ from the primary template. - -\pnum -The following operations perform pointer arithmetic. -The correspondence among key, operator, and computation is specified -in \tref{atomic.types.pointer.comp}. - -\begin{floattable} -{Atomic pointer computations}{atomic.types.pointer.comp}{lll|lll} -\hline -\hdstyle{\tcode{\placeholder{key}}} & - \hdstyle{Op} & - \hdstyle{Computation} & -\hdstyle{\tcode{\placeholder{key}}} & - \hdstyle{Op} & - \hdstyle{Computation} \\ \hline -\tcode{add} & - \tcode{+} & - addition & -\tcode{sub} & - \tcode{-} & - subtraction \\ -\end{floattable} - -\indexlibraryglobal{atomic_fetch_add}% -\indexlibraryglobal{atomic_fetch_sub}% -\indexlibraryglobal{atomic_fetch_add_explicit}% -\indexlibraryglobal{atomic_fetch_sub_explicit}% -\indexlibrarymember{fetch_add}{atomic}% -\indexlibrarymember{fetch_sub}{atomic}% -\begin{itemdecl} -T* fetch_@\placeholdernc{key}@(ptrdiff_t operand, memory_order order = memory_order::seq_cst) volatile noexcept; -T* fetch_@\placeholdernc{key}@(ptrdiff_t operand, memory_order order = memory_order::seq_cst) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -For the \tcode{volatile} overload of this function, -\tcode{is_always_lock_free} is \tcode{true}. - -\pnum -\mandates -\tcode{T} is a complete object type. -\begin{note} -Pointer arithmetic on \tcode{void*} or function pointers is ill-formed. -\end{note} - -\pnum -\effects -Atomically replaces the value pointed to by -\keyword{this} with the result of the computation applied to the -value pointed to by \keyword{this} and the given \tcode{operand}. -Memory is affected according to the value of \tcode{order}. -These operations are atomic read-modify-write operations\iref{intro.multithread}. - -\pnum -\returns -Atomically, the value pointed to by \keyword{this} immediately before the effects. - -\pnum -\remarks -The result may be an undefined address, -but the operations otherwise have no undefined behavior. -\end{itemdescr} - -\indexlibrarymember{operator+=}{atomic}% -\indexlibrarymember{operator-=}{atomic}% -\begin{itemdecl} -T* operator @\placeholder{op}@=(ptrdiff_t operand) volatile noexcept; -T* operator @\placeholder{op}@=(ptrdiff_t operand) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -For the \tcode{volatile} overload of this function, -\tcode{is_always_lock_free} is \tcode{true}. - -\pnum -\effects -Equivalent to: \tcode{return fetch_\placeholder{key}(operand) \placeholder{op} operand;} -\end{itemdescr} - -\rSec2[atomics.types.memop]{Member operators common to integers and pointers to objects} - -\indexlibrarymember{operator++}{atomic}% -\indexlibrarymember{operator++}{atomic<\placeholder{integral}>}% -\begin{itemdecl} -value_type operator++(int) volatile noexcept; -value_type operator++(int) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -For the \tcode{volatile} overload of this function, -\tcode{is_always_lock_free} is \tcode{true}. - -\pnum -\effects -Equivalent to: \tcode{return fetch_add(1);} -\end{itemdescr} - -\indexlibrarymember{operator--}{atomic}% -\indexlibrarymember{operator--}{atomic<\placeholder{integral}>}% -\begin{itemdecl} -value_type operator--(int) volatile noexcept; -value_type operator--(int) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -For the \tcode{volatile} overload of this function, -\tcode{is_always_lock_free} is \tcode{true}. - -\pnum -\effects -Equivalent to: \tcode{return fetch_sub(1);} -\end{itemdescr} - -\indexlibrarymember{operator++}{atomic}% -\indexlibrarymember{operator++}{atomic<\placeholder{integral}>}% -\begin{itemdecl} -value_type operator++() volatile noexcept; -value_type operator++() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -For the \tcode{volatile} overload of this function, -\tcode{is_always_lock_free} is \tcode{true}. - -\pnum -\effects -Equivalent to: \tcode{return fetch_add(1) + 1;} -\end{itemdescr} - -\indexlibrarymember{operator--}{atomic}% -\indexlibrarymember{operator--}{atomic<\placeholder{integral}>}% -\begin{itemdecl} -value_type operator--() volatile noexcept; -value_type operator--() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -For the \tcode{volatile} overload of this function, -\tcode{is_always_lock_free} is \tcode{true}. - -\pnum -\effects -Equivalent to: \tcode{return fetch_sub(1) - 1;} -\end{itemdescr} - -\rSec2[util.smartptr.atomic]{Partial specializations for smart pointers}% -\indextext{atomic!smart pointers|(}% - -\rSec3[util.smartptr.atomic.general]{General} - -\pnum -The library provides partial specializations of the \tcode{atomic} template -for shared-ownership smart pointers\iref{util.sharedptr}. -\begin{note} -The partial specializations are declared in header \libheaderref{memory}. -\end{note} -The behavior of all operations is as specified in \ref{atomics.types.generic}, -unless specified otherwise. -The template parameter \tcode{T} of these partial specializations -may be an incomplete type. - -\pnum -All changes to an atomic smart pointer in \ref{util.smartptr.atomic}, and -all associated \tcode{use_count} increments, -are guaranteed to be performed atomically. -Associated \tcode{use_count} decrements -are sequenced after the atomic operation, -but are not required to be part of it. -Any associated deletion and deallocation -are sequenced after the atomic update step and -are not part of the atomic operation. -\begin{note} -If the atomic operation uses locks, -locks acquired by the implementation -will be held when any \tcode{use_count} adjustments are performed, and -will not be held when any destruction or deallocation -resulting from this is performed. -\end{note} - -\pnum -\begin{example} -\begin{codeblock} -template class atomic_list { - struct node { - T t; - shared_ptr next; - }; - atomic> head; - -public: - auto find(T t) const { - auto p = head.load(); - while (p && p->t != t) - p = p->next; - - return shared_ptr(move(p)); - } - - void push_front(T t) { - auto p = make_shared(); - p->t = t; - p->next = head; - while (!head.compare_exchange_weak(p->next, p)) {} - } -}; -\end{codeblock} -\end{example} - -\rSec3[util.smartptr.atomic.shared]{Partial specialization for \tcode{shared_ptr}} -\indexlibraryglobal{atomic>}% -\begin{codeblock} -namespace std { - template struct atomic> { - using value_type = shared_ptr; - - static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; - bool is_lock_free() const noexcept; - - constexpr atomic() noexcept; - constexpr atomic(nullptr_t) noexcept : atomic() { } - atomic(shared_ptr desired) noexcept; - atomic(const atomic&) = delete; - void operator=(const atomic&) = delete; - - shared_ptr load(memory_order order = memory_order::seq_cst) const noexcept; - operator shared_ptr() const noexcept; - void store(shared_ptr desired, memory_order order = memory_order::seq_cst) noexcept; - void operator=(shared_ptr desired) noexcept; - - shared_ptr exchange(shared_ptr desired, - memory_order order = memory_order::seq_cst) noexcept; - bool compare_exchange_weak(shared_ptr& expected, shared_ptr desired, - memory_order success, memory_order failure) noexcept; - bool compare_exchange_strong(shared_ptr& expected, shared_ptr desired, - memory_order success, memory_order failure) noexcept; - bool compare_exchange_weak(shared_ptr& expected, shared_ptr desired, - memory_order order = memory_order::seq_cst) noexcept; - bool compare_exchange_strong(shared_ptr& expected, shared_ptr desired, - memory_order order = memory_order::seq_cst) noexcept; - - void wait(shared_ptr old, memory_order order = memory_order::seq_cst) const noexcept; - void notify_one() noexcept; - void notify_all() noexcept; - - private: - shared_ptr p; // \expos - }; -} -\end{codeblock} - -\indexlibraryctor{atomic>}% -\begin{itemdecl} -constexpr atomic() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \tcode{p\{\}}. -\end{itemdescr} - -\indexlibraryctor{atomic>}% -\begin{itemdecl} -atomic(shared_ptr desired) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes the object with the value \tcode{desired}. -Initialization is not an atomic operation\iref{intro.multithread}. -\begin{note} -It is possible to have an access to -an atomic object \tcode{A} race with its construction, -for example, -by communicating the address of the just-constructed object \tcode{A} -to another thread via \tcode{memory_order::relaxed} operations -on a suitable atomic pointer variable, and -then immediately accessing \tcode{A} in the receiving thread. -This results in undefined behavior. -\end{note} -\end{itemdescr} - -\indexlibrarymember{store}{atomic>}% -\begin{itemdecl} -void store(shared_ptr desired, memory_order order = memory_order::seq_cst) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{order} is neither -\tcode{memory_order::consume}, -\tcode{memory_order::acquire}, nor -\tcode{memory_order::acq_rel}. - -\pnum -\effects -Atomically replaces the value pointed to by \keyword{this} with -the value of \tcode{desired} as if by \tcode{p.swap(desired)}. -Memory is affected according to the value of \tcode{order}. -\end{itemdescr} - -\indexlibrarymember{operator=}{atomic>}% -\begin{itemdecl} -void operator=(shared_ptr desired) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to \tcode{store(desired)}. -\end{itemdescr} - -\indexlibrarymember{load}{atomic>}% -\begin{itemdecl} -shared_ptr load(memory_order order = memory_order::seq_cst) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{order} is neither -\tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. - -\pnum -\effects -Memory is affected according to the value of \tcode{order}. - -\pnum -\returns -Atomically returns \tcode{p}. -\end{itemdescr} - -\indexlibrarymember{operator shared_ptr}{atomic>}% -\begin{itemdecl} -operator shared_ptr() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return load();} -\end{itemdescr} - -\indexlibrarymember{exchange}{atomic>}% -\begin{itemdecl} -shared_ptr exchange(shared_ptr desired, memory_order order = memory_order::seq_cst) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Atomically replaces \tcode{p} with \tcode{desired} -as if by \tcode{p.swap(desired)}. -Memory is affected according to the value of \tcode{order}. -This is an atomic read-modify-write operation\iref{intro.races}. - -\pnum -\returns -Atomically returns the value of \tcode{p} immediately before the effects. -\end{itemdescr} - -\indexlibrarymember{compare_exchange_weak}{atomic>}% -\indexlibrarymember{compare_exchange_strong}{atomic>}% -\begin{itemdecl} -bool compare_exchange_weak(shared_ptr& expected, shared_ptr desired, - memory_order success, memory_order failure) noexcept; -bool compare_exchange_strong(shared_ptr& expected, shared_ptr desired, - memory_order success, memory_order failure) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{failure} is neither -\tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. - -\pnum -\effects -If \tcode{p} is equivalent to \tcode{expected}, -assigns \tcode{desired} to \tcode{p} and -has synchronization semantics corresponding to the value of \tcode{success}, -otherwise assigns \tcode{p} to \tcode{expected} and -has synchronization semantics corresponding to the value of \tcode{failure}. - -\pnum -\returns -\tcode{true} if \tcode{p} was equivalent to \tcode{expected}, -\tcode{false} otherwise. - -\pnum -\remarks -Two \tcode{shared_ptr} objects are equivalent if -they store the same pointer value and -either share ownership or are both empty. -The weak form may fail spuriously. See \ref{atomics.types.operations}. - -\pnum -If the operation returns \tcode{true}, -\tcode{expected} is not accessed after the atomic update and -the operation is an atomic read-modify-write operation\iref{intro.multithread} -on the memory pointed to by \keyword{this}. -Otherwise, the operation is an atomic load operation on that memory, and -\tcode{expected} is updated with the existing value -read from the atomic object in the attempted atomic update. -The \tcode{use_count} update corresponding to the write to \tcode{expected} -is part of the atomic operation. -The write to \tcode{expected} itself -is not required to be part of the atomic operation. -\end{itemdescr} - -\indexlibrarymember{compare_exchange_weak}{atomic>}% -\begin{itemdecl} -bool compare_exchange_weak(shared_ptr& expected, shared_ptr desired, - memory_order order = memory_order::seq_cst) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -return compare_exchange_weak(expected, desired, order, fail_order); -\end{codeblock} -where \tcode{fail_order} is the same as \tcode{order} -except that a value of \tcode{memory_order::acq_rel} -shall be replaced by the value \tcode{memory_order::acquire} and -a value of \tcode{memory_order::release} -shall be replaced by the value \tcode{memory_order::relaxed}. -\end{itemdescr} - -\indexlibrarymember{compare_exchange_strong}{atomic>}% -\begin{itemdecl} -bool compare_exchange_strong(shared_ptr& expected, shared_ptr desired, - memory_order order = memory_order::seq_cst) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -return compare_exchange_strong(expected, desired, order, fail_order); -\end{codeblock} -where \tcode{fail_order} is the same as \tcode{order} -except that a value of \tcode{memory_order::acq_rel} -shall be replaced by the value \tcode{memory_order::acquire} and -a value of \tcode{memory_order::release} -shall be replaced by the value \tcode{memory_order::relaxed}. -\end{itemdescr} - -\indexlibrarymember{wait}{atomic>}% -\begin{itemdecl} -void wait(shared_ptr old, memory_order order = memory_order::seq_cst) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{order} is -neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. - -\pnum -\effects -Repeatedly performs the following steps, in order: -\begin{itemize} -\item - Evaluates \tcode{load(order)} and compares it to \tcode{old}. -\item - If the two are not equivalent, returns. -\item - Blocks until it - is unblocked by an atomic notifying operation or is unblocked spuriously. -\end{itemize} - -\pnum -\remarks -Two \tcode{shared_ptr} objects are equivalent -if they store the same pointer and either share ownership or are both empty. -This function is an atomic waiting operation\iref{atomics.wait}. -\end{itemdescr} - -\indexlibrarymember{notify_one}{atomic>}% -\begin{itemdecl} -void notify_one() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Unblocks the execution of at least one atomic waiting operation -that is eligible to be unblocked\iref{atomics.wait} by this call, -if any such atomic waiting operations exist. - -\pnum -\remarks -This function is an atomic notifying operation\iref{atomics.wait}. -\end{itemdescr} - -\indexlibrarymember{notify_all}{atomic>}% -\begin{itemdecl} -void notify_all() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Unblocks the execution of all atomic waiting operations -that are eligible to be unblocked\iref{atomics.wait} by this call. - -\pnum -\remarks -This function is an atomic notifying operation\iref{atomics.wait}. -\end{itemdescr} - -\rSec3[util.smartptr.atomic.weak]{Partial specialization for \tcode{weak_ptr}} -\indexlibraryglobal{atomic>}% -\begin{codeblock} -namespace std { - template struct atomic> { - using value_type = weak_ptr; - - static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; - bool is_lock_free() const noexcept; - - constexpr atomic() noexcept; - atomic(weak_ptr desired) noexcept; - atomic(const atomic&) = delete; - void operator=(const atomic&) = delete; - - weak_ptr load(memory_order order = memory_order::seq_cst) const noexcept; - operator weak_ptr() const noexcept; - void store(weak_ptr desired, memory_order order = memory_order::seq_cst) noexcept; - void operator=(weak_ptr desired) noexcept; - - weak_ptr exchange(weak_ptr desired, - memory_order order = memory_order::seq_cst) noexcept; - bool compare_exchange_weak(weak_ptr& expected, weak_ptr desired, - memory_order success, memory_order failure) noexcept; - bool compare_exchange_strong(weak_ptr& expected, weak_ptr desired, - memory_order success, memory_order failure) noexcept; - bool compare_exchange_weak(weak_ptr& expected, weak_ptr desired, - memory_order order = memory_order::seq_cst) noexcept; - bool compare_exchange_strong(weak_ptr& expected, weak_ptr desired, - memory_order order = memory_order::seq_cst) noexcept; - - void wait(weak_ptr old, memory_order order = memory_order::seq_cst) const noexcept; - void notify_one() noexcept; - void notify_all() noexcept; - - private: - weak_ptr p; // \expos - }; -} -\end{codeblock} - -\indexlibraryctor{atomic>}% -\begin{itemdecl} -constexpr atomic() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \tcode{p\{\}}. -\end{itemdescr} - -\indexlibraryctor{atomic>}% -\begin{itemdecl} -atomic(weak_ptr desired) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes the object with the value \tcode{desired}. -Initialization is not an atomic operation\iref{intro.multithread}. -\begin{note} -It is possible to have an access to -an atomic object \tcode{A} race with its construction, -for example, -by communicating the address of the just-constructed object \tcode{A} -to another thread via \tcode{memory_order::relaxed} operations -on a suitable atomic pointer variable, and -then immediately accessing \tcode{A} in the receiving thread. -This results in undefined behavior. -\end{note} -\end{itemdescr} - -\indexlibrarymember{store}{atomic>}% -\begin{itemdecl} -void store(weak_ptr desired, memory_order order = memory_order::seq_cst) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{order} is neither -\tcode{memory_order::consume}, -\tcode{memory_order::acquire}, nor -\tcode{memory_order::acq_rel}. - -\pnum -\effects -Atomically replaces the value pointed to by \keyword{this} with -the value of \tcode{desired} as if by \tcode{p.swap(desired)}. -Memory is affected according to the value of \tcode{order}. -\end{itemdescr} - -\indexlibrarymember{operator=}{atomic>}% -\begin{itemdecl} -void operator=(weak_ptr desired) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to \tcode{store(desired)}. -\end{itemdescr} - -\indexlibrarymember{load}{atomic>}% -\begin{itemdecl} -weak_ptr load(memory_order order = memory_order::seq_cst) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{order} is neither -\tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. - -\pnum -\effects -Memory is affected according to the value of \tcode{order}. - -\pnum -\returns -Atomically returns \tcode{p}. -\end{itemdescr} - -\indexlibrarymember{operator weak_ptr}{atomic>}% -\begin{itemdecl} -operator weak_ptr() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return load();} -\end{itemdescr} - -\indexlibrarymember{exchange}{atomic>}% -\begin{itemdecl} -weak_ptr exchange(weak_ptr desired, memory_order order = memory_order::seq_cst) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Atomically replaces \tcode{p} with \tcode{desired} -as if by \tcode{p.swap(desired)}. -Memory is affected according to the value of \tcode{order}. -This is an atomic read-modify-write operation\iref{intro.races}. - -\pnum -\returns -Atomically returns the value of \tcode{p} immediately before the effects. -\end{itemdescr} - -\indexlibrarymember{compare_exchange_weak}{atomic>}% -\begin{itemdecl} -bool compare_exchange_weak(weak_ptr& expected, weak_ptr desired, - memory_order success, memory_order failure) noexcept; -bool compare_exchange_strong(weak_ptr& expected, weak_ptr desired, - memory_order success, memory_order failure) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{failure} is neither -\tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. - -\pnum -\effects -If \tcode{p} is equivalent to \tcode{expected}, -assigns \tcode{desired} to \tcode{p} and -has synchronization semantics corresponding to the value of \tcode{success}, -otherwise assigns \tcode{p} to \tcode{expected} and -has synchronization semantics corresponding to the value of \tcode{failure}. - -\pnum -\returns -\tcode{true} if \tcode{p} was equivalent to \tcode{expected}, -\tcode{false} otherwise. - -\pnum -\remarks -Two \tcode{weak_ptr} objects are equivalent if -they store the same pointer value and -either share ownership or are both empty. -The weak form may fail spuriously. See \ref{atomics.types.operations}. - -\pnum -If the operation returns \tcode{true}, -\tcode{expected} is not accessed after the atomic update and -the operation is an atomic read-modify-write operation\iref{intro.multithread} -on the memory pointed to by \keyword{this}. -Otherwise, the operation is an atomic load operation on that memory, and -\tcode{expected} is updated with the existing value -read from the atomic object in the attempted atomic update. -The \tcode{use_count} update corresponding to the write to \tcode{expected} -is part of the atomic operation. -The write to \tcode{expected} itself -is not required to be part of the atomic operation. -\end{itemdescr} - -\indexlibrarymember{compare_exchange_weak}{atomic>}% -\begin{itemdecl} -bool compare_exchange_weak(weak_ptr& expected, weak_ptr desired, - memory_order order = memory_order::seq_cst) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -return compare_exchange_weak(expected, desired, order, fail_order); -\end{codeblock} -where \tcode{fail_order} is the same as \tcode{order} -except that a value of \tcode{memory_order::acq_rel} -shall be replaced by the value \tcode{memory_order::acquire} and -a value of \tcode{memory_order::release} -shall be replaced by the value \tcode{memory_order::relaxed}. -\end{itemdescr} - -\indexlibrarymember{compare_exchange_strong}{atomic>}% -\begin{itemdecl} -bool compare_exchange_strong(weak_ptr& expected, weak_ptr desired, - memory_order order = memory_order::seq_cst) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -return compare_exchange_strong(expected, desired, order, fail_order); -\end{codeblock} -where \tcode{fail_order} is the same as \tcode{order} -except that a value of \tcode{memory_order::acq_rel} -shall be replaced by the value \tcode{memory_order::acquire} and -a value of \tcode{memory_order::release} -shall be replaced by the value \tcode{memory_order::relaxed}. -\end{itemdescr} - -\indexlibrarymember{wait}{atomic>}% -\begin{itemdecl} -void wait(weak_ptr old, memory_order order = memory_order::seq_cst) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{order} is -neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. - -\pnum -\effects -Repeatedly performs the following steps, in order: -\begin{itemize} -\item - Evaluates \tcode{load(order)} and compares it to \tcode{old}. -\item - If the two are not equivalent, returns. -\item - Blocks until it - is unblocked by an atomic notifying operation or is unblocked spuriously. -\end{itemize} - -\pnum -\remarks -Two \tcode{weak_ptr} objects are equivalent -if they store the same pointer and either share ownership or are both empty. -This function is an atomic waiting operation\iref{atomics.wait}. -\end{itemdescr} - - -\indexlibrarymember{notify_one}{atomic>}% -\begin{itemdecl} -void notify_one() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Unblocks the execution of at least one atomic waiting operation -that is eligible to be unblocked\iref{atomics.wait} by this call, -if any such atomic waiting operations exist. - -\pnum -\remarks -This function is an atomic notifying operation\iref{atomics.wait}. -\end{itemdescr} - -\indexlibrarymember{notify_all}{atomic>}% -\begin{itemdecl} -void notify_all() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Unblocks the execution of all atomic waiting operations -that are eligible to be unblocked\iref{atomics.wait} by this call. - -\pnum -\remarks -This function is an atomic notifying operation\iref{atomics.wait}. -\end{itemdescr} -\indextext{atomic!smart pointers|)} - -\rSec1[atomics.nonmembers]{Non-member functions} - -\pnum -A non-member function template whose name matches the pattern -\tcode{atomic_\placeholder{f}} or the pattern \tcode{atomic_\placeholder{f}_explicit} -invokes the member function \tcode{\placeholder{f}}, with the value of the -first parameter as the object expression and the values of the remaining parameters -(if any) as the arguments of the member function call, in order. An argument -for a parameter of type \tcode{atomic::value_type*} is dereferenced when -passed to the member function call. -If no such member function exists, the program is ill-formed. - -\pnum -\begin{note} -The non-member functions enable programmers to write code that can be -compiled as either C or \Cpp{}, for example in a shared header file. -\end{note} - -\rSec1[atomics.flag]{Flag type and operations} - -\begin{codeblock} -namespace std { - struct atomic_flag { - constexpr atomic_flag() noexcept; - atomic_flag(const atomic_flag&) = delete; - atomic_flag& operator=(const atomic_flag&) = delete; - atomic_flag& operator=(const atomic_flag&) volatile = delete; - - bool test(memory_order = memory_order::seq_cst) const volatile noexcept; - bool test(memory_order = memory_order::seq_cst) const noexcept; - bool test_and_set(memory_order = memory_order::seq_cst) volatile noexcept; - bool test_and_set(memory_order = memory_order::seq_cst) noexcept; - void clear(memory_order = memory_order::seq_cst) volatile noexcept; - void clear(memory_order = memory_order::seq_cst) noexcept; - - void wait(bool, memory_order = memory_order::seq_cst) const volatile noexcept; - void wait(bool, memory_order = memory_order::seq_cst) const noexcept; - void notify_one() volatile noexcept; - void notify_one() noexcept; - void notify_all() volatile noexcept; - void notify_all() noexcept; - }; -} -\end{codeblock} - -\pnum -The \tcode{atomic_flag} type provides the classic test-and-set functionality. It has two states, set and clear. - -\pnum -Operations on an object of type \tcode{atomic_flag} shall be lock-free. -The operations should also be address-free. - -\pnum -The \tcode{atomic_flag} type is a standard-layout struct. -It has a trivial destructor. - -\indexlibraryctor{atomic_flag}% -\begin{itemdecl} -constexpr atomic_flag::atomic_flag() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \tcode{*this} to the clear state. -\end{itemdescr} - -\indexlibraryglobal{atomic_flag_test}% -\indexlibraryglobal{atomic_flag_test_explicit}% -\indexlibrarymember{test}{atomic_flag}% -\begin{itemdecl} -bool atomic_flag_test(const volatile atomic_flag* object) noexcept; -bool atomic_flag_test(const atomic_flag* object) noexcept; -bool atomic_flag_test_explicit(const volatile atomic_flag* object, - memory_order order) noexcept; -bool atomic_flag_test_explicit(const atomic_flag* object, - memory_order order) noexcept; -bool atomic_flag::test(memory_order order = memory_order::seq_cst) const volatile noexcept; -bool atomic_flag::test(memory_order order = memory_order::seq_cst) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -For \tcode{atomic_flag_test}, let \tcode{order} be \tcode{memory_order::seq_cst}. - -\pnum -\expects -\tcode{order} is -neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. - -\pnum -\effects -Memory is affected according to the value of \tcode{order}. - -\pnum -\returns -Atomically returns the value pointed to by \tcode{object} or \keyword{this}. -\end{itemdescr} - -\indexlibraryglobal{atomic_flag_test_and_set}% -\indexlibraryglobal{atomic_flag_test_and_set_explicit}% -\indexlibrarymember{test_and_set}{atomic_flag}% -\begin{itemdecl} -bool atomic_flag_test_and_set(volatile atomic_flag* object) noexcept; -bool atomic_flag_test_and_set(atomic_flag* object) noexcept; -bool atomic_flag_test_and_set_explicit(volatile atomic_flag* object, memory_order order) noexcept; -bool atomic_flag_test_and_set_explicit(atomic_flag* object, memory_order order) noexcept; -bool atomic_flag::test_and_set(memory_order order = memory_order::seq_cst) volatile noexcept; -bool atomic_flag::test_and_set(memory_order order = memory_order::seq_cst) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Atomically sets the value pointed to by \tcode{object} or by \keyword{this} to \tcode{true}. Memory is affected according to the value of -\tcode{order}. These operations are atomic read-modify-write operations\iref{intro.multithread}. - -\pnum -\returns -Atomically, the value of the object immediately before the effects. -\end{itemdescr} - -\indexlibraryglobal{atomic_flag_clear}% -\indexlibraryglobal{atomic_flag_clear_explicit}% -\indexlibrarymember{clear}{atomic_flag}% -\begin{itemdecl} -void atomic_flag_clear(volatile atomic_flag* object) noexcept; -void atomic_flag_clear(atomic_flag* object) noexcept; -void atomic_flag_clear_explicit(volatile atomic_flag* object, memory_order order) noexcept; -void atomic_flag_clear_explicit(atomic_flag* object, memory_order order) noexcept; -void atomic_flag::clear(memory_order order = memory_order::seq_cst) volatile noexcept; -void atomic_flag::clear(memory_order order = memory_order::seq_cst) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -The \tcode{order} argument is neither \tcode{memory_order::consume}, -\tcode{memory_order::acquire}, nor \tcode{memory_order::acq_rel}. - -\pnum -\effects -Atomically sets the value pointed to by \tcode{object} or by \keyword{this} to -\tcode{false}. Memory is affected according to the value of \tcode{order}. -\end{itemdescr} - -\indexlibraryglobal{atomic_flag_wait}% -\indexlibraryglobal{atomic_flag_wait_explicit}% -\indexlibrarymember{wait}{atomic_flag}% -\begin{itemdecl} -void atomic_flag_wait(const volatile atomic_flag* object, bool old) noexcept; -void atomic_flag_wait(const atomic_flag* object, bool old) noexcept; -void atomic_flag_wait_explicit(const volatile atomic_flag* object, - bool old, memory_order order) noexcept; -void atomic_flag_wait_explicit(const atomic_flag* object, - bool old, memory_order order) noexcept; -void atomic_flag::wait(bool old, memory_order order = - memory_order::seq_cst) const volatile noexcept; -void atomic_flag::wait(bool old, memory_order order = - memory_order::seq_cst) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -For \tcode{atomic_flag_wait}, -let \tcode{order} be \tcode{memory_order::seq_cst}. -Let \tcode{flag} be \tcode{object} for the non-member functions and -\keyword{this} for the member functions. - -\pnum -\expects -\tcode{order} is -neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. - -\pnum -\effects -Repeatedly performs the following steps, in order: -\begin{itemize} -\item - Evaluates \tcode{flag->test(order) != old}. -\item - If the result of that evaluation is \tcode{true}, returns. -\item - Blocks until it - is unblocked by an atomic notifying operation or is unblocked spuriously. -\end{itemize} - -\pnum -\remarks -This function is an atomic waiting operation\iref{atomics.wait}. -\end{itemdescr} - -\begin{itemdecl} -void atomic_flag_notify_one(volatile atomic_flag* object) noexcept; -void atomic_flag_notify_one(atomic_flag* object) noexcept; -void atomic_flag::notify_one() volatile noexcept; -void atomic_flag::notify_one() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Unblocks the execution of at least one atomic waiting operation -that is eligible to be unblocked\iref{atomics.wait} by this call, -if any such atomic waiting operations exist. - -\pnum -\remarks -This function is an atomic notifying operation\iref{atomics.wait}. -\end{itemdescr} - -\begin{itemdecl} -void atomic_flag_notify_all(volatile atomic_flag* object) noexcept; -void atomic_flag_notify_all(atomic_flag* object) noexcept; -void atomic_flag::notify_all() volatile noexcept; -void atomic_flag::notify_all() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Unblocks the execution of all atomic waiting operations -that are eligible to be unblocked\iref{atomics.wait} by this call. - -\pnum -\remarks -This function is an atomic notifying operation\iref{atomics.wait}. -\end{itemdescr} - -\rSec1[atomics.fences]{Fences} - -\pnum -This subclause introduces synchronization primitives called \term{fences}. Fences can have -acquire semantics, release semantics, or both. A fence with acquire semantics is called -an \term{acquire fence}. A fence with release semantics is called a \term{release -fence}. - -\pnum -A release fence $A$ synchronizes with an acquire fence $B$ if there exist -atomic operations $X$ and $Y$, both operating on some atomic object -$M$, such that $A$ is sequenced before $X$, $X$ modifies -$M$, $Y$ is sequenced before $B$, and $Y$ reads the value -written by $X$ or a value written by any side effect in the hypothetical release -sequence $X$ would head if it were a release operation. - -\pnum -A release fence $A$ synchronizes with an atomic operation $B$ that -performs an acquire operation on an atomic object $M$ if there exists an atomic -operation $X$ such that $A$ is sequenced before $X$, $X$ -modifies $M$, and $B$ reads the value written by $X$ or a value -written by any side effect in the hypothetical release sequence $X$ would head if -it were a release operation. - -\pnum -An atomic operation $A$ that is a release operation on an atomic object -$M$ synchronizes with an acquire fence $B$ if there exists some atomic -operation $X$ on $M$ such that $X$ is sequenced before $B$ -and reads the value written by $A$ or a value written by any side effect in the -release sequence headed by $A$. - -\indexlibraryglobal{atomic_thread_fence}% -\begin{itemdecl} -extern "C" void atomic_thread_fence(memory_order order) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Depending on the value of \tcode{order}, this operation: -\begin{itemize} -\item has no effects, if \tcode{order == memory_order::relaxed}; - -\item is an acquire fence, if \tcode{order == memory_order::acquire} or \tcode{order == memory_order::consume}; - -\item is a release fence, if \tcode{order == memory_order::release}; - -\item is both an acquire fence and a release fence, if \tcode{order == memory_order::acq_rel}; - -\item is a sequentially consistent acquire and release fence, if \tcode{order == memory_order::seq_cst}. -\end{itemize} -\end{itemdescr} - -\indexlibraryglobal{atomic_signal_fence}% -\begin{itemdecl} -extern "C" void atomic_signal_fence(memory_order order) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to \tcode{atomic_thread_fence(order)}, except that -the resulting ordering constraints are established only between a thread and a -signal handler executed in the same thread. - -\pnum -\begin{note} -\tcode{atomic_signal_fence} can be used to specify the order in which actions -performed by the thread become visible to the signal handler. -Compiler optimizations and reorderings of loads and stores are inhibited in -the same way as with \tcode{atomic_thread_fence}, but the hardware fence instructions -that \tcode{atomic_thread_fence} would have inserted are not emitted. -\end{note} -\end{itemdescr} - -\rSec1[stdatomic.h.syn]{C compatibility} - -The header \libheaderdef{stdatomic.h} provides the following definitions: - -\begin{codeblock} -template - using @\exposid{std-atomic}@ = std::atomic; // \expos - -#define _Atomic(T) @\exposid{std-atomic}@ - -#define ATOMIC_BOOL_LOCK_FREE @\seebelow@ -#define ATOMIC_CHAR_LOCK_FREE @\seebelow@ -#define ATOMIC_CHAR16_T_LOCK_FREE @\seebelow@ -#define ATOMIC_CHAR32_T_LOCK_FREE @\seebelow@ -#define ATOMIC_WCHAR_T_LOCK_FREE @\seebelow@ -#define ATOMIC_SHORT_LOCK_FREE @\seebelow@ -#define ATOMIC_INT_LOCK_FREE @\seebelow@ -#define ATOMIC_LONG_LOCK_FREE @\seebelow@ -#define ATOMIC_LLONG_LOCK_FREE @\seebelow@ -#define ATOMIC_POINTER_LOCK_FREE @\seebelow@ - -using std::@\libglobal{memory_order}@; // \seebelow -using std::@\libglobal{memory_order_relaxed}@; // \seebelow -using std::@\libglobal{memory_order_consume}@; // \seebelow -using std::@\libglobal{memory_order_acquire}@; // \seebelow -using std::@\libglobal{memory_order_release}@; // \seebelow -using std::@\libglobal{memory_order_acq_rel}@; // \seebelow -using std::@\libglobal{memory_order_seq_cst}@; // \seebelow - -using std::@\libglobal{atomic_flag}@; // \seebelow - -using std::@\libglobal{atomic_bool}@; // \seebelow -using std::@\libglobal{atomic_char}@; // \seebelow -using std::@\libglobal{atomic_schar}@; // \seebelow -using std::@\libglobal{atomic_uchar}@; // \seebelow -using std::@\libglobal{atomic_short}@; // \seebelow -using std::@\libglobal{atomic_ushort}@; // \seebelow -using std::@\libglobal{atomic_int}@; // \seebelow -using std::@\libglobal{atomic_uint}@; // \seebelow -using std::@\libglobal{atomic_long}@; // \seebelow -using std::@\libglobal{atomic_ulong}@; // \seebelow -using std::@\libglobal{atomic_llong}@; // \seebelow -using std::@\libglobal{atomic_ullong}@; // \seebelow -using std::@\libglobal{atomic_char8_t}@; // \seebelow -using std::@\libglobal{atomic_char16_t}@; // \seebelow -using std::@\libglobal{atomic_char32_t}@; // \seebelow -using std::@\libglobal{atomic_wchar_t}@; // \seebelow -using std::@\libglobal{atomic_int8_t}@; // \seebelow -using std::@\libglobal{atomic_uint8_t}@; // \seebelow -using std::@\libglobal{atomic_int16_t}@; // \seebelow -using std::@\libglobal{atomic_uint16_t}@; // \seebelow -using std::@\libglobal{atomic_int32_t}@; // \seebelow -using std::@\libglobal{atomic_uint32_t}@; // \seebelow -using std::@\libglobal{atomic_int64_t}@; // \seebelow -using std::@\libglobal{atomic_uint64_t}@; // \seebelow -using std::@\libglobal{atomic_int_least8_t}@; // \seebelow -using std::@\libglobal{atomic_uint_least8_t}@; // \seebelow -using std::@\libglobal{atomic_int_least16_t}@; // \seebelow -using std::@\libglobal{atomic_uint_least16_t}@; // \seebelow -using std::@\libglobal{atomic_int_least32_t}@; // \seebelow -using std::@\libglobal{atomic_uint_least32_t}@; // \seebelow -using std::@\libglobal{atomic_int_least64_t}@; // \seebelow -using std::@\libglobal{atomic_uint_least64_t}@; // \seebelow -using std::@\libglobal{atomic_int_fast8_t}@; // \seebelow -using std::@\libglobal{atomic_uint_fast8_t}@; // \seebelow -using std::@\libglobal{atomic_int_fast16_t}@; // \seebelow -using std::@\libglobal{atomic_uint_fast16_t}@; // \seebelow -using std::@\libglobal{atomic_int_fast32_t}@; // \seebelow -using std::@\libglobal{atomic_uint_fast32_t}@; // \seebelow -using std::@\libglobal{atomic_int_fast64_t}@; // \seebelow -using std::@\libglobal{atomic_uint_fast64_t}@; // \seebelow -using std::@\libglobal{atomic_intptr_t}@; // \seebelow -using std::@\libglobal{atomic_uintptr_t}@; // \seebelow -using std::@\libglobal{atomic_size_t}@; // \seebelow -using std::@\libglobal{atomic_ptrdiff_t}@; // \seebelow -using std::@\libglobal{atomic_intmax_t}@; // \seebelow -using std::@\libglobal{atomic_uintmax_t}@; // \seebelow - -using std::@\libglobal{atomic_is_lock_free}@; // \seebelow -using std::@\libglobal{atomic_load}@; // \seebelow -using std::@\libglobal{atomic_load_explicit}@; // \seebelow -using std::@\libglobal{atomic_store}@; // \seebelow -using std::@\libglobal{atomic_store_explicit}@; // \seebelow -using std::@\libglobal{atomic_exchange}@; // \seebelow -using std::@\libglobal{atomic_exchange_explicit}@; // \seebelow -using std::@\libglobal{atomic_compare_exchange_strong}@; // \seebelow -using std::@\libglobal{atomic_compare_exchange_strong_explicit}@; // \seebelow -using std::@\libglobal{atomic_compare_exchange_weak}@; // \seebelow -using std::@\libglobal{atomic_compare_exchange_weak_explicit}@; // \seebelow -using std::@\libglobal{atomic_fetch_add}@; // \seebelow -using std::@\libglobal{atomic_fetch_add_explicit}@; // \seebelow -using std::@\libglobal{atomic_fetch_sub}@; // \seebelow -using std::@\libglobal{atomic_fetch_sub_explicit}@; // \seebelow -using std::@\libglobal{atomic_fetch_or}@; // \seebelow -using std::@\libglobal{atomic_fetch_or_explicit}@; // \seebelow -using std::@\libglobal{atomic_fetch_and}@; // \seebelow -using std::@\libglobal{atomic_fetch_and_explicit}@; // \seebelow -using std::@\libglobal{atomic_flag_test_and_set}@; // \seebelow -using std::@\libglobal{atomic_flag_test_and_set_explicit}@; // \seebelow -using std::@\libglobal{atomic_flag_clear}@; // \seebelow -using std::@\libglobal{atomic_flag_clear_explicit}@; // \seebelow - -using std::@\libglobal{atomic_thread_fence}@; // \seebelow -using std::@\libglobal{atomic_signal_fence}@; // \seebelow -\end{codeblock} - -\pnum -Each \grammarterm{using-declaration} for some name $A$ in the synopsis above -makes available the same entity as \tcode{std::$A$} -declared in \libheaderrefx{atomic}{atomics.syn}. -Each macro listed above other than \tcode{_Atomic(T)} -is defined as in \libheader{atomic}. -It is unspecified whether \libheader{stdatomic.h} makes available -any declarations in namespace \tcode{std}. - -\pnum -Each of the \grammarterm{using-declaration}s for -\tcode{int$N$_t}, \tcode{uint$N$_t}, \tcode{intptr_t}, and \tcode{uintptr_t} -listed above is defined if and only if the implementation defines -the corresponding \grammarterm{typedef-name} in \ref{atomics.syn}. - -\pnum -Neither the \tcode{_Atomic} macro, -nor any of the non-macro global namespace declarations, -are provided by any \Cpp{} standard library header -other than \libheader{stdatomic.h}. - -\pnum -\recommended -Implementations should ensure -that C and \Cpp{} representations of atomic objects are compatible, -so that the same object can be accessed as both an \tcode{_Atomic(T)} -from C code and an \tcode{atomic} from \Cpp{} code. -The representations should be the same, and -the mechanisms used to ensure atomicity and memory ordering -should be compatible. diff --git a/source/compatibility.tex b/source/compatibility.tex index a5b7bac5ee..77cf38c7ec 100644 --- a/source/compatibility.tex +++ b/source/compatibility.tex @@ -1591,7 +1591,7 @@ \libheaderrefx{system_error}{system.error.syn}, \libheaderref{thread}, \libheaderref{tuple}, -\libheaderrefx{typeindex}{type.index.synopsis}, +\libheaderrefx{type\-index}{type.index.synopsis}, \libheaderrefx{type_traits}{meta.type.synop}, \libheaderrefx{unordered_map}{unord.map.syn}, and diff --git a/source/lib-intro.tex b/source/lib-intro.tex index 870871efcd..6c61e9440b 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -29,6 +29,8 @@ \ref{support} & Language support library \\ \ref{concepts} & Concepts library \\ \ref{diagnostics} & Diagnostics library \\ +\ref{mem} & Memory management library \\ +\ref{meta} & Metaprogramming library \\ \ref{utilities} & General utilities library \\ \ref{strings} & Strings library \\ \ref{containers} & Containers library \\ @@ -40,8 +42,7 @@ \ref{localization} & Localization library \\ \ref{input.output} & Input/output library \\ \ref{re} & Regular expressions library \\ -\ref{atomics} & Atomic operations library \\ -\ref{thread} & Thread support library \\ +\ref{thread} & Concurrency support library \\ \end{floattable} \pnum @@ -59,6 +60,15 @@ The diagnostics library\iref{diagnostics} provides a consistent framework for reporting errors in a \Cpp{} program, including predefined exception classes. +\pnum +The memory management library\iref{mem} provides components for +memory management, including smart pointers and scoped allocators. + +\pnum +The metaprogramming library\iref{meta} describes facilities +for use in templates and during constant evaluation, +including type traits, integer sequences, and rational arithmetic. + \pnum The general utilities library\iref{utilities} includes components used by other library elements, such as a predefined storage allocator for dynamic @@ -110,13 +120,10 @@ \pnum The regular expressions library\iref{re} provides regular expression matching and searching. -\pnum -The atomic operations library\iref{atomics} allows more fine-grained -concurrent access to shared data than is possible with locks. - \pnum The thread support library\iref{thread} provides components to create -and manage threads, including mutual exclusion and interthread communication. +and manage threads, +including atomic operations, mutual exclusion, and interthread communication. \rSec1[library.c]{The C standard library} @@ -1332,7 +1339,7 @@ \ref{support.coroutine} & Coroutines support & \tcode{} \\ \rowsep \ref{support.runtime} & Other runtime support & \tcode{} \\ \rowsep \ref{concepts} & Concepts library & \tcode{} \\ \rowsep -\ref{meta} & Type traits & \tcode{} \\ \rowsep +\ref{type.traits} & Type traits & \tcode{} \\ \rowsep \ref{bit} & Bit manipulation & \tcode{} \\ \rowsep \ref{atomics} & Atomics & \tcode{} \\ \end{libsumtab} diff --git a/source/memory.tex b/source/memory.tex new file mode 100644 index 0000000000..668bdf2667 --- /dev/null +++ b/source/memory.tex @@ -0,0 +1,6754 @@ +%!TEX root = std.tex +\rSec0[mem]{Memory management library} + +\rSec1[mem.general]{General} + +\pnum +This Clause describes components for memory management. + +\pnum +The following subclauses describe general memory management facilities, +smart pointers, memory resources, and scoped allocators, +as summarized in \tref{mem.summary}. + +\begin{libsumtab}{Memory management library summary}{mem.summary} +\ref{memory} & Memory & \tcode{}, \tcode{} \\ \rowsep +\ref{smartptr} & Smart pointers & \tcode{} \\ \rowsep +\ref{mem.res} & Memory resources & \tcode{} \\ \rowsep +\ref{allocator.adaptor} & Scoped allocators & \tcode{} \\ +\end{libsumtab} + +\rSec1[memory]{Memory} + +\rSec2[memory.general]{In general} + +\pnum +Subclause~\ref{memory} describes the contents of the header +\libheaderref{memory} and some +of the contents of the header \libheaderref{cstdlib}. + +\rSec2[memory.syn]{Header \tcode{} synopsis} + +\pnum +The header \libheaderdef{memory} defines several types and function templates that +describe properties of pointers and pointer-like types, manage memory +for containers and other template types, destroy objects, and +construct objects in +uninitialized memory +buffers~(\ref{pointer.traits}--\ref{specialized.addressof} and \ref{specialized.algorithms}). +The header also defines the templates +\tcode{unique_ptr}, \tcode{shared_ptr}, \tcode{weak_ptr}, +\tcode{out_ptr_t}, \tcode{inout_ptr_t}, and various function +templates that operate on objects of these types\iref{smartptr}. + +\pnum +Let \tcode{\exposid{POINTER_OF}(T)} denote a type that is +\begin{itemize} +\item +\tcode{T::pointer} if the \grammarterm{qualified-id} \tcode{T::pointer} +is valid and denotes a type, +\item +otherwise, \tcode{T::element_type*} +if the \grammarterm{qualified-id} \tcode{T::element_type} +is valid and denotes a type, +\item +otherwise, \tcode{pointer_traits::element_type*}. +\end{itemize} + +\pnum +Let \tcode{\exposid{POINTER_OF_OR}(T, U)} denote a type that is: +\begin{itemize} +\item +\tcode{\exposid{POINTER_OF}(T)} +if \tcode{\exposid{POINTER_OF}(T)} is valid and denotes a type, +\item +otherwise, \tcode{U}. +\end{itemize} + +\begin{codeblock} +#include // see \ref{compare.syn} + +namespace std { + // \ref{pointer.traits}, pointer traits + template struct pointer_traits; + template struct pointer_traits; + + // \ref{pointer.conversion}, pointer conversion + template + constexpr T* to_address(T* p) noexcept; + template + constexpr auto to_address(const Ptr& p) noexcept; + + // \ref{ptr.align}, pointer alignment + void* align(size_t alignment, size_t size, void*& ptr, size_t& space); + template + [[nodiscard]] constexpr T* assume_aligned(T* ptr); + + // \ref{allocator.tag}, allocator argument tag + struct allocator_arg_t { explicit allocator_arg_t() = default; }; + inline constexpr allocator_arg_t allocator_arg{}; + + // \ref{allocator.uses}, \tcode{uses_allocator} + template struct uses_allocator; + + // \ref{allocator.uses.trait}, \tcode{uses_allocator} + template + inline constexpr bool @\libglobal{uses_allocator_v}@ = uses_allocator::value; + + // \ref{allocator.uses.construction}, uses-allocator construction + template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + Args&&... args) noexcept; + template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, + Tuple1&& x, Tuple2&& y) noexcept; + template + constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept; + template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + U&& u, V&& v) noexcept; + template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + pair& pr) noexcept; + template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + const pair& pr) noexcept; + template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + pair&& pr) noexcept; + template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + const pair&& pr) noexcept; + template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, U&& u) noexcept; + template + constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args); + template + constexpr T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, + Args&&... args); + + // \ref{allocator.traits}, allocator traits + template struct allocator_traits; + + template + struct allocation_result { + Pointer ptr; + size_t count; + }; + + template + [[nodiscard] constexpr allocation_result::pointer> + allocate_at_least(Allocator& a, size_t n); + + // \ref{default.allocator}, the default allocator + template class allocator; + template + constexpr bool operator==(const allocator&, const allocator&) noexcept; + + // \ref{specialized.addressof}, addressof + template + constexpr T* addressof(T& r) noexcept; + template + const T* addressof(const T&&) = delete; + + // \ref{specialized.algorithms}, specialized algorithms + // \ref{special.mem.concepts}, special memory concepts + template + concept @\exposconcept{nothrow-input-iterator}@ = @\seebelow@; // \expos + template + concept @\exposconcept{nothrow-forward-iterator}@ = @\seebelow@; // \expos + template + concept @\exposconcept{nothrow-sentinel-for}@ = @\seebelow@; // \expos + template + concept @\exposconcept{nothrow-input-range}@ = @\seebelow@; // \expos + template + concept @\exposconcept{nothrow-forward-range}@ = @\seebelow@; // \expos + + template + void uninitialized_default_construct(NoThrowForwardIterator first, + NoThrowForwardIterator last); + template + void uninitialized_default_construct(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + NoThrowForwardIterator first, + NoThrowForwardIterator last); + template + NoThrowForwardIterator + uninitialized_default_construct_n(NoThrowForwardIterator first, Size n); + template + NoThrowForwardIterator + uninitialized_default_construct_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + NoThrowForwardIterator first, Size n); + + namespace ranges { + template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S> + requires @\libconcept{default_initializable}@> + I uninitialized_default_construct(I first, S last); + template<@\exposconcept{nothrow-forward-range}@ R> + requires @\libconcept{default_initializable}@> + borrowed_iterator_t uninitialized_default_construct(R&& r); + + template<@\exposconcept{nothrow-forward-iterator}@ I> + requires @\libconcept{default_initializable}@> + I uninitialized_default_construct_n(I first, iter_difference_t n); + } + + template + void uninitialized_value_construct(NoThrowForwardIterator first, + NoThrowForwardIterator last); + template + void uninitialized_value_construct(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + NoThrowForwardIterator first, + NoThrowForwardIterator last); + template + NoThrowForwardIterator + uninitialized_value_construct_n(NoThrowForwardIterator first, Size n); + template + NoThrowForwardIterator + uninitialized_value_construct_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + NoThrowForwardIterator first, Size n); + + namespace ranges { + template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S> + requires @\libconcept{default_initializable}@> + I uninitialized_value_construct(I first, S last); + template<@\exposconcept{nothrow-forward-range}@ R> + requires @\libconcept{default_initializable}@> + borrowed_iterator_t uninitialized_value_construct(R&& r); + + template<@\exposconcept{nothrow-forward-iterator}@ I> + requires @\libconcept{default_initializable}@> + I uninitialized_value_construct_n(I first, iter_difference_t n); + } + + template + NoThrowForwardIterator uninitialized_copy(InputIterator first, InputIterator last, + NoThrowForwardIterator result); + template + NoThrowForwardIterator uninitialized_copy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator first, ForwardIterator last, + NoThrowForwardIterator result); + template + NoThrowForwardIterator uninitialized_copy_n(InputIterator first, Size n, + NoThrowForwardIterator result); + template + NoThrowForwardIterator uninitialized_copy_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator first, Size n, + NoThrowForwardIterator result); + + namespace ranges { + template + using uninitialized_copy_result = in_out_result; + template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S1, + @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S2> + requires @\libconcept{constructible_from}@, iter_reference_t> + uninitialized_copy_result + uninitialized_copy(I ifirst, S1 ilast, O ofirst, S2 olast); + template<@\libconcept{input_range}@ IR, @\exposconcept{nothrow-forward-range}@ OR> + requires @\libconcept{constructible_from}@, range_reference_t> + uninitialized_copy_result, borrowed_iterator_t> + uninitialized_copy(IR&& in_range, OR&& out_range); + + template + using uninitialized_copy_n_result = in_out_result; + template<@\libconcept{input_iterator}@ I, @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S> + requires @\libconcept{constructible_from}@, iter_reference_t> + uninitialized_copy_n_result + uninitialized_copy_n(I ifirst, iter_difference_t n, O ofirst, S olast); + } + + template + NoThrowForwardIterator uninitialized_move(InputIterator first, InputIterator last, + NoThrowForwardIterator result); + template + NoThrowForwardIterator uninitialized_move(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator first, ForwardIterator last, + NoThrowForwardIterator result); + template + pair + uninitialized_move_n(InputIterator first, Size n, NoThrowForwardIterator result); + template + pair + uninitialized_move_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator first, Size n, NoThrowForwardIterator result); + + namespace ranges { + template + using uninitialized_move_result = in_out_result; + template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S1, + @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S2> + requires @\libconcept{constructible_from}@, iter_rvalue_reference_t> + uninitialized_move_result + uninitialized_move(I ifirst, S1 ilast, O ofirst, S2 olast); + template<@\libconcept{input_range}@ IR, @\exposconcept{nothrow-forward-range}@ OR> + requires @\libconcept{constructible_from}@, range_rvalue_reference_t> + uninitialized_move_result, borrowed_iterator_t> + uninitialized_move(IR&& in_range, OR&& out_range); + + template + using uninitialized_move_n_result = in_out_result; + template<@\libconcept{input_iterator}@ I, + @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S> + requires @\libconcept{constructible_from}@, iter_rvalue_reference_t> + uninitialized_move_n_result + uninitialized_move_n(I ifirst, iter_difference_t n, O ofirst, S olast); + } + + template + void uninitialized_fill(NoThrowForwardIterator first, NoThrowForwardIterator last, + const T& x); + template + void uninitialized_fill(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + NoThrowForwardIterator first, NoThrowForwardIterator last, + const T& x); + template + NoThrowForwardIterator + uninitialized_fill_n(NoThrowForwardIterator first, Size n, const T& x); + template + NoThrowForwardIterator + uninitialized_fill_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + NoThrowForwardIterator first, Size n, const T& x); + + namespace ranges { + template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S, class T> + requires @\libconcept{constructible_from}@, const T&> + I uninitialized_fill(I first, S last, const T& x); + template<@\exposconcept{nothrow-forward-range}@ R, class T> + requires @\libconcept{constructible_from}@, const T&> + borrowed_iterator_t uninitialized_fill(R&& r, const T& x); + + template<@\exposconcept{nothrow-forward-iterator}@ I, class T> + requires @\libconcept{constructible_from}@, const T&> + I uninitialized_fill_n(I first, iter_difference_t n, const T& x); + } + + // \ref{specialized.construct}, \tcode{construct_at} + template + constexpr T* construct_at(T* location, Args&&... args); + + namespace ranges { + template + constexpr T* construct_at(T* location, Args&&... args); + } + + // \ref{specialized.destroy}, \tcode{destroy} + template + constexpr void destroy_at(T* location); + template + constexpr void destroy(NoThrowForwardIterator first, NoThrowForwardIterator last); + template + void destroy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + NoThrowForwardIterator first, NoThrowForwardIterator last); + template + constexpr NoThrowForwardIterator destroy_n(NoThrowForwardIterator first, Size n); + template + NoThrowForwardIterator destroy_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + NoThrowForwardIterator first, Size n); + + namespace ranges { + template<@\libconcept{destructible}@ T> + constexpr void destroy_at(T* location) noexcept; + + template<@\exposconcept{nothrow-input-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S> + requires @\libconcept{destructible}@> + constexpr I destroy(I first, S last) noexcept; + template<@\exposconcept{nothrow-input-range}@ R> + requires @\libconcept{destructible}@> + constexpr borrowed_iterator_t destroy(R&& r) noexcept; + + template<@\exposconcept{nothrow-input-iterator}@ I> + requires @\libconcept{destructible}@> + constexpr I destroy_n(I first, iter_difference_t n) noexcept; + } + + // \ref{unique.ptr}, class template \tcode{unique_ptr} + template struct default_delete; + template struct default_delete; + template> class unique_ptr; + template class unique_ptr; + + template + constexpr unique_ptr make_unique(Args&&... args); // \tcode{T} is not array + template + constexpr unique_ptr make_unique(size_t n); // \tcode{T} is \tcode{U[]} + template + @\unspecnc@ make_unique(Args&&...) = delete; // \tcode{T} is \tcode{U[N]} + + template + constexpr unique_ptr make_unique_for_overwrite(); // \tcode{T} is not array + template + constexpr unique_ptr make_unique_for_overwrite(size_t n); // \tcode{T} is \tcode{U[]} + template + @\unspecnc@ make_unique_for_overwrite(Args&&...) = delete; // \tcode{T} is \tcode{U[N]} + + template + constexpr void swap(unique_ptr& x, unique_ptr& y) noexcept; + + template + constexpr bool operator==(const unique_ptr& x, const unique_ptr& y); + template + bool operator<(const unique_ptr& x, const unique_ptr& y); + template + bool operator>(const unique_ptr& x, const unique_ptr& y); + template + bool operator<=(const unique_ptr& x, const unique_ptr& y); + template + bool operator>=(const unique_ptr& x, const unique_ptr& y); + template + requires @\libconcept{three_way_comparable_with}@::pointer, + typename unique_ptr::pointer> + compare_three_way_result_t::pointer, + typename unique_ptr::pointer> + operator<=>(const unique_ptr& x, const unique_ptr& y); + + template + constexpr bool operator==(const unique_ptr& x, nullptr_t) noexcept; + template + constexpr bool operator<(const unique_ptr& x, nullptr_t); + template + constexpr bool operator<(nullptr_t, const unique_ptr& y); + template + constexpr bool operator>(const unique_ptr& x, nullptr_t); + template + constexpr bool operator>(nullptr_t, const unique_ptr& y); + template + constexpr bool operator<=(const unique_ptr& x, nullptr_t); + template + constexpr bool operator<=(nullptr_t, const unique_ptr& y); + template + constexpr bool operator>=(const unique_ptr& x, nullptr_t); + template + constexpr bool operator>=(nullptr_t, const unique_ptr& y); + template + requires @\libconcept{three_way_comparable}@::pointer> + constexpr compare_three_way_result_t::pointer> + operator<=>(const unique_ptr& x, nullptr_t); + + template + basic_ostream& operator<<(basic_ostream& os, const unique_ptr& p); + + // \ref{util.smartptr.weak.bad}, class \tcode{bad_weak_ptr} + class bad_weak_ptr; + + // \ref{util.smartptr.shared}, class template \tcode{shared_ptr} + template class shared_ptr; + + // \ref{util.smartptr.shared.create}, \tcode{shared_ptr} creation + template + shared_ptr make_shared(Args&&... args); // \tcode{T} is not array + template + shared_ptr allocate_shared(const A& a, Args&&... args); // \tcode{T} is not array + + template + shared_ptr make_shared(size_t N); // \tcode{T} is \tcode{U[]} + template + shared_ptr allocate_shared(const A& a, size_t N); // \tcode{T} is \tcode{U[]} + + template + shared_ptr make_shared(); // \tcode{T} is \tcode{U[N]} + template + shared_ptr allocate_shared(const A& a); // \tcode{T} is \tcode{U[N]} + + template + shared_ptr make_shared(size_t N, const remove_extent_t& u); // \tcode{T} is \tcode{U[]} + template + shared_ptr allocate_shared(const A& a, size_t N, + const remove_extent_t& u); // \tcode{T} is \tcode{U[]} + + template + shared_ptr make_shared(const remove_extent_t& u); // \tcode{T} is \tcode{U[N]} + template + shared_ptr allocate_shared(const A& a, const remove_extent_t& u); // \tcode{T} is \tcode{U[N]} + + template + shared_ptr make_shared_for_overwrite(); // \tcode{T} is not \tcode{U[]} + template + shared_ptr allocate_shared_for_overwrite(const A& a); // \tcode{T} is not \tcode{U[]} + + template + shared_ptr make_shared_for_overwrite(size_t N); // \tcode{T} is \tcode{U[]} + template + shared_ptr allocate_shared_for_overwrite(const A& a, size_t N); // \tcode{T} is \tcode{U[]} + + // \ref{util.smartptr.shared.cmp}, \tcode{shared_ptr} comparisons + template + bool operator==(const shared_ptr& a, const shared_ptr& b) noexcept; + template + strong_ordering operator<=>(const shared_ptr& a, const shared_ptr& b) noexcept; + + template + bool operator==(const shared_ptr& x, nullptr_t) noexcept; + template + strong_ordering operator<=>(const shared_ptr& x, nullptr_t) noexcept; + + // \ref{util.smartptr.shared.spec}, \tcode{shared_ptr} specialized algorithms + template + void swap(shared_ptr& a, shared_ptr& b) noexcept; + + // \ref{util.smartptr.shared.cast}, \tcode{shared_ptr} casts + template + shared_ptr static_pointer_cast(const shared_ptr& r) noexcept; + template + shared_ptr static_pointer_cast(shared_ptr&& r) noexcept; + template + shared_ptr dynamic_pointer_cast(const shared_ptr& r) noexcept; + template + shared_ptr dynamic_pointer_cast(shared_ptr&& r) noexcept; + template + shared_ptr const_pointer_cast(const shared_ptr& r) noexcept; + template + shared_ptr const_pointer_cast(shared_ptr&& r) noexcept; + template + shared_ptr reinterpret_pointer_cast(const shared_ptr& r) noexcept; + template + shared_ptr reinterpret_pointer_cast(shared_ptr&& r) noexcept; + + // \ref{util.smartptr.getdeleter}, \tcode{shared_ptr} \tcode{get_deleter} + template + D* get_deleter(const shared_ptr& p) noexcept; + + // \ref{util.smartptr.shared.io}, \tcode{shared_ptr} I/O + template + basic_ostream& operator<<(basic_ostream& os, const shared_ptr& p); + + // \ref{util.smartptr.weak}, class template \tcode{weak_ptr} + template class weak_ptr; + + // \ref{util.smartptr.weak.spec}, \tcode{weak_ptr} specialized algorithms + template void swap(weak_ptr& a, weak_ptr& b) noexcept; + + // \ref{util.smartptr.ownerless}, class template \tcode{owner_less} + template struct owner_less; + + // \ref{util.smartptr.enab}, class template \tcode{enable_shared_from_this} + template class enable_shared_from_this; + + // \ref{util.smartptr.hash}, hash support + template struct hash; + template struct hash>; + template struct hash>; + + // \ref{util.smartptr.atomic}, atomic smart pointers + template struct atomic; + template struct atomic>; + template struct atomic>; + + // \ref{out.ptr.t}, class template \tcode{out_ptr_t} + template + class out_ptr_t; + + // \ref{out.ptr}, function template \tcode{out_ptr} + template + auto out_ptr(Smart& s, Args&&... args); + + // \ref{inout.ptr.t}, class template \tcode{inout_ptr_t} + template + class inout_ptr_t; + + // \ref{inout.ptr}, function template \tcode{inout_ptr} + template + auto inout_ptr(Smart& s, Args&&... args); +} +\end{codeblock} + +\rSec2[pointer.traits]{Pointer traits} + +\rSec3[pointer.traits.general]{General} + +\pnum +The class template \tcode{pointer_traits} supplies a uniform interface to certain +attributes of pointer-like types. + +\indexlibraryglobal{pointer_traits}% +\begin{codeblock} +namespace std { + template struct pointer_traits { + using pointer = Ptr; + using element_type = @\seebelow@; + using difference_type = @\seebelow@; + + template using rebind = @\seebelow@; + + static pointer pointer_to(@\seebelow@ r); + }; + + template struct pointer_traits { + using pointer = T*; + using element_type = T; + using difference_type = ptrdiff_t; + + template using rebind = U*; + + static constexpr pointer pointer_to(@\seebelow@ r) noexcept; + }; +} +\end{codeblock} + +\rSec3[pointer.traits.types]{Member types} + +\indexlibrarymember{element_type}{pointer_traits}% +\begin{itemdecl} +using element_type = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ctype \tcode{Ptr::element_type} if +the \grammarterm{qualified-id} \tcode{Ptr::element_type} is valid and denotes a +type\iref{temp.deduct}; otherwise, \tcode{T} if +\tcode{Ptr} is a class template instantiation of the form \tcode{SomePointer}, +where \tcode{Args} is zero or more type arguments; otherwise, the specialization is +ill-formed. +\end{itemdescr} + +\indexlibrarymember{difference_type}{pointer_traits}% +\begin{itemdecl} +using difference_type = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ctype \tcode{Ptr::difference_type} if +the \grammarterm{qualified-id} \tcode{Ptr::difference_type} is valid and denotes a +type\iref{temp.deduct}; otherwise, +\tcode{ptrdiff_t}. +\end{itemdescr} + +\indexlibrarymember{rebind}{pointer_traits}% +\begin{itemdecl} +template using rebind = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\templalias \tcode{Ptr::rebind} if +the \grammarterm{qualified-id} \tcode{Ptr::rebind} is valid and denotes a +type\iref{temp.deduct}; otherwise, +\tcode{SomePointer} if +\tcode{Ptr} is a class template instantiation of the form \tcode{SomePointer}, +where \tcode{Args} is zero or more type arguments; otherwise, the instantiation of +\tcode{rebind} is ill-formed. +\end{itemdescr} + +\rSec3[pointer.traits.functions]{Member functions} + +\indexlibrarymember{pointer_to}{pointer_traits}% +\begin{itemdecl} +static pointer pointer_traits::pointer_to(@\seebelow@ r); +static constexpr pointer pointer_traits::pointer_to(@\seebelow@ r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +For the first member function, +\tcode{Ptr::pointer_to(r)} is well-formed. + +\pnum +\expects +For the first member function, +\tcode{Ptr::pointer_to(r)} returns a pointer to \tcode{r} +through which indirection is valid. + +\pnum +\returns +The first member function returns \tcode{Ptr::pointer_to(r)}. +The second member function returns \tcode{addressof(r)}. + +\pnum +\remarks +If \tcode{element_type} is \cv{}~\keyword{void}, the type of +\tcode{r} is unspecified; otherwise, it is \tcode{element_type\&}. +\end{itemdescr} + +\rSec3[pointer.traits.optmem]{Optional members} + +\pnum +Specializations of \tcode{pointer_traits} may define the member declared +in this subclause to customize the behavior of the standard library. + +\indexlibrarymember{to_address}{pointer_traits}% +\begin{itemdecl} +static element_type* to_address(pointer p) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A pointer of type \tcode{element_type*} that references +the same location as the argument \tcode{p}. + +\pnum +\begin{note} +This function is intended to be the inverse of \tcode{pointer_to}. +If defined, it customizes the behavior of +the non-member function +\tcode{to_address}\iref{pointer.conversion}. +\end{note} +\end{itemdescr} + +\rSec2[pointer.conversion]{Pointer conversion} + +\indexlibraryglobal{to_address}% +\begin{itemdecl} +template constexpr T* to_address(T* p) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{T} is not a function type. + +\pnum +\returns +\tcode{p}. +\end{itemdescr} + +\indexlibraryglobal{to_address}% +\begin{itemdecl} +template constexpr auto to_address(const Ptr& p) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{pointer_traits::to_address(p)} if that expression is well-formed +(see \ref{pointer.traits.optmem}), +otherwise \tcode{to_address(p.operator->())}. +\end{itemdescr} + +\rSec2[ptr.align]{Pointer alignment} + +\indexlibraryglobal{align}% +\begin{itemdecl} +void* align(size_t alignment, size_t size, void*& ptr, size_t& space); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\begin{itemize} +\item +\tcode{alignment} is a power of two + +\item +\tcode{ptr} represents the address of contiguous storage of at least +\tcode{space} bytes +\end{itemize} + +\pnum +\effects +If it is possible to fit \tcode{size} bytes +of storage aligned by \tcode{alignment} into the buffer pointed to by +\tcode{ptr} with length \tcode{space}, the function updates +\tcode{ptr} to represent the first possible address of such storage +and decreases \tcode{space} by the number of bytes used for alignment. +Otherwise, the function does nothing. + +\pnum +\returns +A null pointer if the requested aligned buffer +would not fit into the available space, otherwise the adjusted value +of \tcode{ptr}. + +\pnum +\begin{note} +The function updates its \tcode{ptr} +and \tcode{space} arguments so that it can be called repeatedly +with possibly different \tcode{alignment} and \tcode{size} +arguments for the same buffer. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{assume_aligned}% +\begin{itemdecl} +template + [[nodiscard]] constexpr T* assume_aligned(T* ptr); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{N} is a power of two. + +\pnum +\expects +\tcode{ptr} points to an object \tcode{X} of +a type similar\iref{conv.qual} to \tcode{T}, +where \tcode{X} has alignment \tcode{N}\iref{basic.align}. + +\pnum +\returns +\tcode{ptr}. + +\pnum +\throws +Nothing. + +\pnum +\begin{note} +The alignment assumption on an object \tcode{X} +expressed by a call to \tcode{assume_aligned} +might result in generation of more efficient code. +It is up to the program to ensure that the assumption actually holds. +The call does not cause the implementation to verify or enforce this. +An implementation might only make the assumption +for those operations on \tcode{X} that access \tcode{X} +through the pointer returned by \tcode{assume_aligned}. +\end{note} +\end{itemdescr} + +\rSec2[allocator.tag]{Allocator argument tag} + +\indexlibraryglobal{allocator_arg_t}% +\indexlibraryglobal{allocator_arg}% +\begin{itemdecl} +namespace std { + struct allocator_arg_t { explicit allocator_arg_t() = default; }; + inline constexpr allocator_arg_t allocator_arg{}; +} +\end{itemdecl} + +\pnum +The \tcode{allocator_arg_t} struct is an empty class type used as a unique type to +disambiguate constructor and function overloading. Specifically, several types (see +\tcode{tuple}~\ref{tuple}) have constructors with \tcode{allocator_arg_t} as the first +argument, immediately followed by an argument of a type that meets the +\oldconcept{Allocator} requirements (\tref{cpp17.allocator}). + +\rSec2[allocator.uses]{\tcode{uses_allocator}} + +\rSec3[allocator.uses.trait]{\tcode{uses_allocator} trait} + +\indexlibraryglobal{uses_allocator}% +\begin{itemdecl} +template struct uses_allocator; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\remarks +Automatically detects whether \tcode{T} has a nested \tcode{allocator_type} that +is convertible from \tcode{Alloc}. Meets the \oldconcept{BinaryTypeTrait} +requirements\iref{meta.rqmts}. The implementation shall provide a definition that is +derived from \tcode{true_type} if the \grammarterm{qualified-id} \tcode{T::allocator_type} +is valid and denotes a type\iref{temp.deduct} and +\tcode{is_convertible_v != false}, otherwise it shall be +derived from \tcode{false_type}. A program may specialize this template to derive from +\tcode{true_type} for a program-defined type \tcode{T} that does not have a nested +\tcode{allocator_type} but nonetheless can be constructed with an allocator where +either: +\begin{itemize} +\item the first argument of a constructor has type \tcode{allocator_arg_t} and the +second argument has type \tcode{Alloc} or + +\item the last argument of a constructor has type \tcode{Alloc}. +\end{itemize} +\end{itemdescr} + +\rSec3[allocator.uses.construction]{Uses-allocator construction} + +\pnum +\defnx{Uses-allocator construction}{uses-allocator construction} +with allocator \tcode{alloc} and constructor arguments \tcode{args...} +refers to the construction of an object of type \tcode{T} +such that \tcode{alloc} is passed to the constructor of \tcode{T} +if \tcode{T} uses an allocator type compatible with \tcode{alloc}. +When applied to the construction of an object of type \tcode{T}, +it is equivalent to initializing it with the value of the expression +\tcode{make_obj_using_allocator(alloc, args...)}, described below. + +\pnum +The following utility functions support +three conventions for passing \tcode{alloc} to a constructor: +\begin{itemize} +\item + If \tcode{T} does not use an allocator compatible with \tcode{alloc}, + then \tcode{alloc} is ignored. +\item + Otherwise, if \tcode{T} has a constructor invocable as + \tcode{T(allocator_arg, alloc, args...)} (leading-allocator convention), + then uses-allocator construction chooses this constructor form. +\item + Otherwise, if \tcode{T} has a constructor invocable as + \tcode{T(args..., alloc)} (trailing-allocator convention), + then uses-allocator construction chooses this constructor form. +\end{itemize} + +\pnum +The \tcode{uses_allocator_construction_args} function template +takes an allocator and argument list and +produces (as a tuple) a new argument list matching one of the above conventions. +Additionally, overloads are provided +that treat specializations of \tcode{pair} +such that uses-allocator construction is applied individually +to the \tcode{first} and \tcode{second} data members. +The \tcode{make_obj_using_allocator} and +\tcode{uninitialized_construct_using_allocator} function templates +apply the modified constructor arguments +to construct an object of type \tcode{T} +as a return value or in-place, respectively. +\begin{note} +For \tcode{uses_allocator_construction_args} and +\tcode{make_obj_using_allocator}, type \tcode{T} +is not deduced and must therefore be specified explicitly by the caller. +\end{note} + +\indexlibraryglobal{uses_allocator_construction_args}% +\begin{itemdecl} +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + Args&&... args) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is not a specialization of \tcode{pair}. + +\pnum +\returns +A \tcode{tuple} value determined as follows: +\begin{itemize} +\item + If \tcode{uses_allocator_v} is \tcode{false} and + \tcode{is_constructible_v} is \tcode{true}, + return \tcode{forward_as_tuple(std::forward(args)...)}. +\item + Otherwise, if \tcode{uses_allocator_v} is \tcode{true} and + \tcode{is_constructible_v} + is \tcode{true}, + return +\begin{codeblock} +tuple( + allocator_arg, alloc, std::forward(args)...) +\end{codeblock} +\item + Otherwise, if \tcode{uses_allocator_v} is \tcode{true} and + \tcode{is_constructible_v} is \tcode{true}, + return \tcode{forward_as_tuple(std::forward(args)..., alloc)}. +\item + Otherwise, the program is ill-formed. +\end{itemize} +\begin{note} +This definition prevents a silent failure +to pass the allocator to a constructor of a type for which +\tcode{uses_allocator_v} is \tcode{true}. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{uses_allocator_construction_args}% +\begin{itemdecl} +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, + Tuple1&& x, Tuple2&& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is a specialization of \tcode{pair}. + +\pnum +\effects +For \tcode{T} specified as \tcode{pair}, equivalent to: +\begin{codeblock} +return make_tuple( + piecewise_construct, + apply([&alloc](auto&&... args1) { + return uses_allocator_construction_args( + alloc, std::forward(args1)...); + }, std::forward(x)), + apply([&alloc](auto&&... args2) { + return uses_allocator_construction_args( + alloc, std::forward(args2)...); + }, std::forward(y))); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{uses_allocator_construction_args}% +\begin{itemdecl} +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is a specialization of \tcode{pair}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +return uses_allocator_construction_args(alloc, piecewise_construct, + tuple<>{}, tuple<>{}); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{uses_allocator_construction_args}% +\begin{itemdecl} +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + U&& u, V&& v) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is a specialization of \tcode{pair}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +return uses_allocator_construction_args(alloc, piecewise_construct, + forward_as_tuple(std::forward(u)), + forward_as_tuple(std::forward(v))); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{uses_allocator_construction_args}% +\begin{itemdecl} +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + pair& pr) noexcept; +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + const pair& pr) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is a specialization of \tcode{pair}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +return uses_allocator_construction_args(alloc, piecewise_construct, + forward_as_tuple(pr.first), + forward_as_tuple(pr.second)); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{uses_allocator_construction_args}% +\begin{itemdecl} +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + pair&& pr) noexcept; +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + const pair&& pr) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is a specialization of \tcode{pair}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +return uses_allocator_construction_args(alloc, piecewise_construct, + forward_as_tuple(get<0>(std::move(pr))), + forward_as_tuple(get<1>(std::move(pr)))); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{uses_allocator_construction_args}% +\begin{itemdecl} +template + constexpr auto uses_allocator_construction_args(const Alloc& alloc, U&& u) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \exposid{FUN} be the function template: +\begin{codeblock} +template + void @\exposid{FUN}@(const pair&); +\end{codeblock} + +\pnum +\constraints +\tcode{T} is a specialization of \tcode{pair}, and +the expression \tcode{\exposid{FUN}(u)} is not well-formed +when considered as an unevaluated operand. + +\pnum +Let \exposid{pair-constructor} be an exposition-only class defined as follows: + +\begin{codeblock} +class @\exposid{pair-constructor}@ { + using @\exposid{pair-type}@ = remove_cv_t; // \expos + + constexpr auto @\exposid{do-construct}@(const @\exposid{pair-type}@& p) const { // \expos + return make_obj_using_allocator<@\exposid{pair-type}@>(@\exposid{alloc_}@, p); + } + constexpr auto @\exposid{do-construct}@(@\exposid{pair-type}@&& p) const { // \expos + return make_obj_using_allocator<@\exposid{pair-type}@>(@\exposid{alloc_}@, std::move(p)); + } + + const Alloc& @\exposid{alloc_}@; // \expos + U& @\exposid{u_}@; // \expos + +public: + constexpr operator @\exposid{pair-type}@() const { + return @\exposid{do-construct}@(std::forward(@\exposid{u_}@)); + } +}; +\end{codeblock} + +\pnum +\returns +\tcode{make_tuple(pc)}, +where \tcode{pc} is a \exposid{pair-constructor} object +whose \exposid{alloc_} member is initialized with \tcode{alloc} and +whose \exposid{u_} member is initialized with \tcode{u}. +\end{itemdescr} + +\indexlibraryglobal{make_obj_using_allocator}% +\begin{itemdecl} +template + constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return make_from_tuple(uses_allocator_construction_args( + alloc, std::forward(args)...)); +\end{codeblock} +\end{itemdescr} + +\indexlibraryglobal{uninitialized_construct_using_allocator}% +\begin{itemdecl} +template + constexpr T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return apply([&](U&&... xs) { + return construct_at(p, std::forward(xs)...); + }, uses_allocator_construction_args(alloc, std::forward(args)...)); +\end{codeblock} +\end{itemdescr} + +\rSec2[allocator.traits]{Allocator traits} + +\rSec3[allocator.traits.general]{General} + +\pnum +The class template \tcode{allocator_traits} supplies a uniform interface to all +allocator types. +An allocator cannot be a non-class type, however, even if \tcode{allocator_traits} +supplies the entire required interface. +\begin{note} +Thus, it is always possible to create +a derived class from an allocator. +\end{note} + +\indexlibraryglobal{allocator_traits}% +\begin{codeblock} +namespace std { + template struct allocator_traits { + using allocator_type = Alloc; + + using value_type = typename Alloc::value_type; + + using pointer = @\seebelow@; + using const_pointer = @\seebelow@; + using void_pointer = @\seebelow@; + using const_void_pointer = @\seebelow@; + + using difference_type = @\seebelow@; + using size_type = @\seebelow@; + + using propagate_on_container_copy_assignment = @\seebelow@; + using propagate_on_container_move_assignment = @\seebelow@; + using propagate_on_container_swap = @\seebelow@; + using is_always_equal = @\seebelow@; + + template using rebind_alloc = @\seebelow@; + template using rebind_traits = allocator_traits>; + + [[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n); + [[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n, + const_void_pointer hint); + + static constexpr void deallocate(Alloc& a, pointer p, size_type n); + + template + static constexpr void construct(Alloc& a, T* p, Args&&... args); + + template + static constexpr void destroy(Alloc& a, T* p); + + static constexpr size_type max_size(const Alloc& a) noexcept; + + static constexpr Alloc select_on_container_copy_construction(const Alloc& rhs); + }; +} +\end{codeblock} + +\rSec3[allocator.traits.types]{Member types} + +\indexlibrarymember{pointer}{allocator_traits}% +\begin{itemdecl} +using pointer = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ctype \tcode{Alloc::pointer} if +the \grammarterm{qualified-id} \tcode{Alloc::pointer} is valid and denotes a +type\iref{temp.deduct}; otherwise, \tcode{value_type*}. +\end{itemdescr} + +\indexlibrarymember{const_pointer}{allocator_traits}% +\begin{itemdecl} +using const_pointer = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ctype \tcode{Alloc::const_pointer} if +the \grammarterm{qualified-id} \tcode{Alloc::const_pointer} is valid and denotes a +type\iref{temp.deduct}; otherwise, +\tcode{pointer_traits::rebind<\brk{}const value_type>}. +\end{itemdescr} + +\indexlibrarymember{void_pointer}{allocator_traits}% +\begin{itemdecl} +using void_pointer = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ctype \tcode{Alloc::void_pointer} if +the \grammarterm{qualified-id} \tcode{Alloc::void_pointer} is valid and denotes a +type\iref{temp.deduct}; otherwise, +\tcode{pointer_traits::rebind<\brk{}void>}. +\end{itemdescr} + +\indexlibrarymember{const_void_pointer}{allocator_traits}% +\begin{itemdecl} +using const_void_pointer = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ctype \tcode{Alloc::const_void_pointer} if +the \grammarterm{qualified-id} \tcode{Alloc::const_void_pointer} is valid and denotes a +type\iref{temp.deduct}; otherwise, +\tcode{pointer_traits::\brk{}rebind}. +\end{itemdescr} + +\indexlibrarymember{difference_type}{allocator_traits}% +\begin{itemdecl} +using difference_type = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ctype \tcode{Alloc::difference_type} if +the \grammarterm{qualified-id} \tcode{Alloc::difference_type} is valid and denotes a +type\iref{temp.deduct}; otherwise, +\tcode{pointer_traits::dif\-ference_type}. +\end{itemdescr} + +\indexlibrarymember{size_type}{allocator_traits}% +\begin{itemdecl} +using size_type = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ctype \tcode{Alloc::size_type} if +the \grammarterm{qualified-id} \tcode{Alloc::size_type} is valid and denotes a +type\iref{temp.deduct}; otherwise, +\tcode{make_unsigned_t}. +\end{itemdescr} + +\indexlibrarymember{propagate_on_container_copy_assignment}{allocator_traits}% +\begin{itemdecl} +using propagate_on_container_copy_assignment = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ctype \tcode{Alloc::propagate_on_container_copy_assignment} if +the \grammarterm{qualified-id} \tcode{Alloc::propagate_on_container_copy_assignment} is valid and denotes a +type\iref{temp.deduct}; otherwise +\tcode{false_type}. +\end{itemdescr} + +\indexlibrarymember{propagate_on_container_move_assignment}{allocator_traits}% +\begin{itemdecl} +using propagate_on_container_move_assignment = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ctype \tcode{Alloc::propagate_on_container_move_assignment} if +the \grammarterm{qualified-id} \tcode{Alloc::propagate_on_container_move_assignment} is valid and denotes a +type\iref{temp.deduct}; otherwise +\tcode{false_type}. +\end{itemdescr} + +\indexlibrarymember{propagate_on_container_swap}{allocator_traits}% +\begin{itemdecl} +using propagate_on_container_swap = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ctype \tcode{Alloc::propagate_on_container_swap} if +the \grammarterm{qualified-id} \tcode{Alloc::propagate_on_container_swap} is valid and denotes a +type\iref{temp.deduct}; otherwise +\tcode{false_type}. +\end{itemdescr} + +\indexlibrarymember{is_always_equal}{allocator_traits}% +\begin{itemdecl} +using is_always_equal = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ctype \tcode{Alloc::is_always_equal} if +the \grammarterm{qualified-id} \tcode{Alloc::is_always_equal} +is valid and denotes a type\iref{temp.deduct}; +otherwise \tcode{is_empty::type}. +\end{itemdescr} + +\indexlibrarymember{rebind_alloc}{allocator_traits}% +\begin{itemdecl} +template using rebind_alloc = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\templalias \tcode{Alloc::rebind::other} if +the \grammarterm{qualified-id} \tcode{Alloc::rebind::other} is valid and denotes a +type\iref{temp.deduct}; otherwise, +\tcode{Alloc} if \tcode{Alloc} is a class template instantiation +of the form \tcode{Alloc}, where \tcode{Args} is zero or more type arguments; +otherwise, the instantiation of \tcode{rebind_alloc} is ill-formed. +\end{itemdescr} + +\rSec3[allocator.traits.members]{Static member functions} + +\indexlibrarymember{allocate}{allocator_traits}% +\begin{itemdecl} +[[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{a.allocate(n)}. +\end{itemdescr} + +\indexlibrarymember{allocate}{allocator_traits}% +\begin{itemdecl} +[[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n, const_void_pointer hint); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{a.allocate(n, hint)} if that expression is well-formed; otherwise, \tcode{a.allocate(n)}. +\end{itemdescr} + +\indexlibrarymember{deallocate}{allocator_traits}% +\begin{itemdecl} +static constexpr void deallocate(Alloc& a, pointer p, size_type n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Calls \tcode{a.deallocate(p, n)}. + +\pnum +\throws +Nothing. +\end{itemdescr} + +\indexlibrarymember{construct}{allocator_traits}% +\begin{itemdecl} +template + static constexpr void construct(Alloc& a, T* p, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Calls \tcode{a.construct(p, std::forward(args)...)} +if that call is well-formed; +otherwise, invokes \tcode{construct_at(p, std::forward(args)...)}. +\end{itemdescr} + +\indexlibrarymember{destroy}{allocator_traits}% +\begin{itemdecl} +template + static constexpr void destroy(Alloc& a, T* p); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Calls \tcode{a.destroy(p)} if that call is well-formed; otherwise, invokes +\tcode{destroy_at(p)}. +\end{itemdescr} + +\indexlibrarymember{max_size}{allocator_traits}% +\begin{itemdecl} +static constexpr size_type max_size(const Alloc& a) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{a.max_size()} if that expression is well-formed; otherwise, +\tcode{numeric_limits::\brk{}max()/sizeof(value_type)}. +\end{itemdescr} + +\indexlibrarymember{select_on_container_copy_construction}{allocator_traits}% +\begin{itemdecl} +static constexpr Alloc select_on_container_copy_construction(const Alloc& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{rhs.select_on_container_copy_construction()} if that expression is +well-formed; otherwise, \tcode{rhs}. +\end{itemdescr} + +\rSec3[allocator.traits.other]{Other} + +\pnum +The class template \tcode{allocation_result} has +the template parameters, data members, and special members specified above. +It has no base classes or members other than those specified. + +\begin{itemdecl} +template +[[nodiscard]] constexpr allocation_result::pointer> + allocate_at_least(Allocator& a, size_t n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{a.allocate_at_least(n)} if that expression is well-formed; +otherwise, \tcode{\{a.allocate(n), n\}}. +\end{itemdescr} + +\rSec2[default.allocator]{The default allocator} + +\rSec3[default.allocator.general]{General} + +\pnum +All specializations of the default allocator meet the +allocator completeness requirements\iref{allocator.requirements.completeness}. + +\indexlibraryglobal{allocator}% +\indexlibrarymember{value_type}{allocator}% +\indexlibrarymember{size_type}{allocator}% +\indexlibrarymember{difference_type}{allocator}% +\indexlibrarymember{propagate_on_container_move_assignment}{allocator}% +\indexlibrarymember{operator=}{allocator}% +\begin{codeblock} +namespace std { + template class allocator { + public: + using value_type = T; + using size_type = size_t; + using difference_type = ptrdiff_t; + using propagate_on_container_move_assignment = true_type; + + constexpr allocator() noexcept; + constexpr allocator(const allocator&) noexcept; + template constexpr allocator(const allocator&) noexcept; + constexpr ~allocator(); + constexpr allocator& operator=(const allocator&) = default; + + [[nodiscard]] constexpr T* allocate(size_t n); + [[nodiscard]] constexpr allocation_result allocate_at_least(size_t n); + constexpr void deallocate(T* p, size_t n); + }; +} +\end{codeblock} + +\pnum +\tcode{allocator_traits>::is_always_equal::value} +is \tcode{true} for any \tcode{T}. + +\rSec3[allocator.members]{Members} + +\pnum +Except for the destructor, member functions of the default allocator shall not introduce +data races\iref{intro.multithread} as a result of concurrent calls to those member +functions from different threads. Calls to these functions that allocate or deallocate a +particular unit of storage shall occur in a single total order, and each such +deallocation call shall happen before the next allocation (if any) in this order. + +\indexlibrarymember{allocate}{allocator}% +\begin{itemdecl} +[[nodiscard]] constexpr T* allocate(size_t n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{T} is not an incomplete type\iref{term.incomplete.type}. + +\pnum +\returns +A pointer to the initial element of an array of \tcode{n} \tcode{T}. + +\pnum +\throws +\tcode{bad_array_new_length} if +\tcode{numeric_limits::max() / sizeof(T) < n}, or +\tcode{bad_alloc} if the storage cannot be obtained. + +\pnum +\remarks +The storage for the array +is obtained by calling \tcode{::operator new}\iref{new.delete}, +but it is unspecified when or how often this +function is called. +This function starts the lifetime of the array object, +but not that of any of the array elements. +\end{itemdescr} + +\indexlibrarymember{allocate_at_least}{allocator}% +\begin{itemdecl} +[[nodiscard]] constexpr allocation_result allocate_at_least(size_t n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{T} is not an incomplete type\iref{term.incomplete.type}. + +\pnum +\returns +\tcode{allocation_result\{ptr, count\}}, +where \tcode{ptr} is a pointer to +the initial element of an array of \tcode{count} \tcode{T} and +$\tcode{count} \geq \tcode{n}$. + +\pnum +\throws +\tcode{bad_array_new_length} +if $\tcode{numeric_limits::max() / sizeof(T)} < \tcode{n}$, +or \tcode{bad_alloc} if the storage cannot be obtained. + +\pnum +\remarks +The storage for the array is obtained by calling \tcode{::operator new}, +but it is unspecified when or how often this function is called. +This function starts the lifetime of the array object, +but not that of any of the array elements. +\end{itemdescr} + +\indexlibrarymember{deallocate}{allocator}% +\begin{itemdecl} +constexpr void deallocate(T* p, size_t n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\begin{itemize} +\item +If \tcode{p} is memory that was obtained by a call to \tcode{allocate_at_least}, +let \tcode{ret} be the value returned and +\tcode{req} be the value passed as the first argument to that call. +\tcode{p} is equal to \tcode{ret.ptr} and +\tcode{n} is a value such that $\tcode{req} \leq \tcode{n} \leq \tcode{ret.count}$. +\item +Otherwise, \tcode{p} is a pointer value obtained from \tcode{allocate}. +\tcode{n} equals the value passed as the first argument +to the invocation of \tcode{allocate} which returned \tcode{p}. +\end{itemize} + +\pnum +\effects +Deallocates the storage referenced by \tcode{p}. + +\pnum +\remarks +Uses +\tcode{::operator delete}\iref{new.delete}, +but it is unspecified +when this function is called. +\end{itemdescr} + +\rSec3[allocator.globals]{Operators} + +\indexlibrarymember{operator==}{allocator}% +\begin{itemdecl} +template + constexpr bool operator==(const allocator&, const allocator&) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true}. +\end{itemdescr} + +\rSec2[specialized.addressof]{\tcode{addressof}} + +\indexlibraryglobal{addressof}% +\begin{itemdecl} +template constexpr T* addressof(T& r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The actual address of the object or function referenced by \tcode{r}, even in the +presence of an overloaded \tcode{operator\&}. + +\pnum +\remarks +An expression \tcode{addressof(E)} +is a constant subexpression\iref{defns.const.subexpr} +if \tcode{E} is an lvalue constant subexpression. +\end{itemdescr} + +\rSec2[c.malloc]{C library memory allocation} + +\pnum +\begin{note} +The header \libheaderref{cstdlib} +declares the functions described in this subclause. +\end{note} + +\indexlibraryglobal{aligned_alloc}% +\indexlibraryglobal{calloc}% +\indexlibraryglobal{malloc}% +\indexlibraryglobal{realloc}% +\begin{itemdecl} +void* aligned_alloc(size_t alignment, size_t size); +void* calloc(size_t nmemb, size_t size); +void* malloc(size_t size); +void* realloc(void* ptr, size_t size); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +These functions have the semantics specified in the C standard library. + +\pnum +\remarks +These functions do not attempt to allocate +storage by calling \tcode{::operator new()}\iref{new.delete}. +\indexlibrarymember{new}{operator}% + +\pnum +These functions implicitly create objects\iref{intro.object} +in the returned region of storage and +return a pointer to a suitable created object. +In the case of \tcode{calloc} and \tcode{realloc}, +the objects are created before the storage is zeroed or copied, respectively. +\end{itemdescr} + +\indexlibraryglobal{free}% +\begin{itemdecl} +void free(void* ptr); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +This function has the semantics specified in the C standard library. + +\pnum +\remarks +This function does not attempt to +deallocate storage by calling +\tcode{::operator delete()}\indexlibrarymember{delete}{operator}. +\end{itemdescr} + +\xrefc{7.22.3} + +\rSec1[smartptr]{Smart pointers} + +\rSec2[unique.ptr]{Unique-ownership pointers} + +\rSec3[unique.ptr.general]{General} + +\pnum +A \defn{unique pointer} is an object that owns another object and +manages that other object through a pointer. More precisely, a unique pointer +is an object \textit{u} that stores a pointer to a second object \textit{p} and +will dispose of \textit{p} when \textit{u} is itself destroyed (e.g., when +leaving block scope\iref{stmt.dcl}). In this context, \textit{u} is said +to \defn{own} \tcode{p}. + +\pnum +The mechanism by which \textit{u} disposes of \textit{p} is known as +\textit{p}'s associated \defn{deleter}, a function object whose correct +invocation results in \textit{p}'s appropriate disposition (typically its deletion). + +\pnum +Let the notation \textit{u.p} denote the pointer stored by \textit{u}, and +let \textit{u.d} denote the associated deleter. Upon request, \textit{u} can +\defn{reset} (replace) \textit{u.p} and \textit{u.d} with another pointer and +deleter, but properly disposes of its owned object via the associated +deleter before such replacement is considered completed. + +\pnum +Each object of a type \tcode{U} instantiated from the \tcode{unique_ptr} template +specified in \ref{unique.ptr} has the strict ownership semantics, specified above, +of a unique pointer. In partial satisfaction of these semantics, each such \tcode{U} +is \oldconcept{MoveConstructible} and \oldconcept{MoveAssignable}, but is not +\oldconcept{CopyConstructible} nor \oldconcept{CopyAssignable}. +The template parameter \tcode{T} of \tcode{unique_ptr} may be an incomplete type. + +\pnum +\begin{note} +The uses +of \tcode{unique_ptr} include providing exception safety for +dynamically allocated memory, passing ownership of dynamically allocated +memory to a function, and returning dynamically allocated memory from a +function. +\end{note} + +\rSec3[unique.ptr.dltr]{Default deleters} + +\rSec4[unique.ptr.dltr.general]{In general} + +\pnum +The class template \tcode{default_delete} serves as the default deleter (destruction policy) +for the class template \tcode{unique_ptr}. + +\pnum +The template parameter \tcode{T} of \tcode{default_delete} may be +an incomplete type. + +\rSec4[unique.ptr.dltr.dflt]{\tcode{default_delete}} + +\begin{codeblock} +namespace std { + template struct default_delete { + constexpr default_delete() noexcept = default; + template constexpr default_delete(const default_delete&) noexcept; + constexpr void operator()(T*) const; + }; +} +\end{codeblock} + +\indexlibraryctor{default_delete}% +\begin{itemdecl} +template constexpr default_delete(const default_delete& other) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{U*} is implicitly convertible to \tcode{T*}. + +\pnum +\effects +Constructs a \tcode{default_delete} object +from another \tcode{default_delete} object. +\end{itemdescr} + +\indexlibrarymember{operator()}{default_delete}% +\begin{itemdecl} +constexpr void operator()(T* ptr) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{T} is a complete type. + +\pnum +\effects +Calls \keyword{delete} on \tcode{ptr}. +\end{itemdescr} + +\rSec4[unique.ptr.dltr.dflt1]{\tcode{default_delete}} + +\begin{codeblock} +namespace std { + template struct default_delete { + constexpr default_delete() noexcept = default; + template constexpr default_delete(const default_delete&) noexcept; + template constexpr void operator()(U* ptr) const; + }; +} +\end{codeblock} + +\indexlibraryctor{default_delete} +\begin{itemdecl} +template constexpr default_delete(const default_delete& other) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{U(*)[]} is convertible to \tcode{T(*)[]}. + +\pnum +\effects +Constructs a \tcode{default_delete} object from another \tcode{default_delete} object. +\end{itemdescr} + +\indexlibrarymember{operator()}{default_delete}% +\begin{itemdecl} +template constexpr void operator()(U* ptr) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{U(*)[]} is convertible to \tcode{T(*)[]}. + +\pnum +\mandates +\tcode{U} is a complete type. + +\pnum +\effects +Calls \tcode{delete[]} on \tcode{ptr}. +\end{itemdescr} + +\rSec3[unique.ptr.single]{\tcode{unique_ptr} for single objects} + +\rSec4[unique.ptr.single.general]{General} + +\indexlibraryglobal{unique_ptr}% +\begin{codeblock} +namespace std { + template> class unique_ptr { + public: + using pointer = @\seebelow@; + using element_type = T; + using deleter_type = D; + + // \ref{unique.ptr.single.ctor}, constructors + constexpr unique_ptr() noexcept; + constexpr explicit unique_ptr(type_identity_t p) noexcept; + constexpr unique_ptr(type_identity_t p, @\seebelow@ d1) noexcept; + constexpr unique_ptr(type_identity_t p, @\seebelow@ d2) noexcept; + constexpr unique_ptr(unique_ptr&& u) noexcept; + constexpr unique_ptr(nullptr_t) noexcept; + template + constexpr unique_ptr(unique_ptr&& u) noexcept; + + // \ref{unique.ptr.single.dtor}, destructor + constexpr ~unique_ptr(); + + // \ref{unique.ptr.single.asgn}, assignment + constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; + template + constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; + constexpr unique_ptr& operator=(nullptr_t) noexcept; + + // \ref{unique.ptr.single.observers}, observers + constexpr add_lvalue_reference_t operator*() const noexcept(@\seebelow@); + constexpr pointer operator->() const noexcept; + constexpr pointer get() const noexcept; + constexpr deleter_type& get_deleter() noexcept; + constexpr const deleter_type& get_deleter() const noexcept; + constexpr explicit operator bool() const noexcept; + + // \ref{unique.ptr.single.modifiers}, modifiers + constexpr pointer release() noexcept; + constexpr void reset(pointer p = pointer()) noexcept; + constexpr void swap(unique_ptr& u) noexcept; + + // disable copy from lvalue + unique_ptr(const unique_ptr&) = delete; + unique_ptr& operator=(const unique_ptr&) = delete; + }; +} +\end{codeblock} + +\pnum +The default type for the template parameter \tcode{D} is +\tcode{default_delete}. A client-supplied template argument +\tcode{D} shall be a function +object type\iref{function.objects}, lvalue reference to function, or +lvalue reference to function object type +for which, given +a value \tcode{d} of type \tcode{D} and a value +\tcode{ptr} of type \tcode{unique_ptr::pointer}, the expression +\tcode{d(ptr)} is valid and has the effect of disposing of the +pointer as appropriate for that deleter. + +\pnum +If the deleter's type \tcode{D} is not a reference type, \tcode{D} shall meet +the \oldconcept{Destructible} requirements (\tref{cpp17.destructible}). + +\pnum +If the \grammarterm{qualified-id} \tcode{remove_reference_t::pointer} is valid and denotes a +type\iref{temp.deduct}, then \tcode{unique_ptr::pointer} shall be a synonym for \tcode{remove_reference_t::pointer}. Otherwise +\tcode{unique_ptr::pointer} shall be a synonym for \tcode{element_type*}. The type \tcode{unique_ptr::pointer} shall +meet the \oldconcept{NullablePointer} requirements (\tref{cpp17.nullablepointer}). + +\pnum +\begin{example} +Given an allocator type \tcode{X} (\tref{cpp17.allocator}) and +letting \tcode{A} be a synonym for \tcode{allocator_traits}, the types \tcode{A::pointer}, +\tcode{A::const_pointer}, \tcode{A::void_pointer}, and \tcode{A::const_void_pointer} +may be used as \tcode{unique_ptr::pointer}. +\end{example} + +\rSec4[unique.ptr.single.ctor]{Constructors} + +\indexlibraryctor{unique_ptr}% +\begin{itemdecl} +constexpr unique_ptr() noexcept; +constexpr unique_ptr(nullptr_t) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_pointer_v} is \tcode{false} and +\tcode{is_default_constructible_v} is \tcode{true}. + +\pnum +\expects +\tcode{D} meets the \oldconcept{DefaultConstructible} requirements (\tref{cpp17.defaultconstructible}), +and that construction does not throw an exception. + +\pnum +\effects +Constructs a \tcode{unique_ptr} object that owns +nothing, value-initializing the stored pointer and the stored deleter. + +\pnum +\ensures +\tcode{get() == nullptr}. \tcode{get_deleter()} +returns a reference to the stored deleter. +\end{itemdescr} + +\indexlibraryctor{unique_ptr}% +\begin{itemdecl} +constexpr explicit unique_ptr(type_identity_t p) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_pointer_v} is \tcode{false} and +\tcode{is_default_constructible_v} is \tcode{true}. + +\pnum +\expects +\tcode{D} meets the \oldconcept{DefaultConstructible} requirements (\tref{cpp17.defaultconstructible}), +and that construction does not throw an exception. + +\pnum +\effects +Constructs a \tcode{unique_ptr} which owns +\tcode{p}, initializing the stored pointer with \tcode{p} and +value-initializing the stored deleter. + +\pnum +\ensures +\tcode{get() == p}. \tcode{get_deleter()} +returns a reference to the stored deleter. +\end{itemdescr} + +\indexlibraryctor{unique_ptr}% +\begin{itemdecl} +constexpr unique_ptr(type_identity_t p, const D& d) noexcept; +constexpr unique_ptr(type_identity_t p, remove_reference_t&& d) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\expects +For the first constructor, if \tcode{D} is not a reference type, +\tcode{D} meets the \oldconcept{CopyConstructible} requirements and +such construction does not exit via an exception. +For the second constructor, if \tcode{D} is not a reference type, +\tcode{D} meets the \oldconcept{MoveConstructible} requirements and +such construction does not exit via an exception. + +\pnum +\effects +Constructs a \tcode{unique_ptr} object which owns \tcode{p}, initializing +the stored pointer with \tcode{p} and initializing the deleter +from \tcode{std::forward(d)}. + +\pnum +\ensures +\tcode{get() == p}. +\tcode{get_deleter()} returns a reference to the stored +deleter. If \tcode{D} is a reference type then \tcode{get_deleter()} +returns a reference to the lvalue \tcode{d}. + +\pnum +\remarks +If \tcode{D} is a reference type, +the second constructor is defined as deleted. + +\pnum +\begin{example} +\begin{codeblock} +D d; +unique_ptr p1(new int, D()); // \tcode{D} must be \oldconcept{MoveConstructible} +unique_ptr p2(new int, d); // \tcode{D} must be \oldconcept{CopyConstructible} +unique_ptr p3(new int, d); // \tcode{p3} holds a reference to \tcode{d} +unique_ptr p4(new int, D()); // error: rvalue deleter object combined + // with reference deleter type +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryctor{unique_ptr}% +\begin{itemdecl} +constexpr unique_ptr(unique_ptr&& u) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_move_constructible_v} is \tcode{true}. + +\pnum +\expects +If \tcode{D} is not a reference type, +\tcode{D} meets the \oldconcept{MoveConstructible} +requirements (\tref{cpp17.moveconstructible}). +Construction +of the deleter from an rvalue of type \tcode{D} does not +throw an exception. + +\pnum +\effects +Constructs a \tcode{unique_ptr} from +\tcode{u}. If \tcode{D} is a reference type, this +deleter is copy constructed from \tcode{u}'s deleter; otherwise, this +deleter is move constructed from \tcode{u}'s deleter. +\begin{note} +The +construction of the deleter can be implemented with \tcode{std::forward}. +\end{note} + +\pnum +\ensures +\tcode{get()} yields the value \tcode{u.get()} +yielded before the construction. \tcode{u.get() == nullptr}. +\tcode{get_deleter()} returns a reference +to the stored deleter that was constructed from +\tcode{u.get_deleter()}. If \tcode{D} is a reference type then +\tcode{get_deleter()} and \tcode{u.get_deleter()} both reference +the same lvalue deleter. +\end{itemdescr} + +\indexlibraryctor{unique_ptr}% +\begin{itemdecl} +template constexpr unique_ptr(unique_ptr&& u) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item \tcode{unique_ptr::pointer} is implicitly convertible to \tcode{pointer}, +\item \tcode{U} is not an array type, and +\item either \tcode{D} is a reference type and \tcode{E} is the same type as \tcode{D}, or +\tcode{D} is not a reference type and \tcode{E} is implicitly convertible to \tcode{D}. +\end{itemize} + +\pnum +\expects +If \tcode{E} is not a reference type, +construction of the deleter from an rvalue of type \tcode{E} +is well-formed and does not throw an exception. +Otherwise, \tcode{E} is a reference type and +construction of the deleter from an lvalue of type \tcode{E} +is well-formed and does not throw an exception. + +\pnum +\effects +Constructs a \tcode{unique_ptr} from \tcode{u}. +If \tcode{E} is a reference type, this deleter is copy constructed from +\tcode{u}'s deleter; otherwise, this deleter is move constructed from \tcode{u}'s +deleter. +\begin{note} +The deleter constructor can be implemented with +\tcode{std::forward}. +\end{note} + +\pnum +\ensures +\tcode{get()} yields the value \tcode{u.get()} +yielded before the construction. \tcode{u.get() == nullptr}. +\tcode{get_deleter()} returns a reference +to the stored deleter that was constructed from +\tcode{u.get_deleter()}. +\end{itemdescr} + +\rSec4[unique.ptr.single.dtor]{Destructor} + +\indexlibrarydtor{unique_ptr}% +\begin{itemdecl} +constexpr ~unique_ptr(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{if (get()) get_deleter()(get());} +\begin{note} +The use of \tcode{default_delete} requires \tcode{T} to be a complete type. +\end{note} + +\pnum +\remarks +The behavior is undefined +if the evaluation of \tcode{get_deleter()(get())} throws an exception. +\end{itemdescr} + +\rSec4[unique.ptr.single.asgn]{Assignment} + +\indexlibrarymember{operator=}{unique_ptr}% +\begin{itemdecl} +constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_move_assignable_v} is \tcode{true}. + +\pnum +\expects +If \tcode{D} is not a reference type, \tcode{D} meets the +\oldconcept{MoveAssignable} requirements (\tref{cpp17.moveassignable}) and assignment +of the deleter from an rvalue of type \tcode{D} does not throw an exception. +Otherwise, \tcode{D} is a reference type; +\tcode{remove_reference_t} meets the \oldconcept{CopyAssignable} +requirements and assignment of the deleter from an +lvalue of type \tcode{D} does not throw an exception. + +\pnum +\effects +Calls \tcode{reset(u.release())} followed by +\tcode{get_deleter() = std::forward(u.get_dele\-ter())}. + +\pnum +\ensures +If \tcode{this != addressof(u)}, +\tcode{u.get() == nullptr}, +otherwise \tcode{u.get()} is unchanged. + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + +\indexlibrarymember{operator=}{unique_ptr}% +\begin{itemdecl} +template constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item \tcode{unique_ptr::pointer} is implicitly convertible to \tcode{pointer}, and +\item \tcode{U} is not an array type, and +\item \tcode{is_assignable_v} is \tcode{true}. +\end{itemize} + +\pnum +\expects +If \tcode{E} is not a reference type, +assignment of the deleter from an rvalue of type \tcode{E} +is well-formed and does not throw an exception. +Otherwise, \tcode{E} is a reference type and +assignment of the deleter from an lvalue of type \tcode{E} +is well-formed and does not throw an exception. + +\pnum +\effects +Calls \tcode{reset(u.release())} followed by +\tcode{get_deleter() = std::forward(u.get_dele\-ter())}. + +\pnum +\ensures +\tcode{u.get() == nullptr}. + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + +\indexlibrarymember{operator=}{unique_ptr}% +\begin{itemdecl} +constexpr unique_ptr& operator=(nullptr_t) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +As if by \tcode{reset()}. + +\pnum +\ensures +\tcode{get() == nullptr}. + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + +\rSec4[unique.ptr.single.observers]{Observers} + +\indexlibrarymember{operator*}{unique_ptr}% +\begin{itemdecl} +constexpr add_lvalue_reference_t operator*() const noexcept(noexcept(*declval())); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{get() != nullptr}. + +\pnum +\returns +\tcode{*get()}. + +\end{itemdescr} + +\indexlibrarymember{operator->}{unique_ptr}% +\begin{itemdecl} +constexpr pointer operator->() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{get() != nullptr}. + +\pnum +\returns +\tcode{get()}. + +\pnum +\begin{note} +The use of this function typically requires that \tcode{T} be a complete type. +\end{note} +\end{itemdescr} + +\indexlibrarymember{get}{unique_ptr}% +\begin{itemdecl} +constexpr pointer get() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The stored pointer. +\end{itemdescr} + +\indexlibrarymember{get_deleter}{unique_ptr}% +\begin{itemdecl} +constexpr deleter_type& get_deleter() noexcept; +constexpr const deleter_type& get_deleter() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A reference to the stored deleter. +\end{itemdescr} + +\indexlibrarymember{operator bool}{unique_ptr}% +\begin{itemdecl} +constexpr explicit operator bool() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{get() != nullptr}. +\end{itemdescr} + +\rSec4[unique.ptr.single.modifiers]{Modifiers} + +\indexlibrarymember{release}{unique_ptr}% +\begin{itemdecl} +constexpr pointer release() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures +\tcode{get() == nullptr}. + +\pnum +\returns +The value \tcode{get()} had at the start of +the call to \tcode{release}. +\end{itemdescr} + +\indexlibrarymember{reset}{unique_ptr}% +\begin{itemdecl} +constexpr void reset(pointer p = pointer()) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Assigns \tcode{p} to the stored pointer, and then, +with the old value of the stored pointer, \tcode{old_p}, +evaluates \tcode{if (old_p) get_deleter()(old_p);} +\begin{note} +The order of these operations is significant +because the call to \tcode{get_deleter()} might destroy \tcode{*this}. +\end{note} + +\pnum +\ensures +\tcode{get() == p}. +\begin{note} +The postcondition does not hold if the call to \tcode{get_deleter()} +destroys \tcode{*this} since \tcode{this->get()} is no longer a valid expression. +\end{note} + +\pnum +\remarks +The behavior is undefined +if the evaluation of \tcode{get_deleter()(old_p)} throws an exception. +\end{itemdescr} + +\indexlibrarymember{swap}{unique_ptr}% +\begin{itemdecl} +constexpr void swap(unique_ptr& u) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{get_deleter()} is swappable\iref{swappable.requirements} and +does not throw an exception under \tcode{swap}. + +\pnum +\effects +Invokes \tcode{swap} on the stored pointers and on the stored +deleters of \tcode{*this} and \tcode{u}. +\end{itemdescr} + +\rSec3[unique.ptr.runtime]{\tcode{unique_ptr} for array objects with a runtime length} + +\rSec4[unique.ptr.runtime.general]{General} + +\indexlibraryglobal{unique_ptr}% +\begin{codeblock} +namespace std { + template class unique_ptr { + public: + using pointer = @\seebelow@; + using element_type = T; + using deleter_type = D; + + // \ref{unique.ptr.runtime.ctor}, constructors + constexpr unique_ptr() noexcept; + template constexpr explicit unique_ptr(U p) noexcept; + template constexpr unique_ptr(U p, @\seebelow@ d) noexcept; + template constexpr unique_ptr(U p, @\seebelow@ d) noexcept; + constexpr unique_ptr(unique_ptr&& u) noexcept; + template + constexpr unique_ptr(unique_ptr&& u) noexcept; + constexpr unique_ptr(nullptr_t) noexcept; + + // destructor + constexpr ~unique_ptr(); + + // assignment + constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; + template + constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; + constexpr unique_ptr& operator=(nullptr_t) noexcept; + + // \ref{unique.ptr.runtime.observers}, observers + constexpr T& operator[](size_t i) const; + constexpr pointer get() const noexcept; + constexpr deleter_type& get_deleter() noexcept; + constexpr const deleter_type& get_deleter() const noexcept; + constexpr explicit operator bool() const noexcept; + + // \ref{unique.ptr.runtime.modifiers}, modifiers + constexpr pointer release() noexcept; + template constexpr void reset(U p) noexcept; + constexpr void reset(nullptr_t = nullptr) noexcept; + constexpr void swap(unique_ptr& u) noexcept; + + // disable copy from lvalue + unique_ptr(const unique_ptr&) = delete; + unique_ptr& operator=(const unique_ptr&) = delete; + }; +} +\end{codeblock} + +\pnum +A specialization for array types is provided with a slightly altered +interface. + +\begin{itemize} +\item Conversions between different types of +\tcode{unique_ptr} +that would be disallowed for the corresponding pointer-to-array types, +and conversions to or from the non-array forms of +\tcode{unique_ptr}, produce an ill-formed program. + +\item Pointers to types derived from \tcode{T} are +rejected by the constructors, and by \tcode{reset}. + +\item The observers \tcode{operator*} and +\tcode{operator->} are not provided. + +\item The indexing observer \tcode{operator[]} is provided. + +\item The default deleter will call \tcode{delete[]}. +\end{itemize} + +\pnum +Descriptions are provided below only for members that +differ from the primary template. + +\pnum +The template argument \tcode{T} shall be a complete type. + +\rSec4[unique.ptr.runtime.ctor]{Constructors} + +\indexlibraryctor{unique_ptr}% +\begin{itemdecl} +template constexpr explicit unique_ptr(U p) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +This constructor behaves the same as +the constructor in the primary template that +takes a single parameter of type \tcode{pointer}. + +\pnum +\constraints +\begin{itemize} +\item \tcode{U} is the same type as \tcode{pointer}, or +\item \tcode{pointer} is the same type as \tcode{element_type*}, +\tcode{U} is a pointer type \tcode{V*}, and +\tcode{V(*)[]} is convertible to \tcode{element_type(*)[]}. +\end{itemize} +\end{itemdescr} + +\indexlibraryctor{unique_ptr}% +\begin{itemdecl} +template constexpr unique_ptr(U p, @\seebelow@ d) noexcept; +template constexpr unique_ptr(U p, @\seebelow@ d) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +These constructors behave the same as +the constructors in the primary template that +take a parameter of type \tcode{pointer} and a second parameter. + +\pnum +\constraints +\begin{itemize} +\item \tcode{U} is the same type as \tcode{pointer}, +\item \tcode{U} is \tcode{nullptr_t}, or +\item \tcode{pointer} is the same type as \tcode{element_type*}, + \tcode{U} is a pointer type \tcode{V*}, and + \tcode{V(*)[]} is convertible to \tcode{element_type(*)[]}. +\end{itemize} +\end{itemdescr} + +\indexlibraryctor{unique_ptr}% +\begin{itemdecl} +template constexpr unique_ptr(unique_ptr&& u) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +This constructor behaves the same as in the primary template. + +\pnum +\constraints +Where \tcode{UP} is \tcode{unique_ptr}: +\begin{itemize} +\item \tcode{U} is an array type, and +\item \tcode{pointer} is the same type as \tcode{element_type*}, and +\item \tcode{UP::pointer} is the same type as \tcode{UP::element_type*}, and +\item \tcode{UP::element_type(*)[]} is convertible to \tcode{element_type(*)[]}, and +\item either \tcode{D} is a reference type and \tcode{E} is the same type as \tcode{D}, + or \tcode{D} is not a reference type and \tcode{E} is implicitly convertible to \tcode{D}. +\end{itemize} + +\begin{note} +This replaces the \constraints specification of the primary template. +\end{note} +\end{itemdescr} + +\rSec4[unique.ptr.runtime.asgn]{Assignment} + +\indexlibrarymember{operator=}{unique_ptr}% +\begin{itemdecl} +template constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +This operator behaves the same as in the primary template. + +\pnum +\constraints +Where \tcode{UP} is \tcode{unique_ptr}: +\begin{itemize} +\item \tcode{U} is an array type, and +\item \tcode{pointer} is the same type as \tcode{element_type*}, and +\item \tcode{UP::pointer} is the same type as \tcode{UP::element_type*}, and +\item \tcode{UP::element_type(*)[]} is convertible to \tcode{element_type(*)[]}, and +\item \tcode{is_assignable_v} is \tcode{true}. +\end{itemize} + +\begin{note} +This replaces the \constraints specification of the primary template. +\end{note} +\end{itemdescr} + +\rSec4[unique.ptr.runtime.observers]{Observers} + +\indexlibrarymember{operator[]}{unique_ptr}% +\begin{itemdecl} +constexpr T& operator[](size_t i) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +$\tcode{i} <$ the +number of elements in the array to which +the stored pointer points. + +\pnum +\returns +\tcode{get()[i]}. +\end{itemdescr} + +\rSec4[unique.ptr.runtime.modifiers]{Modifiers} + +\indexlibrarymember{reset}{unique_ptr}% +\begin{itemdecl} +constexpr void reset(nullptr_t p = nullptr) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{reset(pointer())}. +\end{itemdescr} + +\indexlibrarymember{reset}{unique_ptr}% +\begin{itemdecl} +constexpr template void reset(U p) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +This function behaves the same as +the \tcode{reset} member of the primary template. + +\pnum +\constraints +\begin{itemize} +\item \tcode{U} is the same type as \tcode{pointer}, or +\item \tcode{pointer} is the same type as \tcode{element_type*}, + \tcode{U} is a pointer type \tcode{V*}, and + \tcode{V(*)[]} is convertible to \tcode{element_type(*)[]}. +\end{itemize} +\end{itemdescr} + +\rSec3[unique.ptr.create]{Creation} + +\indexlibraryglobal{make_unique}% +\begin{itemdecl} +template constexpr unique_ptr make_unique(Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is not an array type. + +\pnum +\returns +\tcode{unique_ptr(new T(std::forward(args)...))}. + +\end{itemdescr} + +\indexlibraryglobal{make_unique}% +\begin{itemdecl} +template constexpr unique_ptr make_unique(size_t n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an array of unknown bound. + +\pnum +\returns +\tcode{unique_ptr(new remove_extent_t[n]())}. + +\end{itemdescr} + +\indexlibraryglobal{make_unique}% +\begin{itemdecl} +template @\unspec@ make_unique(Args&&...) = delete; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an array of known bound. + +\end{itemdescr} + +\indexlibraryglobal{make_unique}% +\begin{itemdecl} +template constexpr unique_ptr make_unique_for_overwrite(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is not an array type. + +\pnum +\returns +\tcode{unique_ptr(new T)}. +\end{itemdescr} + +\indexlibraryglobal{make_unique}% +\begin{itemdecl} +template constexpr unique_ptr make_unique_for_overwrite(size_t n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an array of unknown bound. + +\pnum +\returns +\tcode{unique_ptr(new remove_extent_t[n])}. +\end{itemdescr} + +\indexlibraryglobal{make_unique}% +\begin{itemdecl} +template @\unspec@ make_unique_for_overwrite(Args&&...) = delete; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an array of known bound. +\end{itemdescr} + +\rSec3[unique.ptr.special]{Specialized algorithms} + +\indexlibrary{\idxcode{swap(unique_ptr\&, unique_ptr\&)}}% +\begin{itemdecl} +template constexpr void swap(unique_ptr& x, unique_ptr& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_swappable_v} is \tcode{true}. + +\pnum +\effects +Calls \tcode{x.swap(y)}. +\end{itemdescr} + +\indexlibrarymember{operator==}{unique_ptr}% +\begin{itemdecl} +template + constexpr bool operator==(const unique_ptr& x, const unique_ptr& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{x.get() == y.get()}. +\end{itemdescr} + +\indexlibrarymember{operator<}{unique_ptr}% +\begin{itemdecl} +template + bool operator<(const unique_ptr& x, const unique_ptr& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{CT} denote +\begin{codeblock} +common_type_t::pointer, + typename unique_ptr::pointer> +\end{codeblock} + +\pnum +\mandates +\begin{itemize} +\item \tcode{unique_ptr::pointer} is implicitly convertible to \tcode{CT} and +\item \tcode{unique_ptr::pointer} is implicitly convertible to \tcode{CT}. +\end{itemize} + +\pnum +\expects +The specialization +\tcode{less} is a function object type\iref{function.objects} that +induces a strict weak ordering\iref{alg.sorting} on the pointer values. + +\pnum +\returns +\tcode{less()(x.get(), y.get())}. +\end{itemdescr} + +\indexlibrarymember{operator>}{unique_ptr}% +\begin{itemdecl} +template + bool operator>(const unique_ptr& x, const unique_ptr& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{y < x}. +\end{itemdescr} + +\indexlibrarymember{operator<=}{unique_ptr}% +\begin{itemdecl} +template + bool operator<=(const unique_ptr& x, const unique_ptr& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{!(y < x)}. +\end{itemdescr} + +\indexlibrarymember{operator>=}{unique_ptr}% +\begin{itemdecl} +template + bool operator>=(const unique_ptr& x, const unique_ptr& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{!(x < y)}. +\end{itemdescr} + +\indexlibrarymember{operator<=>}{unique_ptr}% +\begin{itemdecl} +template + requires @\libconcept{three_way_comparable_with}@::pointer, + typename unique_ptr::pointer> + compare_three_way_result_t::pointer, + typename unique_ptr::pointer> + operator<=>(const unique_ptr& x, const unique_ptr& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{compare_three_way()(x.get(), y.get())}. +\end{itemdescr} + +\indexlibrarymember{operator==}{unique_ptr}% +\begin{itemdecl} +template + constexpr bool operator==(const unique_ptr& x, nullptr_t) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{!x}. +\end{itemdescr} + +\indexlibrarymember{operator<}{unique_ptr}% +\begin{itemdecl} +template + constexpr bool operator<(const unique_ptr& x, nullptr_t); +template + constexpr bool operator<(nullptr_t, const unique_ptr& x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +The specialization \tcode{less::pointer>} is +a function object type\iref{function.objects} that induces a strict weak +ordering\iref{alg.sorting} on the pointer values. + +\pnum +\returns +The first function template returns +\begin{codeblock} +less::pointer>()(x.get(), nullptr) +\end{codeblock} +The second function template returns +\begin{codeblock} +less::pointer>()(nullptr, x.get()) +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator>}{unique_ptr}% +\begin{itemdecl} +template + constexpr bool operator>(const unique_ptr& x, nullptr_t); +template + constexpr bool operator>(nullptr_t, const unique_ptr& x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The first function template returns \tcode{nullptr < x}. +The second function template returns \tcode{x < nullptr}. +\end{itemdescr} + +\indexlibrarymember{operator<=}{unique_ptr}% +\begin{itemdecl} +template + constexpr bool operator<=(const unique_ptr& x, nullptr_t); +template + constexpr bool operator<=(nullptr_t, const unique_ptr& x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The first function template returns \tcode{!(nullptr < x)}. +The second function template returns \tcode{!(x < nullptr)}. +\end{itemdescr} + +\indexlibrarymember{operator>=}{unique_ptr}% +\begin{itemdecl} +template + constexpr bool operator>=(const unique_ptr& x, nullptr_t); +template + constexpr bool operator>=(nullptr_t, const unique_ptr& x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The first function template returns \tcode{!(x < nullptr)}. +The second function template returns \tcode{!(nullptr < x)}. +\end{itemdescr} + +\indexlibrarymember{operator<=>}{unique_ptr}% +\begin{itemdecl} +template + requires @\libconcept{three_way_comparable}@::pointer> + constexpr compare_three_way_result_t::pointer> + operator<=>(const unique_ptr& x, nullptr_t); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\begin{codeblock} +compare_three_way()(x.get(), static_cast::pointer>(nullptr)). +\end{codeblock} +\end{itemdescr} + +\rSec3[unique.ptr.io]{I/O} + +\indexlibrarymember{operator<<}{unique_ptr}% +\begin{itemdecl} +template + basic_ostream& operator<<(basic_ostream& os, const unique_ptr& p); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{os << p.get()} is a valid expression. + +\pnum +\effects +Equivalent to: \tcode{os << p.get();} + +\pnum +\returns +\tcode{os}. +\end{itemdescr} + +\rSec2[util.sharedptr]{Shared-ownership pointers} + +\rSec3[util.smartptr.weak.bad]{Class \tcode{bad_weak_ptr}}% +\indextext{smart pointers|(}% + +\indexlibraryglobal{bad_weak_ptr}% +\begin{codeblock} +namespace std { + class bad_weak_ptr : public exception { + public: + // see \ref{exception} for the specification of the special member functions + const char* what() const noexcept override; + }; +} +\end{codeblock} + +\pnum +An exception of type \tcode{bad_weak_ptr} is thrown by the \tcode{shared_ptr} +constructor taking a \tcode{weak_ptr}. + +\indexlibrarymember{what}{bad_weak_ptr}% +\begin{itemdecl} +const char* what() const noexcept override; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An \impldef{return value of \tcode{bad_weak_ptr::what}} \ntbs{}. +\end{itemdescr} + +\rSec3[util.smartptr.shared]{Class template \tcode{shared_ptr}} + +\rSec4[util.smartptr.shared.general]{General} + +\pnum +\indexlibraryglobal{shared_ptr}% +The \tcode{shared_ptr} class template stores a pointer, usually obtained +via \keyword{new}. \tcode{shared_ptr} implements semantics of shared ownership; +the last remaining owner of the pointer is responsible for destroying +the object, or otherwise releasing the resources associated with the stored pointer. A +\tcode{shared_ptr} is said to be empty if it does not own a pointer. + +\begin{codeblock} +namespace std { + template class shared_ptr { + public: + using element_type = remove_extent_t; + using weak_type = weak_ptr; + + // \ref{util.smartptr.shared.const}, constructors + constexpr shared_ptr() noexcept; + constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { } + template + explicit shared_ptr(Y* p); + template + shared_ptr(Y* p, D d); + template + shared_ptr(Y* p, D d, A a); + template + shared_ptr(nullptr_t p, D d); + template + shared_ptr(nullptr_t p, D d, A a); + template + shared_ptr(const shared_ptr& r, element_type* p) noexcept; + template + shared_ptr(shared_ptr&& r, element_type* p) noexcept; + shared_ptr(const shared_ptr& r) noexcept; + template + shared_ptr(const shared_ptr& r) noexcept; + shared_ptr(shared_ptr&& r) noexcept; + template + shared_ptr(shared_ptr&& r) noexcept; + template + explicit shared_ptr(const weak_ptr& r); + template + shared_ptr(unique_ptr&& r); + + // \ref{util.smartptr.shared.dest}, destructor + ~shared_ptr(); + + // \ref{util.smartptr.shared.assign}, assignment + shared_ptr& operator=(const shared_ptr& r) noexcept; + template + shared_ptr& operator=(const shared_ptr& r) noexcept; + shared_ptr& operator=(shared_ptr&& r) noexcept; + template + shared_ptr& operator=(shared_ptr&& r) noexcept; + template + shared_ptr& operator=(unique_ptr&& r); + + // \ref{util.smartptr.shared.mod}, modifiers + void swap(shared_ptr& r) noexcept; + void reset() noexcept; + template + void reset(Y* p); + template + void reset(Y* p, D d); + template + void reset(Y* p, D d, A a); + + // \ref{util.smartptr.shared.obs}, observers + element_type* get() const noexcept; + T& operator*() const noexcept; + T* operator->() const noexcept; + element_type& operator[](ptrdiff_t i) const; + long use_count() const noexcept; + explicit operator bool() const noexcept; + template + bool owner_before(const shared_ptr& b) const noexcept; + template + bool owner_before(const weak_ptr& b) const noexcept; + }; + + template + shared_ptr(weak_ptr) -> shared_ptr; + template + shared_ptr(unique_ptr) -> shared_ptr; +} +\end{codeblock} + +\pnum +Specializations of \tcode{shared_ptr} shall be \oldconcept{CopyConstructible}, +\oldconcept{CopyAssignable}, and \oldconcept{\-Less\-Than\-Comparable}, allowing their use in standard +containers. Specializations of \tcode{shared_ptr} shall be +contextually convertible to \tcode{bool}, +allowing their use in boolean expressions and declarations in conditions. + +\pnum +The template parameter \tcode{T} of \tcode{shared_ptr} +may be an incomplete type. +\begin{note} +\tcode{T} can be a function type. +\end{note} + +\pnum +\begin{example} +\begin{codeblock} +if (shared_ptr px = dynamic_pointer_cast(py)) { + // do something with \tcode{px} +} +\end{codeblock} +\end{example} + +\pnum +For purposes of determining the presence of a data race, member functions shall +access and modify only the \tcode{shared_ptr} and \tcode{weak_ptr} objects +themselves and not objects they refer to. Changes in \tcode{use_count()} do not +reflect modifications that can introduce data races. + +\pnum +For the purposes of subclause \ref{smartptr}, +a pointer type \tcode{Y*} is said to be +\defnx{compatible with}{compatible with!\idxcode{shared_ptr}} +a pointer type \tcode{T*} when either +\tcode{Y*} is convertible to \tcode{T*} or +\tcode{Y} is \tcode{U[N]} and \tcode{T} is \cv{}~\tcode{U[]}. + +\rSec4[util.smartptr.shared.const]{Constructors} + +\pnum +In the constructor definitions below, +enables \tcode{shared_from_this} with \tcode{p}, +for a pointer \tcode{p} of type \tcode{Y*}, +means that if \tcode{Y} has an unambiguous and accessible base class +that is a specialization of \tcode{enable_shared_from_this}\iref{util.smartptr.enab}, +then \tcode{remove_cv_t*} shall be implicitly convertible to \tcode{T*} and +the constructor evaluates the statement: +\begin{codeblock} +if (p != nullptr && p->weak_this.expired()) + p->weak_this = shared_ptr>(*this, const_cast*>(p)); +\end{codeblock} +The assignment to the \tcode{weak_this} member is not atomic and +conflicts with any potentially concurrent access to the same object\iref{intro.multithread}. + +\indexlibraryctor{shared_ptr}% +\begin{itemdecl} +constexpr shared_ptr() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures +\tcode{use_count() == 0 \&\& get() == nullptr}. +\end{itemdescr} + +\indexlibraryctor{shared_ptr}% +\begin{itemdecl} +template explicit shared_ptr(Y* p); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +When \tcode{T} is an array type, +the expression \tcode{delete[] p} is well-formed and either +\tcode{T} is \tcode{U[N]} and \tcode{Y(*)[N]} is convertible to \tcode{T*}, or +\tcode{T} is \tcode{U[]} and \tcode{Y(*)[]} is convertible to \tcode{T*}. +When \tcode{T} is not an array type, +the expression \tcode{delete p} is well-formed and +\tcode{Y*} is convertible to \tcode{T*}. + +\pnum +\mandates +\tcode{Y} is a complete type. + +\pnum +\expects +The expression +\tcode{delete[] p}, when \tcode{T} is an array type, or +\tcode{delete p}, when \tcode{T} is not an array type, +has well-defined behavior, and +does not throw exceptions. + +\pnum +\effects +When \tcode{T} is not an array type, +constructs a \tcode{shared_ptr} object +that owns the pointer \tcode{p}. +Otherwise, constructs a \tcode{shared_ptr} +that owns \tcode{p} and a deleter of an +unspecified type that calls \tcode{delete[] p}. +When \tcode{T} is not an array type, +enables \tcode{shared_from_this} with \tcode{p}. +If an exception is thrown, \tcode{delete p} is called +when \tcode{T} is not an array type, \tcode{delete[] p} otherwise. + +\pnum +\ensures +\tcode{use_count() == 1 \&\& get() == p}. + +\pnum +\throws +\tcode{bad_alloc}, or an \impldef{exception type when \tcode{shared_ptr} +constructor fails} exception when a resource other than memory cannot be obtained. +\end{itemdescr} + +\indexlibraryctor{shared_ptr}% +\begin{itemdecl} +template shared_ptr(Y* p, D d); +template shared_ptr(Y* p, D d, A a); +template shared_ptr(nullptr_t p, D d); +template shared_ptr(nullptr_t p, D d, A a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_move_constructible_v} is \tcode{true}, and +\tcode{d(p)} is a well-formed expression. +For the first two overloads: + +\begin{itemize} +\item +If \tcode{T} is an array type, then either +\tcode{T} is \tcode{U[N]} and \tcode{Y(*)[N]} is convertible to \tcode{T*}, or +\tcode{T} is \tcode{U[]} and \tcode{Y(*)[]} is convertible to \tcode{T*}. + +\item +If \tcode{T} is not an array type, then \tcode{Y*} is convertible to \tcode{T*}. +\end{itemize} + +\pnum +\expects +Construction of \tcode{d} and a deleter of type \tcode{D} +initialized with \tcode{std::move(d)} do not throw exceptions. +The expression \tcode{d(p)} +has well-defined behavior and does not throw exceptions. +\tcode{A} meets the \oldconcept{Allocator} requirements (\tref{cpp17.allocator}). + +\pnum +\effects +Constructs a \tcode{shared_ptr} object that owns the +object \tcode{p} and the deleter \tcode{d}. +When \tcode{T} is not an array type, +the first and second constructors enable \tcode{shared_from_this} with \tcode{p}. +The second and fourth constructors shall use a copy of \tcode{a} to +allocate memory for internal use. +If an exception is thrown, \tcode{d(p)} is called. + +\pnum +\ensures +\tcode{use_count() == 1 \&\& get() == p}. + +\pnum +\throws +\tcode{bad_alloc}, or an \impldef{exception type when \tcode{shared_ptr} +constructor fails} exception +when a resource other than memory cannot be obtained. +\end{itemdescr} + +\indexlibraryctor{shared_ptr}% +\begin{itemdecl} +template shared_ptr(const shared_ptr& r, element_type* p) noexcept; +template shared_ptr(shared_ptr&& r, element_type* p) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Constructs a \tcode{shared_ptr} instance that +stores \tcode{p} and shares ownership with +the initial value of \tcode{r}. + +\pnum +\ensures +\tcode{get() == p}. +For the second overload, +\tcode{r} is empty and \tcode{r.get() == nullptr}. + +\pnum +\begin{note} +Use of this constructor leads to a dangling pointer +unless \tcode{p} remains valid +at least until the ownership group of \tcode{r} is destroyed. +\end{note} + +\pnum +\begin{note} +This constructor allows creation of an empty +\tcode{shared_ptr} instance with a non-null stored pointer. +\end{note} +\end{itemdescr} + +\indexlibraryctor{shared_ptr}% +\begin{itemdecl} +shared_ptr(const shared_ptr& r) noexcept; +template shared_ptr(const shared_ptr& r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the second constructor, \tcode{Y*} is compatible with \tcode{T*}. + +\pnum +\effects +If \tcode{r} is empty, constructs +an empty \tcode{shared_ptr} object; otherwise, constructs +a \tcode{shared_ptr} object that shares ownership with \tcode{r}. + +\pnum +\ensures +\tcode{get() == r.get() \&\& use_count() == r.use_count()}. +\end{itemdescr} + +\indexlibraryctor{shared_ptr}% +\begin{itemdecl} +shared_ptr(shared_ptr&& r) noexcept; +template shared_ptr(shared_ptr&& r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the second constructor, \tcode{Y*} is compatible with \tcode{T*}. + +\pnum +\effects +Move constructs a \tcode{shared_ptr} instance from \tcode{r}. + +\pnum +\ensures +\tcode{*this} contains the old value of +\tcode{r}. \tcode{r} is empty, and \tcode{r.get() == nullptr}. +\end{itemdescr} + +\indexlibraryctor{shared_ptr}% +\indexlibraryglobal{weak_ptr}% +\begin{itemdecl} +template explicit shared_ptr(const weak_ptr& r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{Y*} is compatible with \tcode{T*}. + +\pnum +\effects +Constructs a \tcode{shared_ptr} object that shares ownership with +\tcode{r} and stores a copy of the pointer stored in \tcode{r}. +If an exception is thrown, the constructor has no effect. + +\pnum +\ensures +\tcode{use_count() == r.use_count()}. + +\pnum +\throws +\tcode{bad_weak_ptr} when \tcode{r.expired()}. +\end{itemdescr} + +\indexlibraryctor{shared_ptr}% +\indexlibraryglobal{unique_ptr}% +\begin{itemdecl} +template shared_ptr(unique_ptr&& r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{Y*} is compatible with \tcode{T*} and +\tcode{unique_ptr::pointer} is convertible to \tcode{element_type*}. + +\pnum +\effects +If \tcode{r.get() == nullptr}, equivalent to \tcode{shared_ptr()}. +Otherwise, if \tcode{D} is not a reference type, +equivalent to \tcode{shared_ptr(r.release(), std::move(r.get_deleter()))}. +Otherwise, equivalent to \tcode{shared_ptr(r.release(), ref(r.get_deleter()))}. +If an exception is thrown, the constructor has no effect. +\end{itemdescr} + +\rSec4[util.smartptr.shared.dest]{Destructor} + +\indexlibrarydtor{shared_ptr}% +\begin{itemdecl} +~shared_ptr(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +\begin{itemize} +\item If \tcode{*this} is empty or shares ownership with another +\tcode{shared_ptr} instance (\tcode{use_count() > 1}), there are no side effects. + +\item +Otherwise, if \tcode{*this} owns an object +\tcode{p} and a deleter \tcode{d}, \tcode{d(p)} is called. + +\item Otherwise, \tcode{*this} owns a pointer \tcode{p}, +and \tcode{delete p} is called. +\end{itemize} +\end{itemdescr} + +\pnum +\begin{note} +Since the destruction of \tcode{*this} +decreases the number of instances that share ownership with \tcode{*this} +by one, +after \tcode{*this} has been destroyed +all \tcode{shared_ptr} instances that shared ownership with +\tcode{*this} will report a \tcode{use_count()} that is one less +than its previous value. +\end{note} + +\rSec4[util.smartptr.shared.assign]{Assignment} + +\indexlibrarymember{operator=}{shared_ptr}% +\begin{itemdecl} +shared_ptr& operator=(const shared_ptr& r) noexcept; +template shared_ptr& operator=(const shared_ptr& r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{shared_ptr(r).swap(*this)}. + +\pnum +\returns +\tcode{*this}. + +\pnum +\begin{note} +The use count updates caused by the temporary object +construction and destruction are not observable side +effects, so the implementation can meet the effects (and the +implied guarantees) via different means, without creating a +temporary. In particular, in the example: +\begin{codeblock} +shared_ptr p(new int); +shared_ptr q(p); +p = p; +q = p; +\end{codeblock} +both assignments can be no-ops. +\end{note} +\end{itemdescr} + +\indexlibrarymember{operator=}{shared_ptr}% +\begin{itemdecl} +shared_ptr& operator=(shared_ptr&& r) noexcept; +template shared_ptr& operator=(shared_ptr&& r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{shared_ptr(std::move(r)).swap(*this)}. + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + +\indexlibrarymember{operator=}{shared_ptr}% +\begin{itemdecl} +template shared_ptr& operator=(unique_ptr&& r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{shared_ptr(std::move(r)).swap(*this)}. + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + +\rSec4[util.smartptr.shared.mod]{Modifiers} + +\indexlibrarymember{swap}{shared_ptr}% +\begin{itemdecl} +void swap(shared_ptr& r) noexcept; +\end{itemdecl} + +\begin{itemdescr} + +\pnum +\effects +Exchanges the contents of \tcode{*this} and \tcode{r}. +\end{itemdescr} + +\indexlibrarymember{reset}{shared_ptr}% +\begin{itemdecl} +void reset() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{shared_ptr().swap(*this)}. +\end{itemdescr} + +\indexlibrarymember{reset}{shared_ptr}% +\begin{itemdecl} +template void reset(Y* p); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{shared_ptr(p).swap(*this)}. +\end{itemdescr} + +\indexlibrarymember{reset}{shared_ptr}% +\begin{itemdecl} +template void reset(Y* p, D d); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{shared_ptr(p, d).swap(*this)}. +\end{itemdescr} + +\indexlibrarymember{reset}{shared_ptr}% +\begin{itemdecl} +template void reset(Y* p, D d, A a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{shared_ptr(p, d, a).swap(*this)}. +\end{itemdescr} + +\rSec4[util.smartptr.shared.obs]{Observers} +\indexlibrarymember{get}{shared_ptr}% +\begin{itemdecl} +element_type* get() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The stored pointer. +\end{itemdescr} + +\indexlibrarymember{operator*}{shared_ptr}% +\begin{itemdecl} +T& operator*() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{get() != 0}. + +\pnum +\returns +\tcode{*get()}. + +\pnum +\remarks +When \tcode{T} is an array type or \cv{}~\keyword{void}, +it is unspecified whether this +member function is declared. If it is declared, it is unspecified what its +return type is, except that the declaration (although not necessarily the +definition) of the function shall be well-formed. +\end{itemdescr} + +\indexlibrarymember{operator->}{shared_ptr}% +\begin{itemdecl} +T* operator->() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{get() != 0}. + +\pnum +\returns +\tcode{get()}. + +\pnum +\remarks +When \tcode{T} is an array type, +it is unspecified whether this member function is declared. +If it is declared, it is unspecified what its return type is, +except that the declaration (although not necessarily the definition) +of the function shall be well-formed. +\end{itemdescr} + +\indexlibrarymember{operator[]}{shared_ptr}% +\begin{itemdecl} +element_type& operator[](ptrdiff_t i) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{get() != 0 \&\& i >= 0}. +If \tcode{T} is \tcode{U[N]}, \tcode{i < N}. + +\pnum +\returns +\tcode{get()[i]}. + +\pnum +\throws +Nothing. + +\pnum +\remarks +When \tcode{T} is not an array type, +it is unspecified whether this member function is declared. +If it is declared, it is unspecified what its return type is, +except that the declaration (although not necessarily the definition) +of the function shall be well-formed. +\end{itemdescr} + +\indexlibrarymember{use_count}{shared_ptr}% +\begin{itemdecl} +long use_count() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\sync +None. + +\pnum +\returns +The number of \tcode{shared_ptr} objects, \tcode{*this} included, +that share ownership with \tcode{*this}, or \tcode{0} when \tcode{*this} is +empty. + +\pnum +\begin{note} +\tcode{get() == nullptr} +does not imply a specific return value of \tcode{use_count()}. +\end{note} + +\pnum +\begin{note} +\tcode{weak_ptr::lock()} +can affect the return value of \tcode{use_count()}. +\end{note} + +\pnum +\begin{note} +When multiple threads +might affect the return value of \tcode{use_count()}, +the result is approximate. +In particular, \tcode{use_count() == 1} does not imply that accesses through +a previously destroyed \tcode{shared_ptr} have in any sense completed. +\end{note} +\end{itemdescr} + +\indexlibrarymember{operator bool}{shared_ptr}% +\begin{itemdecl} +explicit operator bool() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{get() != 0}. +\end{itemdescr} + +\indexlibrarymember{owner_before}{shared_ptr}% +\begin{itemdecl} +template bool owner_before(const shared_ptr& b) const noexcept; +template bool owner_before(const weak_ptr& b) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An unspecified value such that +\begin{itemize} +\item \tcode{x.owner_before(y)} defines a strict weak ordering as defined in~\ref{alg.sorting}; + +\item under the equivalence relation defined by \tcode{owner_before}, +\tcode{!a.owner_before(b) \&\& !b.owner_before(a)}, two \tcode{shared_ptr} or +\tcode{weak_ptr} instances are equivalent if and only if they share ownership or +are both empty. +\end{itemize} + +\end{itemdescr} + +\rSec4[util.smartptr.shared.create]{Creation} + +\pnum +The common requirements that apply to all +\tcode{make_shared}, +\tcode{allocate_shared}, +\tcode{make_shared_for_overwrite}, and +\tcode{allocate_shared_for_overwrite} overloads, +unless specified otherwise, are described below. + +\indexlibraryglobal{make_shared}% +\indexlibraryglobal{allocate_shared}% +\begin{itemdecl} +template + shared_ptr make_shared(@\placeholdernc{args}@); +template + shared_ptr allocate_shared(const A& a, @\placeholdernc{args}@); +template + shared_ptr make_shared_for_overwrite(@\placeholdernc{args}@); +template + shared_ptr allocate_shared_for_overwrite(const A& a, @\placeholdernc{args}@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{A} meets the \oldconcept{Allocator} requirements (\tref{cpp17.allocator}). + +\pnum +\effects +Allocates memory for an object of type \tcode{T} +(or \tcode{U[N]} when \tcode{T} is \tcode{U[]}, +where \tcode{N} is determined from \placeholder{args} as specified by the concrete overload). +The object is initialized from \placeholder{args} as specified by the concrete overload. +The \tcode{allocate_shared} and \tcode{allocate_shared_for_overwrite} templates +use a copy of \tcode{a} +(rebound for an unspecified \tcode{value_type}) to allocate memory. +If an exception is thrown, the functions have no effect. + +\pnum +\ensures +\tcode{r.get() != 0 \&\& r.use_count() == 1}, +where \tcode{r} is the return value. + +\pnum +\returns +A \tcode{shared_ptr} instance that stores and owns the address of +the newly constructed object. + +\pnum +\throws +\tcode{bad_alloc}, or +an exception thrown from \tcode{allocate} or from the initialization of the object. + +\pnum +\remarks +\begin{itemize} +\item + Implementations should perform no more than one memory allocation. + \begin{note} + This provides efficiency equivalent to an intrusive smart pointer. + \end{note} +\item + When an object of an array type \tcode{U} is specified to have + an initial value of \tcode{u} (of the same type), + this shall be interpreted to mean that + each array element of the object has as its initial value + the corresponding element from \tcode{u}. +\item + When an object of an array type is specified to have + a default initial value, + this shall be interpreted to mean that each array element of the object + has a default initial value. +\item + When a (sub)object of a non-array type \tcode{U} is specified to have + an initial value of \tcode{v}, or \tcode{U(l...)}, + where \tcode{l...} is a list of constructor arguments, + \tcode{make_shared} shall initialize this (sub)object + via the expression \tcode{::new(pv) U(v)} or \tcode{::new(pv) U(l...)} respectively, + where \tcode{pv} has type \tcode{void*} and points to storage + suitable to hold an object of type \tcode{U}. +\item + When a (sub)object of a non-array type \tcode{U} is specified to have + an initial value of \tcode{v}, or \tcode{U(l...)}, + where \tcode{l...} is a list of constructor arguments, + \tcode{allocate_shared} shall initialize this (sub)object + via the expression + \begin{itemize} + \item \tcode{allocator_traits::construct(a2, pv, v)} or + \item \tcode{allocator_traits::construct(a2, pv, l...)} + \end{itemize} + respectively, + where \tcode{pv} points to storage + suitable to hold an object of type \tcode{U} and + \tcode{a2} of type \tcode{A2} is a rebound copy of + the allocator \tcode{a} passed to \tcode{allocate_shared} + such that its \tcode{value_type} is \tcode{remove_cv_t}. +\item + When a (sub)object of non-array type \tcode{U} is specified to have + a default initial value, + \tcode{make_shared} shall initialize this (sub)object + via the expression \tcode{::new(pv) U()}, + where \tcode{pv} has type \tcode{void*} and points to storage + suitable to hold an object of type \tcode{U}. +\item + When a (sub)object of non-array type \tcode{U} is specified to have + a default initial value, + \tcode{allocate_shared} shall initialize this (sub)object + via the expression \tcode{allocator_traits::construct(a2, pv)}, + where \tcode{pv} points to storage + suitable to hold an object of type \tcode{U} and + \tcode{a2} of type \tcode{A2} is a rebound copy of + the allocator \tcode{a} passed to \tcode{allocate_shared} + such that its \tcode{value_type} is \tcode{remove_cv_t}. +\item + When a (sub)object of non-array type \tcode{U} is initialized by + \tcode{make_shared_for_overwrite} or\linebreak % avoid Overfull + \tcode{allocate_shared_for_overwrite}, + it is initialized via the expression \tcode{::new(pv) U}, + where \tcode{pv} has type \tcode{void*} and + points to storage suitable to hold an object of type \tcode{U}. +\item + Array elements are initialized in ascending order of their addresses. +\item + When the lifetime of the object managed by the return value ends, or + when the initialization of an array element throws an exception, + the initialized elements are destroyed in the reverse order + of their original construction. +\item + When a (sub)object of non-array type \tcode{U} + that was initialized by \tcode{make_shared} is to be destroyed, + it is destroyed via the expression \tcode{pv->\~{}U()} where + \tcode{pv} points to that object of type \tcode{U}. +\item + When a (sub)object of non-array type \tcode{U} + that was initialized by \tcode{allocate_shared} is to be destroyed, + it is destroyed via the expression + \tcode{allocator_traits::destroy(a2, pv)} where + \tcode{pv} points to that object of type \tcode{remove_cv_t} and + \tcode{a2} of type \tcode{A2} is a rebound copy of + the allocator \tcode{a} passed to \tcode{allocate_shared} + such that its \tcode{value_type} is \tcode{remove_cv_t}. +\end{itemize} +\begin{note} +These functions will typically allocate more memory than \tcode{sizeof(T)} to +allow for internal bookkeeping structures such as reference counts. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{make_shared}% +\indexlibraryglobal{allocate_shared}% +\begin{itemdecl} +template + shared_ptr make_shared(Args&&... args); // \tcode{T} is not array +template + shared_ptr allocate_shared(const A& a, Args&&... args); // \tcode{T} is not array +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is not an array type. + +\pnum +\returns +A \tcode{shared_ptr} to an object of type \tcode{T} +with an initial value \tcode{T(forward(args)...)}. + +\pnum +\remarks +The \tcode{shared_ptr} constructors called by these functions +enable \tcode{shared_from_this} +with the address of the newly constructed object of type \tcode{T}. + +\pnum +\begin{example} +\begin{codeblock} +shared_ptr p = make_shared(); // \tcode{shared_ptr} to \tcode{int()} +shared_ptr> q = make_shared>(16, 1); + // \tcode{shared_ptr} to vector of \tcode{16} elements with value \tcode{1} +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{make_shared}% +\indexlibraryglobal{allocate_shared}% +\begin{itemdecl} +template shared_ptr + make_shared(size_t N); // \tcode{T} is \tcode{U[]} +template + shared_ptr allocate_shared(const A& a, size_t N); // \tcode{T} is \tcode{U[]} +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is of the form \tcode{U[]}. + +\pnum +\returns +A \tcode{shared_ptr} to an object of type \tcode{U[N]} +with a default initial value, +where \tcode{U} is \tcode{remove_extent_t}. + +\pnum +\begin{example} +\begin{codeblock} +shared_ptr p = make_shared(1024); + // \tcode{shared_ptr} to a value-initialized \tcode{double[1024]} +shared_ptr q = make_shared(6); + // \tcode{shared_ptr} to a value-initialized \tcode{double[6][2][2]} +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{make_shared}% +\indexlibraryglobal{allocate_shared}% +\begin{itemdecl} +template + shared_ptr make_shared(); // \tcode{T} is \tcode{U[N]} +template + shared_ptr allocate_shared(const A& a); // \tcode{T} is \tcode{U[N]} +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is of the form \tcode{U[N]}. + +\pnum +\returns +A \tcode{shared_ptr} to an object of type \tcode{T} +with a default initial value. + +\pnum +\begin{example} +\begin{codeblock} +shared_ptr p = make_shared(); + // \tcode{shared_ptr} to a value-initialized \tcode{double[1024]} +shared_ptr q = make_shared(); + // \tcode{shared_ptr} to a value-initialized \tcode{double[6][2][2]} +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{make_shared}% +\indexlibraryglobal{allocate_shared}% +\begin{itemdecl} +template + shared_ptr make_shared(size_t N, + const remove_extent_t& u); // \tcode{T} is \tcode{U[]} +template + shared_ptr allocate_shared(const A& a, size_t N, + const remove_extent_t& u); // \tcode{T} is \tcode{U[]} +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is of the form \tcode{U[]}. + +\pnum +\returns +A \tcode{shared_ptr} to an object of type \tcode{U[N]}, +where \tcode{U} is \tcode{remove_extent_t} and +each array element has an initial value of \tcode{u}. + +\pnum +\begin{example} +\begin{codeblock} +shared_ptr p = make_shared(1024, 1.0); + // \tcode{shared_ptr} to a \tcode{double[1024]}, where each element is \tcode{1.0} +shared_ptr q = make_shared(6, {1.0, 0.0}); + // \tcode{shared_ptr} to a \tcode{double[6][2]}, where each \tcode{double[2]} element is \tcode{\{1.0, 0.0\}} +shared_ptr[]> r = make_shared[]>(4, {1, 2}); + // \tcode{shared_ptr} to a \tcode{vector[4]}, where each vector has contents \tcode{\{1, 2\}} +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{make_shared}% +\indexlibraryglobal{allocate_shared}% +\begin{itemdecl} +template + shared_ptr make_shared(const remove_extent_t& u); // \tcode{T} is \tcode{U[N]} +template + shared_ptr allocate_shared(const A& a, + const remove_extent_t& u); // \tcode{T} is \tcode{U[N]} +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is of the form \tcode{U[N]}. + +\pnum +\returns +A \tcode{shared_ptr} to an object of type \tcode{T}, +where each array element of type \tcode{remove_extent_t} +has an initial value of \tcode{u}. + +\pnum +\begin{example} +\begin{codeblock} +shared_ptr p = make_shared(1.0); + // \tcode{shared_ptr} to a \tcode{double[1024]}, where each element is \tcode{1.0} +shared_ptr q = make_shared({1.0, 0.0}); + // \tcode{shared_ptr} to a \tcode{double[6][2]}, where each double[2] element is \tcode{\{1.0, 0.0\}} +shared_ptr[4]> r = make_shared[4]>({1, 2}); + // \tcode{shared_ptr} to a \tcode{vector[4]}, where each vector has contents \tcode{\{1, 2\}} +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{make_shared}% +\indexlibraryglobal{allocate_shared}% +\begin{itemdecl} +template + shared_ptr make_shared_for_overwrite(); +template + shared_ptr allocate_shared_for_overwrite(const A& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is not an array of unknown bound. + +\pnum +\returns +A \tcode{shared_ptr} to an object of type \tcode{T}. + +\pnum +\begin{example} +\begin{codeblock} +struct X { double data[1024]; }; +shared_ptr p = make_shared_for_overwrite(); + // \tcode{shared_ptr} to a default-initialized \tcode{X}, where each element in \tcode{X::data} has an indeterminate value + +shared_ptr q = make_shared_for_overwrite(); + // \tcode{shared_ptr} to a default-initialized \tcode{double[1024]}, where each element has an indeterminate value +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{make_shared}% +\indexlibraryglobal{allocate_shared}% +\begin{itemdecl} +template + shared_ptr make_shared_for_overwrite(size_t N); +template + shared_ptr allocate_shared_for_overwrite(const A& a, size_t N); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an array of unknown bound. + +\pnum +\returns +A \tcode{shared_ptr} to an object of type \tcode{U[N]}, +where \tcode{U} is \tcode{remove_extent_t}. + +\pnum +\begin{example} +\begin{codeblock} +shared_ptr p = make_shared_for_overwrite(1024); + // \tcode{shared_ptr} to a default-initialized \tcode{double[1024]}, where each element has an indeterminate value +\end{codeblock} +\end{example} +\end{itemdescr} + +\rSec4[util.smartptr.shared.cmp]{Comparison} + +\indexlibrarymember{operator==}{shared_ptr}% +\begin{itemdecl} +template + bool operator==(const shared_ptr& a, const shared_ptr& b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{a.get() == b.get()}. +\end{itemdescr} + +\indexlibrarymember{operator==}{shared_ptr}% +\begin{itemdecl} +template + bool operator==(const shared_ptr& a, nullptr_t) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{!a}. +\end{itemdescr} + +\indexlibrarymember{operator<=>}{shared_ptr}% +\begin{itemdecl} +template + strong_ordering operator<=>(const shared_ptr& a, const shared_ptr& b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{compare_three_way()(a.get(), b.get())}. + +\pnum +\begin{note} +Defining a comparison operator function allows \tcode{shared_ptr} objects +to be used as keys in associative containers. +\end{note} +\end{itemdescr} + +\indexlibrarymember{operator<=>}{shared_ptr}% +\begin{itemdecl} +template + strong_ordering operator<=>(const shared_ptr& a, nullptr_t) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\begin{codeblock} +compare_three_way()(a.get(), static_cast::element_type*>(nullptr). +\end{codeblock} +\end{itemdescr} + +\rSec4[util.smartptr.shared.spec]{Specialized algorithms} + +\indexlibrarymember{swap}{shared_ptr}% +\begin{itemdecl} +template + void swap(shared_ptr& a, shared_ptr& b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{a.swap(b)}. +\end{itemdescr} + +\rSec4[util.smartptr.shared.cast]{Casts} + +\indexlibrarymember{static_pointer_cast}{shared_ptr}% +\begin{itemdecl} +template + shared_ptr static_pointer_cast(const shared_ptr& r) noexcept; +template + shared_ptr static_pointer_cast(shared_ptr&& r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +The expression \tcode{static_cast((U*)nullptr)} is well-formed. + +\pnum +\returns +\begin{codeblock} +shared_ptr(@\placeholder{R}@, static_cast::element_type*>(r.get())) +\end{codeblock} +where \tcode{\placeholder{R}} is \tcode{r} for the first overload, and +\tcode{std::move(r)} for the second. + +\pnum +\begin{note} +The seemingly equivalent expression +\tcode{shared_ptr(static_cast(r.get()))} +will eventually result in undefined behavior, attempting to delete the +same object twice. +\end{note} +\end{itemdescr} + +\indexlibrarymember{dynamic_pointer_cast}{shared_ptr}% +\begin{itemdecl} +template + shared_ptr dynamic_pointer_cast(const shared_ptr& r) noexcept; +template + shared_ptr dynamic_pointer_cast(shared_ptr&& r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +The expression \tcode{dynamic_cast((U*)nullptr)} is well-formed. +The expression \tcode{dynamic_cast::element_type*>(r.get())} is well-formed. + +\pnum +\expects +The expression \tcode{dynamic_cast::element_type*>(r.get())} has well-defined behavior. + +\pnum +\returns +\begin{itemize} +\item When \tcode{dynamic_cast::element_type*>(r.get())} + returns a non-null value \tcode{p}, + \tcode{shared_ptr(\placeholder{R}, p)}, + where \tcode{\placeholder{R}} is \tcode{r} for the first overload, and + \tcode{std::move(r)} for the second. +\item Otherwise, \tcode{shared_ptr()}. +\end{itemize} + +\pnum +\begin{note} +The seemingly equivalent expression +\tcode{shared_ptr(dynamic_cast(r.get()))} will eventually result in +undefined behavior, attempting to delete the same object twice. +\end{note} +\end{itemdescr} + +\indexlibrarymember{const_pointer_cast}{shared_ptr}% +\begin{itemdecl} +template + shared_ptr const_pointer_cast(const shared_ptr& r) noexcept; +template + shared_ptr const_pointer_cast(shared_ptr&& r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +The expression \tcode{const_cast((U*)nullptr)} is well-formed. + +\pnum +\returns +\begin{codeblock} +shared_ptr(@\placeholder{R}@, const_cast::element_type*>(r.get())) +\end{codeblock} +where \tcode{\placeholder{R}} is \tcode{r} for the first overload, and +\tcode{std::move(r)} for the second. + +\pnum +\begin{note} +The seemingly equivalent expression +\tcode{shared_ptr(const_cast(r.get()))} will eventually result in +undefined behavior, attempting to delete the same object twice. +\end{note} +\end{itemdescr} + +\indexlibrarymember{reinterpret_pointer_cast}{shared_ptr}% +\begin{itemdecl} +template + shared_ptr reinterpret_pointer_cast(const shared_ptr& r) noexcept; +template + shared_ptr reinterpret_pointer_cast(shared_ptr&& r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +The expression \tcode{reinterpret_cast((U*)nullptr)} is well-formed. + +\pnum +\returns +\begin{codeblock} +shared_ptr(@\placeholder{R}@, reinterpret_cast::element_type*>(r.get())) +\end{codeblock} +where \tcode{\placeholder{R}} is \tcode{r} for the first overload, and +\tcode{std::move(r)} for the second. + +\pnum +\begin{note} +The seemingly equivalent expression +\tcode{shared_ptr(reinterpret_cast(r.get()))} will eventually result in +undefined behavior, attempting to delete the same object twice. +\end{note} +\end{itemdescr} + +\rSec4[util.smartptr.getdeleter]{\tcode{get_deleter}} + +\indexlibrarymember{get_deleter}{shared_ptr}% +\begin{itemdecl} +template + D* get_deleter(const shared_ptr& p) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +If \tcode{p} owns a deleter \tcode{d} of type cv-unqualified +\tcode{D}, returns \tcode{addressof(d)}; otherwise returns \keyword{nullptr}. +The returned +pointer remains valid as long as there exists a \tcode{shared_ptr} instance +that owns \tcode{d}. +\begin{note} +It is unspecified whether the pointer +remains valid longer than that. This can happen if the implementation doesn't destroy +the deleter until all \tcode{weak_ptr} instances that share ownership with +\tcode{p} have been destroyed. +\end{note} +\end{itemdescr} + +\rSec4[util.smartptr.shared.io]{I/O} + +\indexlibrarymember{operator<<}{shared_ptr}% +\begin{itemdecl} +template + basic_ostream& operator<<(basic_ostream& os, const shared_ptr& p); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +As if by: \tcode{os <{}< p.get();} + +\pnum +\returns +\tcode{os}. +\end{itemdescr} + +\rSec3[util.smartptr.weak]{Class template \tcode{weak_ptr}} + +\rSec4[util.smartptr.weak.general]{General} + +\pnum +\indexlibraryglobal{weak_ptr}% +The \tcode{weak_ptr} class template stores a weak reference to an object +that is already managed by a \tcode{shared_ptr}. To access the object, a +\tcode{weak_ptr} can be converted to a \tcode{shared_ptr} using the member +function \tcode{lock}. + +\begin{codeblock} +namespace std { + template class weak_ptr { + public: + using element_type = remove_extent_t; + + // \ref{util.smartptr.weak.const}, constructors + constexpr weak_ptr() noexcept; + template + weak_ptr(const shared_ptr& r) noexcept; + weak_ptr(const weak_ptr& r) noexcept; + template + weak_ptr(const weak_ptr& r) noexcept; + weak_ptr(weak_ptr&& r) noexcept; + template + weak_ptr(weak_ptr&& r) noexcept; + + // \ref{util.smartptr.weak.dest}, destructor + ~weak_ptr(); + + // \ref{util.smartptr.weak.assign}, assignment + weak_ptr& operator=(const weak_ptr& r) noexcept; + template + weak_ptr& operator=(const weak_ptr& r) noexcept; + template + weak_ptr& operator=(const shared_ptr& r) noexcept; + weak_ptr& operator=(weak_ptr&& r) noexcept; + template + weak_ptr& operator=(weak_ptr&& r) noexcept; + + // \ref{util.smartptr.weak.mod}, modifiers + void swap(weak_ptr& r) noexcept; + void reset() noexcept; + + // \ref{util.smartptr.weak.obs}, observers + long use_count() const noexcept; + bool expired() const noexcept; + shared_ptr lock() const noexcept; + template + bool owner_before(const shared_ptr& b) const noexcept; + template + bool owner_before(const weak_ptr& b) const noexcept; + }; + + template + weak_ptr(shared_ptr) -> weak_ptr; +} +\end{codeblock} + +\pnum +Specializations of \tcode{weak_ptr} shall be \oldconcept{CopyConstructible} and +\oldconcept{CopyAssignable}, allowing their use in standard +containers. The template parameter \tcode{T} of \tcode{weak_ptr} may be an +incomplete type. + +\rSec4[util.smartptr.weak.const]{Constructors} + +\indexlibraryctor{weak_ptr}% +\begin{itemdecl} +constexpr weak_ptr() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Constructs an empty \tcode{weak_ptr} object that stores a null pointer value. + +\pnum +\ensures +\tcode{use_count() == 0}. +\end{itemdescr} + +\indexlibraryctor{weak_ptr}% +\begin{itemdecl} +weak_ptr(const weak_ptr& r) noexcept; +template weak_ptr(const weak_ptr& r) noexcept; +template weak_ptr(const shared_ptr& r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the second and third constructors, \tcode{Y*} is compatible with \tcode{T*}. + +\pnum +\effects +If \tcode{r} is empty, constructs +an empty \tcode{weak_ptr} object that stores a null pointer value; +otherwise, constructs +a \tcode{weak_ptr} object that shares ownership +with \tcode{r} and stores a copy of the pointer stored in \tcode{r}. + +\pnum +\ensures +\tcode{use_count() == r.use_count()}. +\end{itemdescr} + +\indexlibraryctor{weak_ptr}% +\begin{itemdecl} +weak_ptr(weak_ptr&& r) noexcept; +template weak_ptr(weak_ptr&& r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the second constructor, \tcode{Y*} is compatible with \tcode{T*}. + +\pnum +\effects +Move constructs a \tcode{weak_ptr} instance from \tcode{r}. + +\pnum +\ensures +\tcode{*this} contains the old value of \tcode{r}. +\tcode{r} is empty, stores a null pointer value, and \tcode{r.use_count() == 0}. +\end{itemdescr} + +\rSec4[util.smartptr.weak.dest]{Destructor} + +\indexlibrarydtor{weak_ptr}% +\begin{itemdecl} +~weak_ptr(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Destroys this \tcode{weak_ptr} object but has no +effect on the object its stored pointer points to. +\end{itemdescr} + +\rSec4[util.smartptr.weak.assign]{Assignment} + +\indexlibrarymember{operator=}{weak_ptr}% +\begin{itemdecl} +weak_ptr& operator=(const weak_ptr& r) noexcept; +template weak_ptr& operator=(const weak_ptr& r) noexcept; +template weak_ptr& operator=(const shared_ptr& r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{weak_ptr(r).swap(*this)}. + +\pnum +\returns +\tcode{*this}. + +\pnum +\remarks +The implementation may meet the effects (and the +implied guarantees) via different means, without creating a temporary object. +\end{itemdescr} + +\indexlibrarymember{operator=}{weak_ptr}% +\begin{itemdecl} +weak_ptr& operator=(weak_ptr&& r) noexcept; +template weak_ptr& operator=(weak_ptr&& r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{weak_ptr(std::move(r)).swap(*this)}. + +\pnum +\returns +\tcode{*this}. +\end{itemdescr} + +\rSec4[util.smartptr.weak.mod]{Modifiers} +\indexlibrarymember{swap}{weak_ptr}% +\begin{itemdecl} +void swap(weak_ptr& r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Exchanges the contents of \tcode{*this} and \tcode{r}. +\end{itemdescr} + +\indexlibrarymember{reset}{weak_ptr}% +\begin{itemdecl} +void reset() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{weak_ptr().swap(*this)}. +\end{itemdescr} + +\rSec4[util.smartptr.weak.obs]{Observers} +\indexlibrarymember{use_count}{weak_ptr}% +\begin{itemdecl} +long use_count() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{0} if \tcode{*this} is empty; +otherwise, the number of \tcode{shared_ptr} instances +that share ownership with \tcode{*this}. +\end{itemdescr} + +\indexlibrarymember{expired}{weak_ptr}% +\begin{itemdecl} +bool expired() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{use_count() == 0}. +\end{itemdescr} + +\indexlibrarymember{lock}{weak_ptr}% +\begin{itemdecl} +shared_ptr lock() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{expired() ?\ shared_ptr() :\ shared_ptr(*this)}, executed atomically. +\end{itemdescr} + +\indexlibrarymember{owner_before}{weak_ptr}% +\begin{itemdecl} +template bool owner_before(const shared_ptr& b) const noexcept; +template bool owner_before(const weak_ptr& b) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An unspecified value such that +\begin{itemize} +\item \tcode{x.owner_before(y)} defines a strict weak ordering as defined in~\ref{alg.sorting}; + +\item under the equivalence relation defined by \tcode{owner_before}, +\tcode{!a.owner_before(b) \&\& !b.owner_before(a)}, two \tcode{shared_ptr} or +\tcode{weak_ptr} instances are equivalent if and only if they share ownership or are +both empty. +\end{itemize} +\end{itemdescr} + + +\rSec4[util.smartptr.weak.spec]{Specialized algorithms} + +\indexlibrarymember{swap}{weak_ptr}% +\begin{itemdecl} +template + void swap(weak_ptr& a, weak_ptr& b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{a.swap(b)}. +\end{itemdescr} + +\rSec3[util.smartptr.ownerless]{Class template \tcode{owner_less}} + +\pnum +The class template \tcode{owner_less} allows ownership-based mixed comparisons of shared +and weak pointers. + +\indexlibraryglobal{owner_less}% +\begin{codeblock} +namespace std { + template struct owner_less; + + template struct owner_less> { + bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; + bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; + bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; + }; + + template struct owner_less> { + bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; + bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; + bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; + }; + + template<> struct owner_less { + template + bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; + template + bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; + template + bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; + template + bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; + + using is_transparent = @\unspec@; + }; +} +\end{codeblock} + +\indexlibrarymember{operator()}{owner_less}% +\pnum +\tcode{operator()(x, y)} returns \tcode{x.owner_before(y)}. +\begin{note} +Note that +\begin{itemize} +\item \tcode{operator()} defines a strict weak ordering as defined in~\ref{alg.sorting}; + +\item +two \tcode{shared_ptr} or \tcode{weak_ptr} instances are equivalent +under the equivalence relation defined by \tcode{operator()}, +\tcode{!operator()(a, b) \&\& !operator()(b, a)}, +if and only if they share ownership or are both empty. +\end{itemize} +\end{note} + +\rSec3[util.smartptr.enab]{Class template \tcode{enable_shared_from_this}} + +\pnum +\indexlibraryglobal{enable_shared_from_this}% +A class \tcode{T} can inherit from \tcode{enable_shared_from_this} +to inherit the \tcode{shared_from_this} member functions that obtain +a \tcode{shared_ptr} instance pointing to \tcode{*this}. + +\pnum +\begin{example} +\begin{codeblock} +struct X: public enable_shared_from_this { }; + +int main() { + shared_ptr p(new X); + shared_ptr q = p->shared_from_this(); + assert(p == q); + assert(!p.owner_before(q) && !q.owner_before(p)); // p and q share ownership +} +\end{codeblock} +\end{example} + +\begin{codeblock} +namespace std { + template class enable_shared_from_this { + protected: + constexpr enable_shared_from_this() noexcept; + enable_shared_from_this(const enable_shared_from_this&) noexcept; + enable_shared_from_this& operator=(const enable_shared_from_this&) noexcept; + ~enable_shared_from_this(); + + public: + shared_ptr shared_from_this(); + shared_ptr shared_from_this() const; + weak_ptr weak_from_this() noexcept; + weak_ptr weak_from_this() const noexcept; + + private: + mutable weak_ptr weak_this; // \expos + }; +} +\end{codeblock} + +\pnum +The template parameter \tcode{T} of \tcode{enable_shared_from_this} +may be an incomplete type. + +\indexlibraryctor{enable_shared_from_this}% +\begin{itemdecl} +constexpr enable_shared_from_this() noexcept; +enable_shared_from_this(const enable_shared_from_this&) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Value-initializes \tcode{weak_this}. +\end{itemdescr} + +\indexlibrarymember{operator=}{enable_shared_from_this}% +\begin{itemdecl} +enable_shared_from_this& operator=(const enable_shared_from_this&) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{*this}. + +\pnum +\begin{note} +\tcode{weak_this} is not changed. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{shared_ptr}% +\indexlibrarymember{shared_from_this}{enable_shared_from_this}% +\begin{itemdecl} +shared_ptr shared_from_this(); +shared_ptr shared_from_this() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{shared_ptr(weak_this)}. +\end{itemdescr} + +\indexlibraryglobal{weak_ptr}% +\indexlibrarymember{weak_from_this}{enable_shared_from_this}% +\begin{itemdecl} +weak_ptr weak_from_this() noexcept; +weak_ptr weak_from_this() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{weak_this}. +\end{itemdescr} + +\rSec2[util.smartptr.hash]{Smart pointer hash support} + +\indexlibrarymember{hash}{unique_ptr}% +\begin{itemdecl} +template struct hash>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Letting \tcode{UP} be \tcode{unique_ptr}, +the specialization \tcode{hash} is enabled\iref{unord.hash} +if and only if \tcode{hash} is enabled. +When enabled, for an object \tcode{p} of type \tcode{UP}, +\tcode{hash()(p)} evaluates to +the same value as \tcode{hash()(p.get())}. +The member functions are not guaranteed to be \keyword{noexcept}. +\end{itemdescr} + +\indexlibrarymember{hash}{shared_ptr}% +\begin{itemdecl} +template struct hash>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +For an object \tcode{p} of type \tcode{shared_ptr}, +\tcode{hash>()(p)} evaluates to +the same value as \tcode{hash::element_type*>()(p.get())}. +\end{itemdescr}% +\indextext{smart pointers|)} + +\rSec2[smartptr.adapt]{Smart pointer adaptors} + +\rSec3[out.ptr.t]{Class template \tcode{out_ptr_t}} + +\pnum +\tcode{out_ptr_t} is a class template used to adapt types +such as smart pointers\iref{smartptr} +for functions that use output pointer parameters. + +\pnum +\begin{example} +\begin{codeblock} +#include +#include + +int fopen_s(std::FILE** f, const char* name, const char* mode); + +struct fclose_deleter { + void operator()(std::FILE* f) const noexcept { + std::fclose(f); + } +}; + +int main(int, char*[]) { + constexpr const char* file_name = "ow.o"; + std::unique_ptr file_ptr; + int err = fopen_s(std::out_ptr(file_ptr), file_name, "r+b"); + if (err != 0) + return 1; + // \tcode{*file_ptr} is valid + return 0; +} +\end{codeblock} +\tcode{unique_ptr} can be used with \tcode{out_ptr} +to be passed into an output pointer-style function, +without needing to hold onto an intermediate pointer value and +manually delete it on error or failure. +\end{example} + +\indexlibraryglobal{out_ptr_t}% +\begin{codeblock} +namespace std { + template + class out_ptr_t { + public: + explicit out_ptr_t(Smart&, Args...); + out_ptr_t(const out_ptr_t&) = delete; + + ~out_ptr_t(); + + operator Pointer*() const noexcept; + operator void**() const noexcept; + + private: + Smart& s; // \expos + tuple a; // \expos + Pointer p; // \expos + }; +} +\end{codeblock} + +\pnum +\tcode{Pointer} shall meet the \oldconcept{NullablePointer} requirements. +If \tcode{Smart} is a specialization of \tcode{shared_ptr} and +\tcode{sizeof...(Args) == 0}, +the program is ill-formed. +\begin{note} +It is typically a user error to reset a \tcode{shared_ptr} +without specifying a deleter, +as \tcode{shared_ptr} will replace a custom deleter upon usage of \tcode{reset}, +as specified in \ref{util.smartptr.shared.mod}. +\end{note} + +\pnum +Program-defined specializations of \tcode{out_ptr_t} +that depend on at least one program-defined type +need not meet the requirements for the primary template. + +\pnum +Evaluations of the conversion functions +on the same object may conflict\iref{intro.races}. + +\indexlibraryctor{out_ptr_t}% +\begin{itemdecl} +explicit out_ptr_t(Smart& smart, Args... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{s} with \tcode{smart}, +\tcode{a} with \tcode{std::forward(args)...}, and +value-initializes \tcode{p}. + +\pnum +\begin{note} +The constructor is not \tcode{noexcept} +to allow for a variety of non-terminating and safe implementation strategies. +For example, an implementation can allocate +a \tcode{shared_ptr}'s internal node in the constructor and +let implementation-defined exceptions escape safely. +The destructor can then move the allocated control block in directly and +avoid any other exceptions. +\end{note} +\end{itemdescr} + +\indexlibrarydtor{out_ptr_t}% +\begin{itemdecl} +~out_ptr_t(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{SP} be +\tcode{\exposid{POINTER_OF_OR}(Smart, Pointer)}\iref{memory.general}. + +\pnum +\effects +Equivalent to: +\begin{itemize} +\item +% pretend to \item that there is real text here, but undo the vertical spacing +\mbox{}\vspace{-\baselineskip}\vspace{-\parskip} +\begin{codeblock} +if (p) { + apply([&](auto&&... args) { + s.reset(static_cast(p), std::forward(args)...); }, std::move(a)); +} +\end{codeblock} +if the expression +\tcode{s.reset(static_cast(p), std::forward(args)...)} +is well-\linebreak formed; +\item +otherwise, +\begin{codeblock} +if (p) { + apply([&](auto&&... args) { + s = Smart(static_cast(p), std::forward(args)...); }, std::move(a)); +} +\end{codeblock} +if \tcode{is_constructible_v} is \tcode{true}; +\item +otherwise, the program is ill-formed. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +operator Pointer*() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{operator void**()} has not been called on \tcode{*this}. + +\pnum +\returns +\tcode{addressof(const_cast(p))}. +\end{itemdescr} + +\begin{itemdecl} +operator void**() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_same_v} is \tcode{false}. + +\pnum +\mandates +\tcode{is_pointer_v} is \tcode{true}. + +\pnum +\expects +\tcode{operator Pointer*()} has not been called on \tcode{*this}. + +\pnum +\returns +A pointer value \tcode{v} such that: +\begin{itemize} +\item +the initial value \tcode{*v} is equivalent to \tcode{static_cast(p)} and +\item +any modification of \tcode{*v} +that is not followed by a subsequent modification of \tcode{*this} +affects the value of \tcode{p} during the destruction of \tcode{*this}, +such that \tcode{static_cast(p) == *v}. +\end{itemize} + +\pnum +\remarks +Accessing \tcode{*v} outside the lifetime of \tcode{*this} +has undefined behavior. + +\pnum +\begin{note} +\tcode{reinterpret_cast(static_cast(*this))} +can be a viable implementation strategy for some implementations. +\end{note} +\end{itemdescr} + +\rSec3[out.ptr]{Function template \tcode{out_ptr}} + +\indexlibraryglobal{out_ptr}% +\begin{itemdecl} +template + auto out_ptr(Smart& s, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{P} be \tcode{Pointer} +if \tcode{is_void_v} is \tcode{false}, +otherwise \tcode{\exposid{POINTER_OF}(Smart)}. + +\pnum +\returns +\tcode{out_ptr_t(s, std::forward(args)...)} +\end{itemdescr} + +\rSec3[inout.ptr.t]{Class template \tcode{inout_ptr_t}} + +\pnum +\tcode{inout_ptr_t} is a class template used to adapt types +such as smart pointers\iref{smartptr} +for functions that use output pointer parameters +whose dereferenced values may first be deleted +before being set to another allocated value. + +\pnum +\begin{example} +\begin{codeblock} +#include + +struct star_fish* star_fish_alloc(); +int star_fish_populate(struct star_fish** ps, const char* description); + +struct star_fish_deleter { + void operator() (struct star_fish* c) const noexcept; +}; + +using star_fish_ptr = std::unique_ptr; + +int main(int, char*[]) { + star_fish_ptr peach(star_fish_alloc()); + // ... + // used, need to re-make + int err = star_fish_populate(std::inout_ptr(peach), "caring clown-fish liker"); + return err; +} +\end{codeblock} +A \tcode{unique_ptr} can be used with \tcode{inout_ptr} +to be passed into an output pointer-style function. +The original value will be properly deleted +according to the function it is used with and +a new value reset in its place. +\end{example} + +\indexlibraryglobal{inout_ptr_t}% +\begin{codeblock} +namespace std { + template + class inout_ptr_t { + public: + explicit inout_ptr_t(Smart&, Args...); + inout_ptr_t(const inout_ptr_t&) = delete; + + ~inout_ptr_t(); + + operator Pointer*() const noexcept; + operator void**() const noexcept; + + private: + Smart& s; // \expos + tuple a; // \expos + Pointer p; // \expos + }; +} +\end{codeblock} + +\pnum +\tcode{Pointer} shall meet the \oldconcept{NullablePointer} requirements. +If \tcode{Smart} is a specialization of \tcode{shared_ptr}, +the program is ill-formed. +\begin{note} +It is impossible to properly acquire unique ownership of the managed resource +from a \tcode{shared_ptr} given its shared ownership model. +\end{note} + +\pnum +Program-defined specializations of \tcode{inout_ptr_t} +that depend on at least one program-defined type +need not meet the requirements for the primary template. + +\pnum +Evaluations of the conversion functions on the same object +may conflict\iref{intro.races}. + +\indexlibraryctor{inout_ptr_t}% +\begin{itemdecl} +explicit inout_ptr_t(Smart& smart, Args... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{s} with \tcode{smart}, +\tcode{a} with \tcode{std::forward(args)...}, and +\tcode{p} to either +\begin{itemize} +\item \tcode{smart} if \tcode{is_pointer_v} is \tcode{true}, +\item otherwise, \tcode{smart.get()}. +\end{itemize} + +\pnum +\remarks +An implementation can call \tcode{s.release()}. + +\pnum +\begin{note} +The constructor is not \tcode{noexcept} +to allow for a variety of non-terminating and safe implementation strategies. +For example, an intrusive pointer implementation with a control block +can allocate in the constructor and safely fail with an exception. +\end{note} +\end{itemdescr} + +\indexlibrarydtor{inout_ptr_t}% +\begin{itemdecl} +~inout_ptr_t(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{SP} be +\tcode{\exposid{POINTER_OF_OR}(Smart, Pointer)}\iref{memory.general}. + +\pnum +Let \exposid{release-statement} be \tcode{s.release();} +if an implementation does not call \tcode{s.release()} in the constructor. +Otherwise, it is empty. + +\pnum +\effects +Equivalent to: +\begin{itemize} +\item +% pretend to \item that there is real text here, but undo the vertical spacing +\mbox{}\vspace{-\baselineskip}\vspace{-\parskip} +\begin{codeblock} +if (p) { + apply([&](auto&&... args) { + s = Smart( static_cast(p), std::forward(args)...); }, std::move(a)); +} +\end{codeblock} +if \tcode{is_pointer_v} is \tcode{true}; +\item +otherwise, +\begin{codeblock} +if (p) { + apply([&](auto&&... args) { + @\exposid{release-statement}@; + s.reset(static_cast(p), std::forward(args)...); }, std::move(a)); +} +\end{codeblock} +if the expression +\tcode{s.reset(static_cast(p), std::forward(args)...)} +is well-\newline formed; +\item +otherwise, +\begin{codeblock} +if (p) { + apply([&](auto&&... args) { + @\exposid{release-statement}@; + s = Smart(static_cast(p), std::forward(args)...); }, std::move(a)); +} +\end{codeblock} +if \tcode{is_constructible_v} is \tcode{true}; +\item +otherwise, the program is ill-formed. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +operator Pointer*() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{operator void**()} has not been called on \tcode{*this}. + +\pnum +\returns +\tcode{addressof(const_cast(p))}. +\end{itemdescr} + +\begin{itemdecl} +operator void**() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_same_v} is \tcode{false}. + +\pnum +\mandates +\tcode{is_pointer_v} is \tcode{true}. + +\pnum +\expects +\tcode{operator Pointer*()} has not been called on \tcode{*this}. + +\pnum +\returns +A pointer value \tcode{v} such that: +\begin{itemize} +\item +the initial value \tcode{*v} is equivalent to \tcode{static_cast(p)} and +\item +any modification of \tcode{*v} +that is not followed by subsequent modification of \tcode{*this} +affects the value of \tcode{p} during the destruction of \tcode{*this}, +such that \tcode{static_cast(p) == *v}. +\end{itemize} + +\pnum +\remarks +Accessing \tcode{*v} outside the lifetime of \tcode{*this} +has undefined behavior. + +\pnum +\begin{note} +\tcode{reinterpret_cast(static_cast(*this))} +can be a viable implementation strategy for some implementations. +\end{note} +\end{itemdescr} + +\rSec3[inout.ptr]{Function template \tcode{inout_ptr}} + +\indexlibraryglobal{inout_ptr}% +\begin{itemdecl} +template + auto inout_ptr(Smart& s, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{P} be \tcode{Pointer} if \tcode{is_void_v} is \tcode{false}, +otherwise \tcode{\exposid{POINTER_OF}(Smart)}. + +\pnum +\returns +\tcode{inout_ptr_t(s, std::forward(args)...)}. +\end{itemdescr} + +\rSec1[mem.res]{Memory resources} + +\rSec2[mem.res.syn]{Header \tcode{} synopsis} + +\indexheader{memory_resource}% +\begin{codeblock} +namespace std::pmr { + // \ref{mem.res.class}, class \tcode{memory_resource} + class memory_resource; + + bool operator==(const memory_resource& a, const memory_resource& b) noexcept; + + // \ref{mem.poly.allocator.class}, class template \tcode{polymorphic_allocator} + template class polymorphic_allocator; + + template + bool operator==(const polymorphic_allocator& a, + const polymorphic_allocator& b) noexcept; + + // \ref{mem.res.global}, global memory resources + memory_resource* new_delete_resource() noexcept; + memory_resource* null_memory_resource() noexcept; + memory_resource* set_default_resource(memory_resource* r) noexcept; + memory_resource* get_default_resource() noexcept; + + // \ref{mem.res.pool}, pool resource classes + struct pool_options; + class synchronized_pool_resource; + class unsynchronized_pool_resource; + class monotonic_buffer_resource; +} +\end{codeblock} + +\rSec2[mem.res.class]{Class \tcode{memory_resource}} + +\rSec3[mem.res.class.general]{General} + +\pnum +The \tcode{memory_resource} class is an abstract interface to an unbounded set of classes encapsulating memory resources. + +\indexlibraryglobal{memory_resource}% +\indexlibrarymember{operator=}{memory_resource}% +\begin{codeblock} +namespace std::pmr { + class memory_resource { + static constexpr size_t max_align = alignof(max_align_t); // \expos + + public: + memory_resource() = default; + memory_resource(const memory_resource&) = default; + virtual ~memory_resource(); + + memory_resource& operator=(const memory_resource&) = default; + + [[nodiscard]] void* allocate(size_t bytes, size_t alignment = max_align); + void deallocate(void* p, size_t bytes, size_t alignment = max_align); + + bool is_equal(const memory_resource& other) const noexcept; + + private: + virtual void* do_allocate(size_t bytes, size_t alignment) = 0; + virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0; + + virtual bool do_is_equal(const memory_resource& other) const noexcept = 0; + }; +} +\end{codeblock} + + +\rSec3[mem.res.public]{Public member functions} + +\indexlibrarydtor{memory_resource}% +\begin{itemdecl} +~memory_resource(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Destroys this \tcode{memory_resource}. +\end{itemdescr} + +\indexlibrarymember{allocate}{memory_resource}% +\begin{itemdecl} +[[nodiscard]] void* allocate(size_t bytes, size_t alignment = max_align); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Allocates storage by calling \tcode{do_allocate(bytes, alignment)} and +implicitly creates objects within the allocated region of storage. + +\pnum +\returns +A pointer to a suitable created object\iref{intro.object} +in the allocated region of storage. + +\pnum +\throws +What and when the call to \tcode{do_allocate} throws. +\end{itemdescr} + +\indexlibrarymember{deallocate}{memory_resource}% +\begin{itemdecl} +void deallocate(void* p, size_t bytes, size_t alignment = max_align); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{do_deallocate(p, bytes, alignment)}. +\end{itemdescr} + +\indexlibrarymember{is_equal}{memory_resource}% +\begin{itemdecl} +bool is_equal(const memory_resource& other) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return do_is_equal(other);} +\end{itemdescr} + + +\rSec3[mem.res.private]{Private virtual member functions} + +\indexlibrarymember{do_allocate}{memory_resource}% +\begin{itemdecl} +virtual void* do_allocate(size_t bytes, size_t alignment) = 0; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{alignment} is a power of two. + +\pnum +\returns +A derived class shall implement this function to +return a pointer to allocated storage\iref{basic.stc.dynamic.allocation} +with a size of at least \tcode{bytes}, +aligned to the specified \tcode{alignment}. + +\pnum +\throws +A derived class implementation shall throw an appropriate exception if it is unable to allocate memory with the requested size and alignment. +\end{itemdescr} + +\indexlibrarymember{do_deallocate}{memory_resource}% +\begin{itemdecl} +virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{p} was returned from a prior call to \tcode{allocate(bytes, alignment)} +on a memory resource equal to \tcode{*this}, +and the storage at \tcode{p} has not yet been deallocated. + +\pnum +\effects +A derived class shall implement this function to dispose of allocated storage. + +\pnum +\throws +Nothing. +\end{itemdescr} + +\indexlibrarymember{do_is_equal}{memory_resource}% +\begin{itemdecl} +virtual bool do_is_equal(const memory_resource& other) const noexcept = 0; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A derived class shall implement this function to return \tcode{true} if memory allocated from \keyword{this} can be deallocated from \tcode{other} and vice-versa, +otherwise \tcode{false}. +\begin{note} +It is possible that the most-derived type of \tcode{other} does not match the type of \keyword{this}. +For a derived class \tcode{D}, an implementation of this function +can immediately return \tcode{false} +if \tcode{dynamic_cast(\&other) == nullptr}. +\end{note} +\end{itemdescr} + +\rSec3[mem.res.eq]{Equality} + +\indexlibrarymember{operator==}{memory_resource}% +\begin{itemdecl} +bool operator==(const memory_resource& a, const memory_resource& b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{\&a == \&b || a.is_equal(b)}. +\end{itemdescr} + +\rSec2[mem.poly.allocator.class]{Class template \tcode{polymorphic_allocator}} + +\rSec3[mem.poly.allocator.class.general]{General} + +\pnum +A specialization of class template \tcode{pmr::polymorphic_allocator} +meets the \oldconcept{Allocator} requirements (\tref{cpp17.allocator}). +Constructed with different memory resources, +different instances of the same specialization of \tcode{pmr::polymorphic_allocator} +can exhibit entirely different allocation behavior. +This runtime polymorphism allows objects that use \tcode{polymorphic_allocator} +to behave as if they used different allocator types at run time +even though they use the same static allocator type. + +\pnum +All specializations of class template \tcode{pmr::polymorphic_allocator} +meet the allocator completeness requirements\iref{allocator.requirements.completeness}. + +\indexlibraryglobal{polymorphic_allocator}% +\indexlibrarymember{value_type}{polymorphic_allocator}% +\begin{codeblock} +namespace std::pmr { + template class polymorphic_allocator { + memory_resource* memory_rsrc; // \expos + + public: + using value_type = Tp; + + // \ref{mem.poly.allocator.ctor}, constructors + polymorphic_allocator() noexcept; + polymorphic_allocator(memory_resource* r); + + polymorphic_allocator(const polymorphic_allocator& other) = default; + + template + polymorphic_allocator(const polymorphic_allocator& other) noexcept; + + polymorphic_allocator& operator=(const polymorphic_allocator&) = delete; + + // \ref{mem.poly.allocator.mem}, member functions + [[nodiscard]] Tp* allocate(size_t n); + void deallocate(Tp* p, size_t n); + + [[nodiscard]] void* allocate_bytes(size_t nbytes, size_t alignment = alignof(max_align_t)); + void deallocate_bytes(void* p, size_t nbytes, size_t alignment = alignof(max_align_t)); + template [[nodiscard]] T* allocate_object(size_t n = 1); + template void deallocate_object(T* p, size_t n = 1); + template [[nodiscard]] T* new_object(CtorArgs&&... ctor_args); + template void delete_object(T* p); + + template + void construct(T* p, Args&&... args); + + polymorphic_allocator select_on_container_copy_construction() const; + + memory_resource* resource() const; + }; +} +\end{codeblock} + +\rSec3[mem.poly.allocator.ctor]{Constructors} + +\indexlibraryctor{polymorphic_allocator}% +\begin{itemdecl} +polymorphic_allocator() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Sets \tcode{memory_rsrc} to \tcode{get_default_resource()}. +\end{itemdescr} + +\indexlibraryctor{polymorphic_allocator}% +\begin{itemdecl} +polymorphic_allocator(memory_resource* r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{r} is non-null. + +\pnum +\effects +Sets \tcode{memory_rsrc} to \tcode{r}. + +\pnum +\throws +Nothing. + +\pnum +\begin{note} +This constructor provides an implicit conversion from \tcode{memory_resource*}. +\end{note} +\end{itemdescr} + +\indexlibraryctor{polymorphic_allocator}% +\begin{itemdecl} +template polymorphic_allocator(const polymorphic_allocator& other) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Sets \tcode{memory_rsrc} to \tcode{other.resource()}. +\end{itemdescr} + + +\rSec3[mem.poly.allocator.mem]{Member functions} + +\indexlibrarymember{allocate}{polymorphic_allocator}% +\begin{itemdecl} +[[nodiscard]] Tp* allocate(size_t n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If \tcode{numeric_limits::max() / sizeof(Tp) < n}, +throws \tcode{bad_array_new_length}. +Otherwise equivalent to: +\begin{codeblock} +return static_cast(memory_rsrc->allocate(n * sizeof(Tp), alignof(Tp))); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{deallocate}{polymorphic_allocator}% +\begin{itemdecl} +void deallocate(Tp* p, size_t n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{p} was allocated from a memory resource \tcode{x}, +equal to \tcode{*memory_rsrc}, +using \tcode{x.allocate(n * sizeof(Tp), alignof(Tp))}. + +\pnum +\effects +Equivalent to \tcode{memory_rsrc->deallocate(p, n * sizeof(Tp), alignof(Tp))}. + +\pnum +\throws +Nothing. +\end{itemdescr} + +\indexlibrarymember{allocate_bytes}{polymorphic_allocator}% +\begin{itemdecl} +[[nodiscard]] void* allocate_bytes(size_t nbytes, size_t alignment = alignof(max_align_t)); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return memory_rsrc->allocate(nbytes, alignment);} + +\pnum +\begin{note} +The return type is \tcode{void*} (rather than, e.g., \tcode{byte*}) +to support conversion to an arbitrary pointer type \tcode{U*} +by \tcode{static_cast}, thus facilitating construction of a \tcode{U} +object in the allocated memory. +\end{note} +\end{itemdescr} + +\indexlibrarymember{deallocate_bytes}{polymorphic_allocator}% +\begin{itemdecl} +void deallocate_bytes(void* p, size_t nbytes, size_t alignment = alignof(max_align_t)); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{memory_rsrc->deallocate(p, nbytes, alignment)}. +\end{itemdescr} + +\indexlibrarymember{allocate_object}{polymorphic_allocator}% +\begin{itemdecl} +template + [[nodiscard]] T* allocate_object(size_t n = 1); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Allocates memory suitable for holding +an array of \tcode{n} objects of type \tcode{T}, as follows: +\begin{itemize} +\item + if \tcode{numeric_limits::max() / sizeof(T) < n}, + throws \tcode{bad_array_new_length}, +\item + otherwise equivalent to: +\begin{codeblock} +return static_cast(allocate_bytes(n*sizeof(T), alignof(T))); +\end{codeblock} +\end{itemize} + +\pnum +\begin{note} +\tcode{T} is not deduced and must therefore be provided as a template argument. +\end{note} +\end{itemdescr} + +\indexlibrarymember{deallocate_object}{polymorphic_allocator}% +\begin{itemdecl} +template + void deallocate_object(T* p, size_t n = 1); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{deallocate_bytes(p, n*sizeof(T), alignof(T))}. +\end{itemdescr} + +\indexlibrarymember{new_object}{polymorphic_allocator}% +\begin{itemdecl} +template + [[nodiscard]] T* new_object(CtorArgs&&... ctor_args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Allocates and constructs an object of type \tcode{T}, as follows.\newline +Equivalent to: +\begin{codeblock} +T* p = allocate_object(); +try { + construct(p, std::forward(ctor_args)...); +} catch (...) { + deallocate_object(p); + throw; +} +return p; +\end{codeblock} + +\pnum +\begin{note} +\tcode{T} is not deduced and must therefore be provided as a template argument. +\end{note} +\end{itemdescr} + +\indexlibrarymember{new_object}{polymorphic_allocator}% +\begin{itemdecl} +template + void delete_object(T* p); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +allocator_traits::destroy(*this, p); +deallocate_object(p); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{construct}{polymorphic_allocator}% +\begin{itemdecl} +template + void construct(T* p, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +Uses-allocator construction of \tcode{T} +with allocator \tcode{*this} (see~\ref{allocator.uses.construction}) +and constructor arguments \tcode{std::forward(args)...} is well-formed. + +\pnum +\effects +Construct a \tcode{T} object in the storage +whose address is represented by \tcode{p} +by uses-allocator construction with allocator \tcode{*this} +and constructor arguments \tcode{std::forward(args)...}. + +\pnum +\throws +Nothing unless the constructor for \tcode{T} throws. +\end{itemdescr} + +\indexlibrarymember{select_on_container_copy_construction}{polymorphic_allocator}% +\begin{itemdecl} +polymorphic_allocator select_on_container_copy_construction() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{polymorphic_allocator()}. + +\pnum +\begin{note} +The memory resource is not propagated. +\end{note} +\end{itemdescr} + +\indexlibrarymember{resource}{polymorphic_allocator}% +\begin{itemdecl} +memory_resource* resource() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{memory_rsrc}. +\end{itemdescr} + +\rSec3[mem.poly.allocator.eq]{Equality} + +\indexlibrarymember{operator==}{polymorphic_allocator}% +\begin{itemdecl} +template + bool operator==(const polymorphic_allocator& a, + const polymorphic_allocator& b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{*a.resource() == *b.resource()}. +\end{itemdescr} + +\rSec2[mem.res.global]{Access to program-wide \tcode{memory_resource} objects} + +\indexlibraryglobal{new_delete_resource}% +\begin{itemdecl} +memory_resource* new_delete_resource() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A pointer to a static-duration object of a type derived from \tcode{memory_resource} +that can serve as a resource for allocating memory +using \tcode{::operator new} and \tcode{::operator delete}. +The same value is returned every time this function is called. +For a return value \tcode{p} and a memory resource \tcode{r}, +\tcode{p->is_equal(r)} returns \tcode{\&r == p}. +\end{itemdescr} + +\indexlibraryglobal{null_memory_resource}% +\begin{itemdecl} +memory_resource* null_memory_resource() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A pointer to a static-duration object of a type derived from \tcode{memory_resource} +for which \tcode{allocate()} always throws \tcode{bad_alloc} and +for which \tcode{deallocate()} has no effect. +The same value is returned every time this function is called. +For a return value \tcode{p} and a memory resource \tcode{r}, +\tcode{p->is_equal(r)} returns \tcode{\&r == p}. +\end{itemdescr} + +\pnum +The \defn{default memory resource pointer} is a pointer to a memory resource +that is used by certain facilities when an explicit memory resource +is not supplied through the interface. +Its initial value is the return value of \tcode{new_delete_resource()}. + +\indexlibraryglobal{set_default_resource}% +\begin{itemdecl} +memory_resource* set_default_resource(memory_resource* r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If \tcode{r} is non-null, +sets the value of the default memory resource pointer to \tcode{r}, +otherwise sets the default memory resource pointer to \tcode{new_delete_resource()}. + +\pnum +\returns +The previous value of the default memory resource pointer. + +\pnum +\remarks +Calling the \tcode{set_default_resource} and +\tcode{get_default_resource} functions shall not incur a data race. +A call to the \tcode{set_default_resource} function +shall synchronize with subsequent calls to +the \tcode{set_default_resource} and \tcode{get_default_resource} functions. +\end{itemdescr} + +\indexlibraryglobal{get_default_resource}% +\begin{itemdecl} +memory_resource* get_default_resource() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The current value of the default memory resource pointer. +\end{itemdescr} + +\rSec2[mem.res.pool]{Pool resource classes} + +\rSec3[mem.res.pool.overview]{Classes \tcode{synchronized_pool_resource} and \tcode{unsynchronized_pool_resource}} + +\pnum +The \tcode{synchronized_pool_resource} and +\tcode{unsynchronized_pool_resource} classes +(collectively called \defn{pool resource classes}) +are general-purpose memory resources having the following qualities: +\begin{itemize} +\item +Each resource frees its allocated memory on destruction, +even if \tcode{deallocate} has not been called for some of the allocated blocks. +\item +A pool resource consists of a collection of \defn{pools}, +serving requests for different block sizes. +Each individual pool manages a collection of \defn{chunks} +that are in turn divided into blocks of uniform size, +returned via calls to \tcode{do_allocate}. +Each call to \tcode{do_allocate(size, alignment)} is dispatched +to the pool serving the smallest blocks accommodating at least \tcode{size} bytes. +\item +When a particular pool is exhausted, +allocating a block from that pool results in the allocation +of an additional chunk of memory from the \defn{upstream allocator} +(supplied at construction), thus replenishing the pool. +With each successive replenishment, +the chunk size obtained increases geometrically. +\begin{note} +By allocating memory in chunks, +the pooling strategy increases the chance that consecutive allocations +will be close together in memory. +\end{note} +\item +Allocation requests that exceed the largest block size of any pool +are fulfilled directly from the upstream allocator. +\item +A \tcode{pool_options} struct may be passed to the pool resource constructors +to tune the largest block size and the maximum chunk size. +\end{itemize} + +\pnum +A \tcode{synchronized_pool_resource} may be accessed from multiple threads +without external synchronization +and may have thread-specific pools to reduce synchronization costs. +An \tcode{unsynchronized_pool_resource} class may not be accessed +from multiple threads simultaneously +and thus avoids the cost of synchronization entirely +in single-threaded applications. + +\indexlibraryglobal{pool_options}% +\indexlibraryglobal{synchronized_pool_resource}% +\indexlibraryglobal{unsynchronized_pool_resource}% +\begin{codeblock} +namespace std::pmr { + struct pool_options { + size_t max_blocks_per_chunk = 0; + size_t largest_required_pool_block = 0; + }; + + class synchronized_pool_resource : public memory_resource { + public: + synchronized_pool_resource(const pool_options& opts, memory_resource* upstream); + + synchronized_pool_resource() + : synchronized_pool_resource(pool_options(), get_default_resource()) {} + explicit synchronized_pool_resource(memory_resource* upstream) + : synchronized_pool_resource(pool_options(), upstream) {} + explicit synchronized_pool_resource(const pool_options& opts) + : synchronized_pool_resource(opts, get_default_resource()) {} + + synchronized_pool_resource(const synchronized_pool_resource&) = delete; + virtual ~synchronized_pool_resource(); + + synchronized_pool_resource& operator=(const synchronized_pool_resource&) = delete; + + void release(); + memory_resource* upstream_resource() const; + pool_options options() const; + + protected: + void* do_allocate(size_t bytes, size_t alignment) override; + void do_deallocate(void* p, size_t bytes, size_t alignment) override; + + bool do_is_equal(const memory_resource& other) const noexcept override; + }; + + class unsynchronized_pool_resource : public memory_resource { + public: + unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream); + + unsynchronized_pool_resource() + : unsynchronized_pool_resource(pool_options(), get_default_resource()) {} + explicit unsynchronized_pool_resource(memory_resource* upstream) + : unsynchronized_pool_resource(pool_options(), upstream) {} + explicit unsynchronized_pool_resource(const pool_options& opts) + : unsynchronized_pool_resource(opts, get_default_resource()) {} + + unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete; + virtual ~unsynchronized_pool_resource(); + + unsynchronized_pool_resource& operator=(const unsynchronized_pool_resource&) = delete; + + void release(); + memory_resource* upstream_resource() const; + pool_options options() const; + + protected: + void* do_allocate(size_t bytes, size_t alignment) override; + void do_deallocate(void* p, size_t bytes, size_t alignment) override; + + bool do_is_equal(const memory_resource& other) const noexcept override; + }; +} +\end{codeblock} + +\rSec3[mem.res.pool.options]{\tcode{pool_options} data members} + +\pnum +The members of \tcode{pool_options} +comprise a set of constructor options for pool resources. +The effect of each option on the pool resource behavior is described below: + +\indexlibrarymember{pool_options}{max_blocks_per_chunk}% +\begin{itemdecl} +size_t max_blocks_per_chunk; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The maximum number of blocks that will be allocated at once +from the upstream memory resource\iref{mem.res.monotonic.buffer} +to replenish a pool. +If the value of \tcode{max_blocks_per_chunk} is zero or +is greater than an \impldef{largest supported value to configure the maximum number of blocks to replenish a pool} +limit, that limit is used instead. +The implementation +may choose to use a smaller value than is specified in this field and +may use different values for different pools. +\end{itemdescr} + +\indexlibrarymember{pool_options}{largest_required_pool_block}% +\begin{itemdecl} +size_t largest_required_pool_block; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The largest allocation size that is required to be fulfilled +using the pooling mechanism. +Attempts to allocate a single block larger than this threshold +will be allocated directly from the upstream memory resource. +If \tcode{largest_required_pool_block} is zero or +is greater than an \impldef{largest supported value to configure the largest allocation satisfied directly by a pool} +limit, that limit is used instead. +The implementation may choose a pass-through threshold +larger than specified in this field. +\end{itemdescr} + +\rSec3[mem.res.pool.ctor]{Constructors and destructors} + +\indexlibraryctor{synchronized_pool_resource}% +\indexlibraryctor{unsynchronized_pool_resource}% +\begin{itemdecl} +synchronized_pool_resource(const pool_options& opts, memory_resource* upstream); +unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{upstream} is the address of a valid memory resource. + +\pnum +\effects +Constructs a pool resource object that will obtain memory from \tcode{upstream} +whenever the pool resource is unable to satisfy a memory request +from its own internal data structures. +The resulting object will hold a copy of \tcode{upstream}, +but will not own the resource to which \tcode{upstream} points. +\begin{note} +The intention is that calls to \tcode{upstream->allocate()} +will be substantially fewer than calls to \tcode{this->allocate()} +in most cases. +\end{note} +The behavior of the pooling mechanism is tuned +according to the value of the \tcode{opts} argument. + +\pnum +\throws +Nothing unless \tcode{upstream->allocate()} throws. +It is unspecified if, or under what conditions, +this constructor calls \tcode{upstream->allocate()}. +\end{itemdescr} + +\indexlibrarydtor{synchronized_pool_resource}% +\indexlibrarydtor{unsynchronized_pool_resource}% +\begin{itemdecl} +virtual ~synchronized_pool_resource(); +virtual ~unsynchronized_pool_resource(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Calls \tcode{release()}. +\end{itemdescr} + +\rSec3[mem.res.pool.mem]{Members} + +\indexlibrarymember{release}{synchronized_pool_resource}% +\indexlibrarymember{release}{unsynchronized_pool_resource}% +\begin{itemdecl} +void release(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Calls \tcode{upstream_resource()->deallocate()} as necessary +to release all allocated memory. +\begin{note} +The memory is released back to \tcode{upstream_resource()} +even if \tcode{deallocate} has not been called +for some of the allocated blocks. +\end{note} +\end{itemdescr} + +\indexlibrarymember{upstream_resource}{synchronized_pool_resource}% +\indexlibrarymember{upstream_resource}{unsynchronized_pool_resource}% +\begin{itemdecl} +memory_resource* upstream_resource() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The value of the \tcode{upstream} argument +provided to the constructor of this object. +\end{itemdescr} + +\indexlibrarymember{options}{synchronized_pool_resource}% +\indexlibrarymember{options}{unsynchronized_pool_resource}% +\begin{itemdecl} +pool_options options() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The options that control the pooling behavior of this resource. +The values in the returned struct may differ +from those supplied to the pool resource constructor in that +values of zero will be replaced with \impldef{default configuration of a pool} +defaults, and sizes may be rounded to unspecified granularity. +\end{itemdescr} + +\indexlibrarymember{do_allocate}{synchronized_pool_resource}% +\indexlibrarymember{do_allocate}{unsynchronized_pool_resource}% +\begin{itemdecl} +void* do_allocate(size_t bytes, size_t alignment) override; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If the pool selected for a block of size \tcode{bytes} +is unable to satisfy the memory request from its own internal data structures, +it will call \tcode{upstream_resource()->allocate()} to obtain more memory. +If \tcode{bytes} is larger than that which the largest pool can handle, +then memory will be allocated using \tcode{upstream_resource()->allocate()}. + +\pnum +\returns +A pointer to allocated storage\iref{basic.stc.dynamic.allocation} +with a size of at least \tcode{bytes}. +The size and alignment of the allocated memory shall meet the requirements +for a class derived from \tcode{memory_resource}\iref{mem.res.class}. + +\pnum +\throws +Nothing unless \tcode{upstream_resource()->allocate()} throws. +\end{itemdescr} + +\indexlibrarymember{do_deallocate}{synchronized_pool_resource}% +\indexlibrarymember{do_deallocate}{unsynchronized_pool_resource}% +\begin{itemdecl} +void do_deallocate(void* p, size_t bytes, size_t alignment) override; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Returns the memory at \tcode{p} to the pool. +It is unspecified if, or under what circumstances, +this operation will result in a call to \tcode{upstream_resource()->deallocate()}. + +\pnum +\throws +Nothing. +\end{itemdescr} + +\indexlibrarymember{do_is_equal}{synchronized_pool_resource}% +\indexlibrarymember{do_is_equal}{unsynchronized_pool_resource}% +\begin{itemdecl} +bool do_is_equal(const memory_resource& other) const noexcept override; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{this == \&other}. +\end{itemdescr} + +\rSec2[mem.res.monotonic.buffer]{Class \tcode{monotonic_buffer_resource}} + +\rSec3[mem.res.monotonic.buffer.general]{General} + +\pnum +A \tcode{monotonic_buffer_resource} is a special-purpose memory resource +intended for very fast memory allocations in situations +where memory is used to build up a few objects +and then is released all at once when the memory resource object is destroyed. + +\indexlibraryglobal{monotonic_buffer_resource}% +\begin{codeblock} +namespace std::pmr { + class monotonic_buffer_resource : public memory_resource { + memory_resource* upstream_rsrc; // \expos + void* current_buffer; // \expos + size_t next_buffer_size; // \expos + + public: + explicit monotonic_buffer_resource(memory_resource* upstream); + monotonic_buffer_resource(size_t initial_size, memory_resource* upstream); + monotonic_buffer_resource(void* buffer, size_t buffer_size, memory_resource* upstream); + + monotonic_buffer_resource() + : monotonic_buffer_resource(get_default_resource()) {} + explicit monotonic_buffer_resource(size_t initial_size) + : monotonic_buffer_resource(initial_size, get_default_resource()) {} + monotonic_buffer_resource(void* buffer, size_t buffer_size) + : monotonic_buffer_resource(buffer, buffer_size, get_default_resource()) {} + + monotonic_buffer_resource(const monotonic_buffer_resource&) = delete; + + virtual ~monotonic_buffer_resource(); + + monotonic_buffer_resource& operator=(const monotonic_buffer_resource&) = delete; + + void release(); + memory_resource* upstream_resource() const; + + protected: + void* do_allocate(size_t bytes, size_t alignment) override; + void do_deallocate(void* p, size_t bytes, size_t alignment) override; + + bool do_is_equal(const memory_resource& other) const noexcept override; + }; +} +\end{codeblock} + +\rSec3[mem.res.monotonic.buffer.ctor]{Constructors and destructor} + +\indexlibraryctor{monotonic_buffer_resource}% +\begin{itemdecl} +explicit monotonic_buffer_resource(memory_resource* upstream); +monotonic_buffer_resource(size_t initial_size, memory_resource* upstream); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{upstream} is the address of a valid memory resource. +\tcode{initial_size}, if specified, is greater than zero. + +\pnum +\effects +Sets \tcode{upstream_rsrc} to \tcode{upstream} and +\tcode{current_buffer} to \keyword{nullptr}. +If \tcode{initial_size} is specified, +sets \tcode{next_buffer_size} to at least \tcode{initial_size}; +otherwise sets \tcode{next_buffer_size} to an +\impldef{default \tcode{next_buffer_size} for a \tcode{monotonic_buffer_resource}} size. +\end{itemdescr} + +\indexlibraryctor{monotonic_buffer_resource}% +\begin{itemdecl} +monotonic_buffer_resource(void* buffer, size_t buffer_size, memory_resource* upstream); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{upstream} is the address of a valid memory resource. +\tcode{buffer_size} is no larger than the number of bytes in \tcode{buffer}. + +\pnum +\effects +Sets \tcode{upstream_rsrc} to \tcode{upstream}, +\tcode{current_buffer} to \tcode{buffer}, and +\tcode{next_buffer_size} to \tcode{buffer_size} (but not less than 1), +then increases \tcode{next_buffer_size} +by an \impldef{growth factor for \tcode{monotonic_buffer_resource}} growth factor (which need not be integral). +\end{itemdescr} + +\indexlibrarydtor{monotonic_buffer_resource}% +\begin{itemdecl} +~monotonic_buffer_resource(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Calls \tcode{release()}. +\end{itemdescr} + + +\rSec3[mem.res.monotonic.buffer.mem]{Members} + +\indexlibrarymember{release}{monotonic_buffer_resource}% +\begin{itemdecl} +void release(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Calls \tcode{upstream_rsrc->deallocate()} as necessary +to release all allocated memory. +Resets \tcode{current_buffer} and \tcode{next_buffer_size} +to their initial values at construction. + +\pnum +\begin{note} +The memory is released back to \tcode{upstream_rsrc} +even if some blocks that were allocated from \keyword{this} +have not been deallocated from \keyword{this}. +\end{note} +\end{itemdescr} + +\indexlibrarymember{upstream_resource}{monotonic_buffer_resource}% +\begin{itemdecl} +memory_resource* upstream_resource() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The value of \tcode{upstream_rsrc}. +\end{itemdescr} + +\indexlibrarymember{do_allocate}{monotonic_buffer_resource}% +\begin{itemdecl} +void* do_allocate(size_t bytes, size_t alignment) override; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If the unused space in \tcode{current_buffer} +can fit a block with the specified \tcode{bytes} and \tcode{alignment}, +then allocate the return block from \tcode{current_buffer}; +otherwise set \tcode{current_buffer} to \tcode{upstream_rsrc->allocate(n, m)}, +where \tcode{n} is not less than \tcode{max(bytes, next_buffer_size)} and +\tcode{m} is not less than \tcode{alignment}, +and increase \tcode{next_buffer_size} +by an \impldef{growth factor for \tcode{monotonic_buffer_resource}} growth factor (which need not be integral), +then allocate the return block from the newly-allocated \tcode{current_buffer}. + +\pnum +\returns +A pointer to allocated storage\iref{basic.stc.dynamic.allocation} +with a size of at least \tcode{bytes}. +The size and alignment of the allocated memory shall meet the requirements +for a class derived from \tcode{memory_resource}\iref{mem.res.class}. + +\pnum +\throws +Nothing unless \tcode{upstream_rsrc->allocate()} throws. +\end{itemdescr} + +\indexlibrarymember{do_deallocate}{monotonic_buffer_resource}% +\begin{itemdecl} +void do_deallocate(void* p, size_t bytes, size_t alignment) override; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +None. + +\pnum +\throws +Nothing. + +\pnum +\remarks +Memory used by this resource increases monotonically until its destruction. +\end{itemdescr} + +\indexlibrarymember{do_is_equal}{monotonic_buffer_resource}% +\begin{itemdecl} +bool do_is_equal(const memory_resource& other) const noexcept override; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{this == \&other}. +\end{itemdescr} + + +\rSec1[allocator.adaptor]{Class template \tcode{scoped_allocator_adaptor}} + +\rSec2[allocator.adaptor.syn]{Header \tcode{} synopsis} + +\indexheader{scoped_allocator}% +\begin{codeblock} +namespace std { + // class template \tcode{scoped allocator adaptor} + template + class scoped_allocator_adaptor; + + // \ref{scoped.adaptor.operators}, scoped allocator operators + template + bool operator==(const scoped_allocator_adaptor& a, + const scoped_allocator_adaptor& b) noexcept; +} +\end{codeblock} + +\pnum +The class template \tcode{scoped_allocator_adaptor} is an allocator template that +specifies an allocator resource (the outer allocator) to be used by a container (as any +other allocator does) and also specifies an inner allocator resource to be passed to the +constructor of every element within the container. This adaptor is instantiated with one +outer and zero or more inner allocator types. If instantiated with only one allocator +type, the inner allocator becomes the \tcode{scoped_allocator_adaptor} itself, thus +using the same allocator resource for the container and every element within the +container and, if the elements themselves are containers, each of their elements +recursively. If instantiated with more than one allocator, the first allocator is the +outer allocator for use by the container, the second allocator is passed to the +constructors of the container's elements, and, if the elements themselves are +containers, the third allocator is passed to the elements' elements, and so on. If +containers are nested to a depth greater than the number of allocators, the last +allocator is used repeatedly, as in the single-allocator case, for any remaining +recursions. +\begin{note} +The \tcode{scoped_allocator_adaptor} is derived from the outer +allocator type so it can be substituted for the outer allocator type in most +expressions. +\end{note} + +\indexlibraryglobal{scoped_allocator_adaptor}% +\indexlibrarymember{outer_allocator_type}{scoped_allocator_adaptor}% +\indexlibrarymember{value_type}{scoped_allocator_adaptor}% +\indexlibrarymember{size_type}{scoped_allocator_adaptor}% +\indexlibrarymember{difference_type}{scoped_allocator_adaptor}% +\indexlibrarymember{pointer}{scoped_allocator_adaptor}% +\indexlibrarymember{const_pointer}{scoped_allocator_adaptor}% +\indexlibrarymember{void_pointer}{scoped_allocator_adaptor}% +\indexlibrarymember{const_void_pointer}{scoped_allocator_adaptor}% +\begin{codeblock} +namespace std { + template + class scoped_allocator_adaptor : public OuterAlloc { + private: + using OuterTraits = allocator_traits; // \expos + scoped_allocator_adaptor inner; // \expos + + public: + using outer_allocator_type = OuterAlloc; + using inner_allocator_type = @\seebelow@; + + using value_type = typename OuterTraits::value_type; + using size_type = typename OuterTraits::size_type; + using difference_type = typename OuterTraits::difference_type; + using pointer = typename OuterTraits::pointer; + using const_pointer = typename OuterTraits::const_pointer; + using void_pointer = typename OuterTraits::void_pointer; + using const_void_pointer = typename OuterTraits::const_void_pointer; + + using propagate_on_container_copy_assignment = @\seebelow@; + using propagate_on_container_move_assignment = @\seebelow@; + using propagate_on_container_swap = @\seebelow@; + using is_always_equal = @\seebelow@; + + template struct rebind { + using other = scoped_allocator_adaptor< + OuterTraits::template rebind_alloc, InnerAllocs...>; + }; + + scoped_allocator_adaptor(); + template + scoped_allocator_adaptor(OuterA2&& outerAlloc, + const InnerAllocs&... innerAllocs) noexcept; + + scoped_allocator_adaptor(const scoped_allocator_adaptor& other) noexcept; + scoped_allocator_adaptor(scoped_allocator_adaptor&& other) noexcept; + + template + scoped_allocator_adaptor( + const scoped_allocator_adaptor& other) noexcept; + template + scoped_allocator_adaptor( + scoped_allocator_adaptor&& other) noexcept; + + scoped_allocator_adaptor& operator=(const scoped_allocator_adaptor&) = default; + scoped_allocator_adaptor& operator=(scoped_allocator_adaptor&&) = default; + + ~scoped_allocator_adaptor(); + + inner_allocator_type& inner_allocator() noexcept; + const inner_allocator_type& inner_allocator() const noexcept; + outer_allocator_type& outer_allocator() noexcept; + const outer_allocator_type& outer_allocator() const noexcept; + + [[nodiscard]] pointer allocate(size_type n); + [[nodiscard]] pointer allocate(size_type n, const_void_pointer hint); + void deallocate(pointer p, size_type n); + size_type max_size() const; + + template + void construct(T* p, Args&&... args); + + template + void destroy(T* p); + + scoped_allocator_adaptor select_on_container_copy_construction() const; + }; + + template + scoped_allocator_adaptor(OuterAlloc, InnerAllocs...) + -> scoped_allocator_adaptor; +} +\end{codeblock} + +\rSec2[allocator.adaptor.types]{Member types} + +\indexlibrarymember{inner_allocator_type}{scoped_allocator_adaptor}% +\begin{itemdecl} +using inner_allocator_type = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ctype \tcode{scoped_allocator_adaptor} if \tcode{sizeof...(InnerAllocs)} is +zero; otherwise,\\ \tcode{scoped_allocator_adaptor}. +\end{itemdescr} + +\indexlibrarymember{propagate_on_container_copy_assignment}{scoped_allocator_adaptor}% +\begin{itemdecl} +using propagate_on_container_copy_assignment = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ctype \tcode{true_type} if +\tcode{allocator_traits::propagate_on_container_copy_assignment::value} is +\tcode{true} for any \tcode{A} in the set of \tcode{OuterAlloc} and +\tcode{InnerAllocs...}; otherwise, \tcode{false_type}. +\end{itemdescr} + +\indexlibrarymember{propagate_on_container_move_assignment}{scoped_allocator_adaptor}% +\begin{itemdecl} +using propagate_on_container_move_assignment = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ctype \tcode{true_type} if +\tcode{allocator_traits::propagate_on_container_move_assignment::value} is +\tcode{true} for any \tcode{A} in the set of \tcode{OuterAlloc} and +\tcode{InnerAllocs...}; otherwise, \tcode{false_type}. +\end{itemdescr} + +\indexlibrarymember{propagate_on_container_swap}{scoped_allocator_adaptor}% +\begin{itemdecl} +using propagate_on_container_swap = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ctype \tcode{true_type} if +\tcode{allocator_traits::propagate_on_container_swap::value} is +\tcode{true} for any \tcode{A} in the set of \tcode{OuterAlloc} and +\tcode{InnerAllocs...}; otherwise, \tcode{false_type}. +\end{itemdescr} + +\indexlibrarymember{is_always_equal}{scoped_allocator_adaptor}% +\begin{itemdecl} +using is_always_equal = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ctype \tcode{true_type} if +\tcode{allocator_traits::is_always_equal::value} is +\tcode{true} for every \tcode{A} in the set of \tcode{OuterAlloc} and +\tcode{InnerAllocs...}; otherwise, \tcode{false_type}. +\end{itemdescr} + +\rSec2[allocator.adaptor.cnstr]{Constructors} + +\indexlibraryctor{scoped_allocator_adaptor}% +\begin{itemdecl} +scoped_allocator_adaptor(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Value-initializes the \tcode{OuterAlloc} base class and the \tcode{inner} allocator +object. +\end{itemdescr} + +\indexlibraryctor{scoped_allocator_adaptor}% +\begin{itemdecl} +template + scoped_allocator_adaptor(OuterA2&& outerAlloc, const InnerAllocs&... innerAllocs) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\effects +Initializes the \tcode{OuterAlloc} base class with +\tcode{std::forward(outerAlloc)} and \tcode{inner} with \tcode{innerAllocs...} +(hence recursively initializing each allocator within the adaptor with the corresponding +allocator from the argument list). +\end{itemdescr} + +\indexlibraryctor{scoped_allocator_adaptor}% +\begin{itemdecl} +scoped_allocator_adaptor(const scoped_allocator_adaptor& other) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes each allocator within the adaptor with the corresponding allocator +from \tcode{other}. +\end{itemdescr} + +\indexlibraryctor{scoped_allocator_adaptor}% +\begin{itemdecl} +scoped_allocator_adaptor(scoped_allocator_adaptor&& other) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Move constructs each allocator within the adaptor with the corresponding allocator +from \tcode{other}. +\end{itemdescr} + +\indexlibraryctor{scoped_allocator_adaptor}% +\begin{itemdecl} +template + scoped_allocator_adaptor( + const scoped_allocator_adaptor& other) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\effects +Initializes each allocator within the adaptor with the corresponding allocator +from \tcode{other}. +\end{itemdescr} + +\indexlibraryctor{scoped_allocator_adaptor}% +\begin{itemdecl} +template + scoped_allocator_adaptor(scoped_allocator_adaptor&& other) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\effects +Initializes each allocator within the adaptor with the corresponding allocator rvalue +from \tcode{other}. +\end{itemdescr} + +\rSec2[allocator.adaptor.members]{Members} + +\pnum +In the \tcode{construct} member functions, +\tcode{\placeholdernc{OUTERMOST}(x)} is +\tcode{\placeholdernc{OUTERMOST}(x.outer_allocator())} if +the expression \tcode{x.outer_allocator()} is +valid~\iref{temp.deduct} and +\tcode{x} otherwise; +\tcode{\placeholdernc{OUTERMOST_ALLOC_TRAITS}(x)} is +\tcode{allocator_traits>}. +\begin{note} +\tcode{\placeholdernc{OUTERMOST}(x)} and +\tcode{\placeholdernc{OUTERMOST_ALL\-OC_TRAITS}(x)} are recursive operations. It +is incumbent upon the definition of \tcode{outer_allocator()} to ensure that the +recursion terminates. It will terminate for all instantiations of +\tcode{scoped_allocator_adaptor}. +\end{note} + +\indexlibrarymember{inner_allocator}{scoped_allocator_adaptor}% +\begin{itemdecl} +inner_allocator_type& inner_allocator() noexcept; +const inner_allocator_type& inner_allocator() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{*this} if \tcode{sizeof...(InnerAllocs)} is zero; otherwise, +\tcode{inner}. +\end{itemdescr} + +\indexlibrarymember{outer_allocator}{scoped_allocator_adaptor}% +\begin{itemdecl} +outer_allocator_type& outer_allocator() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{static_cast(*this)}. +\end{itemdescr} + +\indexlibrarymember{outer_allocator}{scoped_allocator_adaptor}% +\begin{itemdecl} +const outer_allocator_type& outer_allocator() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{static_cast(*this)}. +\end{itemdescr} + +\indexlibrarymember{allocate}{scoped_allocator_adaptor}% +\begin{itemdecl} +[[nodiscard]] pointer allocate(size_type n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{allocator_traits::allocate(outer_allocator(), n)}. +\end{itemdescr} + +\indexlibrarymember{allocate}{scoped_allocator_adaptor}% +\begin{itemdecl} +[[nodiscard]] pointer allocate(size_type n, const_void_pointer hint); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{allocator_traits::allocate(outer_allocator(), n, hint)}. +\end{itemdescr} + +\indexlibrarymember{deallocate}{scoped_allocator_adaptor}% +\begin{itemdecl} +void deallocate(pointer p, size_type n) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +As if by: +\tcode{allocator_traits::deallocate(outer_allocator(), p, n);} +\end{itemdescr} + +\indexlibrarymember{max_size}{scoped_allocator_adaptor}% +\begin{itemdecl} +size_type max_size() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{allocator_traits::max_size(outer_allocator())}. +\end{itemdescr} + +\indexlibrarymember{construct}{scoped_allocator_adaptor}% +\begin{itemdecl} +template + void construct(T* p, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +apply([p, this](auto&&... newargs) { + @\placeholdernc{OUTERMOST_ALLOC_TRAITS}@(*this)::construct( + @\placeholdernc{OUTERMOST}@(*this), p, + std::forward(newargs)...); + }, + uses_allocator_construction_args(inner_allocator(), + std::forward(args)...)); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{destroy}{scoped_allocator_adaptor}% +\begin{itemdecl} +template + void destroy(T* p); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Calls \tcode{\placeholdernc{OUTERMOST_ALLOC_TRAITS}(*this)::destroy(\placeholdernc{OUTERMOST}(*this), p)}. +\end{itemdescr} + +\indexlibrarymember{select_on_container_copy_construction}{scoped_allocator_adaptor}% +\begin{itemdecl} +scoped_allocator_adaptor select_on_container_copy_construction() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A new \tcode{scoped_allocator_adaptor} object +where each allocator \tcode{a1} within the adaptor +is initialized with +\tcode{allocator_traits::select_on_container_copy_construction(a2)}, +where \tcode{A1} is the type of \tcode{a1} and +\tcode{a2} is the corresponding allocator in \tcode{*this}. +\end{itemdescr} + +\rSec2[scoped.adaptor.operators]{Operators} + +\indexlibrarymember{operator==}{scoped_allocator_adaptor}% +\begin{itemdecl} +template + bool operator==(const scoped_allocator_adaptor& a, + const scoped_allocator_adaptor& b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +If \tcode{sizeof...(InnerAllocs)} is zero, +\begin{codeblock} +a.outer_allocator() == b.outer_allocator() +\end{codeblock} +otherwise +\begin{codeblock} +a.outer_allocator() == b.outer_allocator() && a.inner_allocator() == b.inner_allocator() +\end{codeblock} +\end{itemdescr} diff --git a/source/meta.tex b/source/meta.tex new file mode 100644 index 0000000000..6c6d7914fd --- /dev/null +++ b/source/meta.tex @@ -0,0 +1,2629 @@ +%!TEX root = std.tex +\rSec0[meta]{Metaprogramming library} + +\rSec1[meta.general]{General} + +\pnum +This Clause describes metaprogramming facilities. +These facilities are summarized in \tref{meta.summary}. + +\begin{libsumtab}{Metaprogramming library summary}{meta.summary} +\ref{intseq} & Integer sequences & \tcode{} \\ \rowsep +\ref{type.traits} & Type traits & \tcode{} \\ \rowsep +\ref{ratio} & Rational arithmetic & \tcode{} \\ +\end{libsumtab} + +\rSec1[intseq]{Compile-time integer sequences} + +\rSec2[intseq.general]{In general} + +\pnum +The library provides a class template that can represent an integer sequence. +When used as an argument to a function template the template parameter pack defining the +sequence can be deduced and used in a pack expansion. +\begin{note} +The \tcode{index_sequence} alias template is provided for the common case of +an integer sequence of type \tcode{size_t}; see also \ref{tuple.apply}. +\end{note} + +\rSec2[intseq.intseq]{Class template \tcode{integer_sequence}} + +\indexlibraryglobal{integer_sequence}% +\indexlibrarymember{value_type}{integer_sequence}% +\begin{codeblock} +namespace std { + template struct integer_sequence { + using value_type = T; + static constexpr size_t size() noexcept { return sizeof...(I); } + }; +} +\end{codeblock} + +\pnum +\mandates +\tcode{T} is an integer type. + +\rSec2[intseq.make]{Alias template \tcode{make_integer_sequence}} + +\indexlibraryglobal{make_integer_sequence}% +\begin{itemdecl} +template + using make_integer_sequence = integer_sequence; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +$\tcode{N} \geq 0$. + +\pnum +The alias template +\tcode{make_integer_sequence} denotes a specialization of +\tcode{integer_sequence} with \tcode{N} non-type template arguments. +The type \tcode{make_integer_sequence} is an alias for the type +\tcode{integer_sequence}. +\begin{note} +\tcode{make_integer_sequence} is an alias for the type +\tcode{integer_sequence}. +\end{note} +\end{itemdescr} + +\rSec1[type.traits]{Metaprogramming and type traits} + +\rSec2[type.traits.general]{General} + +\pnum +Subclause \ref{type.traits} describes components used by \Cpp{} programs, particularly in +templates, to support the widest possible range of types, optimize +template code usage, detect type related user errors, and perform +type inference and transformation at compile time. It includes type +classification traits, type property inspection traits, and type +transformations. The type classification traits describe a complete taxonomy +of all possible \Cpp{} types, and state where in that taxonomy a given +type belongs. The type property inspection traits allow important +characteristics of types or of combinations of types to be inspected. The +type transformations allow certain properties of types to be manipulated. + +\pnum +\indextext{signal-safe!type traits}% +All functions specified in \ref{type.traits} are signal-safe\iref{support.signal}. + +\rSec2[meta.rqmts]{Requirements} + +\pnum +A \defnoldconcept{UnaryTypeTrait} describes a property +of a type. It shall be a class template that takes one template type +argument and, optionally, additional arguments that help define the +property being described. It shall be \oldconcept{DefaultConstructible}, +\oldconcept{CopyConstructible}, +and publicly and unambiguously derived, directly or indirectly, from +its \defn{base characteristic}, which is +a specialization of the template +\tcode{integral_constant}\iref{meta.help}, with +the arguments to the template \tcode{integral_constant} determined by the +requirements for the particular property being described. +The member names of the base characteristic shall not be hidden and shall be +unambiguously available in the \oldconcept{UnaryTypeTrait}. + +\pnum +A \defnoldconcept{BinaryTypeTrait} describes a +relationship between two types. It shall be a class template that +takes two template type arguments and, optionally, additional +arguments that help define the relationship being described. It shall +be \oldconcept{DefaultConstructible}, \oldconcept{CopyConstructible}, +and publicly and unambiguously derived, directly or +indirectly, from +its \term{base characteristic}, which is a specialization +of the template +\tcode{integral_constant}\iref{meta.help}, with +the arguments to the template \tcode{integral_constant} determined by the +requirements for the particular relationship being described. +The member names of the base characteristic shall not be hidden and shall be +unambiguously available in the \oldconcept{BinaryTypeTrait}. + +\pnum +A \defnoldconcept{TransformationTrait} +modifies a property +of a type. It shall be a class template that takes one +template type argument and, optionally, additional arguments that help +define the modification. It shall define a publicly accessible nested type +named \tcode{type}, which shall be a synonym for the modified type. + +\pnum +Unless otherwise specified, +the behavior of a program that adds specializations +for any of the templates specified in \ref{type.traits} +is undefined. + +\pnum +Unless otherwise specified, an incomplete type may be used +to instantiate a template specified in \ref{type.traits}. +The behavior of a program is undefined if: +\begin{itemize} +\item + an instantiation of a template specified in \ref{type.traits} + directly or indirectly depends on + an incompletely-defined object type \tcode{T}, and +\item + that instantiation could yield a different result + were \tcode{T} hypothetically completed. +\end{itemize} + +\rSec2[meta.type.synop]{Header \tcode{} synopsis} + +\indexheader{type_traits}% +% FIXME: Many index entries missing. +\begin{codeblock} +namespace std { + // \ref{meta.help}, helper class + template struct integral_constant; + + template + using bool_constant = integral_constant; + using true_type = bool_constant; + using false_type = bool_constant; + + // \ref{meta.unary.cat}, primary type categories + template struct is_void; + template struct is_null_pointer; + template struct is_integral; + template struct is_floating_point; + template struct is_array; + template struct is_pointer; + template struct is_lvalue_reference; + template struct is_rvalue_reference; + template struct is_member_object_pointer; + template struct is_member_function_pointer; + template struct is_enum; + template struct is_union; + template struct is_class; + template struct is_function; + + // \ref{meta.unary.comp}, composite type categories + template struct is_reference; + template struct is_arithmetic; + template struct is_fundamental; + template struct is_object; + template struct is_scalar; + template struct is_compound; + template struct is_member_pointer; + + // \ref{meta.unary.prop}, type properties + template struct is_const; + template struct is_volatile; + template struct is_trivial; + template struct is_trivially_copyable; + template struct is_standard_layout; + template struct is_empty; + template struct is_polymorphic; + template struct is_abstract; + template struct is_final; + template struct is_aggregate; + + template struct is_signed; + template struct is_unsigned; + template struct is_bounded_array; + template struct is_unbounded_array; + template struct is_scoped_enum; + + template struct is_constructible; + template struct is_default_constructible; + template struct is_copy_constructible; + template struct is_move_constructible; + + template struct is_assignable; + template struct is_copy_assignable; + template struct is_move_assignable; + + template struct is_swappable_with; + template struct is_swappable; + + template struct is_destructible; + + template struct is_trivially_constructible; + template struct is_trivially_default_constructible; + template struct is_trivially_copy_constructible; + template struct is_trivially_move_constructible; + + template struct is_trivially_assignable; + template struct is_trivially_copy_assignable; + template struct is_trivially_move_assignable; + template struct is_trivially_destructible; + + template struct is_nothrow_constructible; + template struct is_nothrow_default_constructible; + template struct is_nothrow_copy_constructible; + template struct is_nothrow_move_constructible; + + template struct is_nothrow_assignable; + template struct is_nothrow_copy_assignable; + template struct is_nothrow_move_assignable; + + template struct is_nothrow_swappable_with; + template struct is_nothrow_swappable; + + template struct is_nothrow_destructible; + + template struct has_virtual_destructor; + + template struct has_unique_object_representations; + + template struct reference_constructs_from_temporary; + template struct reference_converts_from_temporary; + + // \ref{meta.unary.prop.query}, type property queries + template struct alignment_of; + template struct rank; + template struct extent; + + // \ref{meta.rel}, type relations + template struct is_same; + template struct is_base_of; + template struct is_convertible; + template struct is_nothrow_convertible; + template struct is_layout_compatible; + template struct is_pointer_interconvertible_base_of; + + template struct is_invocable; + template struct is_invocable_r; + + template struct is_nothrow_invocable; + template struct is_nothrow_invocable_r; + + // \ref{meta.trans.cv}, const-volatile modifications + template struct remove_const; + template struct remove_volatile; + template struct remove_cv; + template struct add_const; + template struct add_volatile; + template struct add_cv; + + template + using @\libglobal{remove_const_t}@ = typename remove_const::type; + template + using @\libglobal{remove_volatile_t}@ = typename remove_volatile::type; + template + using @\libglobal{remove_cv_t}@ = typename remove_cv::type; + template + using @\libglobal{add_const_t}@ = typename add_const::type; + template + using @\libglobal{add_volatile_t}@ = typename add_volatile::type; + template + using @\libglobal{add_cv_t}@ = typename add_cv::type; + + // \ref{meta.trans.ref}, reference modifications + template struct remove_reference; + template struct add_lvalue_reference; + template struct add_rvalue_reference; + + template + using @\libglobal{remove_reference_t}@ = typename remove_reference::type; + template + using @\libglobal{add_lvalue_reference_t}@ = typename add_lvalue_reference::type; + template + using @\libglobal{add_rvalue_reference_t}@ = typename add_rvalue_reference::type; + + // \ref{meta.trans.sign}, sign modifications + template struct make_signed; + template struct make_unsigned; + + template + using @\libglobal{make_signed_t}@ = typename make_signed::type; + template + using @\libglobal{make_unsigned_t}@ = typename make_unsigned::type; + + // \ref{meta.trans.arr}, array modifications + template struct remove_extent; + template struct remove_all_extents; + + template + using @\libglobal{remove_extent_t}@ = typename remove_extent::type; + template + using @\libglobal{remove_all_extents_t}@ = typename remove_all_extents::type; + + // \ref{meta.trans.ptr}, pointer modifications + template struct remove_pointer; + template struct add_pointer; + + template + using @\libglobal{remove_pointer_t}@ = typename remove_pointer::type; + template + using @\libglobal{add_pointer_t}@ = typename add_pointer::type; + + // \ref{meta.trans.other}, other transformations + template struct type_identity; + template struct remove_cvref; + template struct decay; + template struct enable_if; + template struct conditional; + template struct common_type; + template class TQual, template class UQual> + struct basic_common_reference { }; + template struct common_reference; + template struct underlying_type; + template struct invoke_result; + template struct unwrap_reference; + template struct unwrap_ref_decay; + + template + using @\libglobal{type_identity_t}@ = typename type_identity::type; + template + using @\libglobal{remove_cvref_t}@ = typename remove_cvref::type; + template + using @\libglobal{decay_t}@ = typename decay::type; + template + using @\libglobal{enable_if_t}@ = typename enable_if::type; + template + using @\libglobal{conditional_t}@ = typename conditional::type; + template + using @\libglobal{common_type_t}@ = typename common_type::type; + template + using @\libglobal{common_reference_t}@ = typename common_reference::type; + template + using @\libglobal{underlying_type_t}@ = typename underlying_type::type; + template + using @\libglobal{invoke_result_t}@ = typename invoke_result::type; + template + using unwrap_reference_t = typename unwrap_reference::type; + template + using unwrap_ref_decay_t = typename unwrap_ref_decay::type; + template + using @\libglobal{void_t}@ = void; + + // \ref{meta.logical}, logical operator traits + template struct conjunction; + template struct disjunction; + template struct negation; + + // \ref{meta.unary.cat}, primary type categories + template + inline constexpr bool @\libglobal{is_void_v}@ = is_void::value; + template + inline constexpr bool @\libglobal{is_null_pointer_v}@ = is_null_pointer::value; + template + inline constexpr bool @\libglobal{is_integral_v}@ = is_integral::value; + template + inline constexpr bool @\libglobal{is_floating_point_v}@ = is_floating_point::value; + template + inline constexpr bool @\libglobal{is_array_v}@ = is_array::value; + template + inline constexpr bool @\libglobal{is_pointer_v}@ = is_pointer::value; + template + inline constexpr bool @\libglobal{is_lvalue_reference_v}@ = is_lvalue_reference::value; + template + inline constexpr bool @\libglobal{is_rvalue_reference_v}@ = is_rvalue_reference::value; + template + inline constexpr bool @\libglobal{is_member_object_pointer_v}@ = is_member_object_pointer::value; + template + inline constexpr bool @\libglobal{is_member_function_pointer_v}@ = is_member_function_pointer::value; + template + inline constexpr bool @\libglobal{is_enum_v}@ = is_enum::value; + template + inline constexpr bool @\libglobal{is_union_v}@ = is_union::value; + template + inline constexpr bool @\libglobal{is_class_v}@ = is_class::value; + template + inline constexpr bool @\libglobal{is_function_v}@ = is_function::value; + + // \ref{meta.unary.comp}, composite type categories + template + inline constexpr bool @\libglobal{is_reference_v}@ = is_reference::value; + template + inline constexpr bool @\libglobal{is_arithmetic_v}@ = is_arithmetic::value; + template + inline constexpr bool @\libglobal{is_fundamental_v}@ = is_fundamental::value; + template + inline constexpr bool @\libglobal{is_object_v}@ = is_object::value; + template + inline constexpr bool @\libglobal{is_scalar_v}@ = is_scalar::value; + template + inline constexpr bool @\libglobal{is_compound_v}@ = is_compound::value; + template + inline constexpr bool @\libglobal{is_member_pointer_v}@ = is_member_pointer::value; + + // \ref{meta.unary.prop}, type properties + template + inline constexpr bool @\libglobal{is_const_v}@ = is_const::value; + template + inline constexpr bool @\libglobal{is_volatile_v}@ = is_volatile::value; + template + inline constexpr bool @\libglobal{is_trivial_v}@ = is_trivial::value; + template + inline constexpr bool @\libglobal{is_trivially_copyable_v}@ = is_trivially_copyable::value; + template + inline constexpr bool @\libglobal{is_standard_layout_v}@ = is_standard_layout::value; + template + inline constexpr bool @\libglobal{is_empty_v}@ = is_empty::value; + template + inline constexpr bool @\libglobal{is_polymorphic_v}@ = is_polymorphic::value; + template + inline constexpr bool @\libglobal{is_abstract_v}@ = is_abstract::value; + template + inline constexpr bool @\libglobal{is_final_v}@ = is_final::value; + template + inline constexpr bool @\libglobal{is_aggregate_v}@ = is_aggregate::value; + template + inline constexpr bool @\libglobal{is_signed_v}@ = is_signed::value; + template + inline constexpr bool @\libglobal{is_unsigned_v}@ = is_unsigned::value; + template + inline constexpr bool @\libglobal{is_bounded_array_v}@ = is_bounded_array::value; + template + inline constexpr bool @\libglobal{is_unbounded_array_v}@ = is_unbounded_array::value; + template + inline constexpr bool @\libglobal{is_scoped_enum_v}@ = is_scoped_enum::value; + template + inline constexpr bool @\libglobal{is_constructible_v}@ = is_constructible::value; + template + inline constexpr bool @\libglobal{is_default_constructible_v}@ = is_default_constructible::value; + template + inline constexpr bool @\libglobal{is_copy_constructible_v}@ = is_copy_constructible::value; + template + inline constexpr bool @\libglobal{is_move_constructible_v}@ = is_move_constructible::value; + template + inline constexpr bool @\libglobal{is_assignable_v}@ = is_assignable::value; + template + inline constexpr bool @\libglobal{is_copy_assignable_v}@ = is_copy_assignable::value; + template + inline constexpr bool @\libglobal{is_move_assignable_v}@ = is_move_assignable::value; + template + inline constexpr bool @\libglobal{is_swappable_with_v}@ = is_swappable_with::value; + template + inline constexpr bool @\libglobal{is_swappable_v}@ = is_swappable::value; + template + inline constexpr bool @\libglobal{is_destructible_v}@ = is_destructible::value; + template + inline constexpr bool is_trivially_constructible_v + = is_trivially_constructible::value; + template + inline constexpr bool is_trivially_default_constructible_v + = is_trivially_default_constructible::value; + template + inline constexpr bool is_trivially_copy_constructible_v + = is_trivially_copy_constructible::value; + template + inline constexpr bool is_trivially_move_constructible_v + = is_trivially_move_constructible::value; + template + inline constexpr bool @\libglobal{is_trivially_assignable_v}@ = is_trivially_assignable::value; + template + inline constexpr bool is_trivially_copy_assignable_v + = is_trivially_copy_assignable::value; + template + inline constexpr bool is_trivially_move_assignable_v + = is_trivially_move_assignable::value; + template + inline constexpr bool @\libglobal{is_trivially_destructible_v}@ = is_trivially_destructible::value; + template + inline constexpr bool is_nothrow_constructible_v + = is_nothrow_constructible::value; + template + inline constexpr bool is_nothrow_default_constructible_v + = is_nothrow_default_constructible::value; + template + inline constexpr bool is_nothrow_copy_constructible_v + = is_nothrow_copy_constructible::value; + template + inline constexpr bool is_nothrow_move_constructible_v + = is_nothrow_move_constructible::value; + template + inline constexpr bool @\libglobal{is_nothrow_assignable_v}@ = is_nothrow_assignable::value; + template + inline constexpr bool @\libglobal{is_nothrow_copy_assignable_v}@ = is_nothrow_copy_assignable::value; + template + inline constexpr bool @\libglobal{is_nothrow_move_assignable_v}@ = is_nothrow_move_assignable::value; + template + inline constexpr bool @\libglobal{is_nothrow_swappable_with_v}@ = is_nothrow_swappable_with::value; + template + inline constexpr bool @\libglobal{is_nothrow_swappable_v}@ = is_nothrow_swappable::value; + template + inline constexpr bool @\libglobal{is_nothrow_destructible_v}@ = is_nothrow_destructible::value; + template + inline constexpr bool @\libglobal{has_virtual_destructor_v}@ = has_virtual_destructor::value; + template + inline constexpr bool has_unique_object_representations_v + = has_unique_object_representations::value; + template + inline constexpr bool @\libglobal{reference_constructs_from_temporary_v}@ + = reference_constructs_from_temporary::value; + template + inline constexpr bool @\libglobal{reference_converts_from_temporary_v}@ + = reference_converts_from_temporary::value; + + // \ref{meta.unary.prop.query}, type property queries + template + inline constexpr size_t @\libglobal{alignment_of_v}@ = alignment_of::value; + template + inline constexpr size_t @\libglobal{rank_v}@ = rank::value; + template + inline constexpr size_t @\libglobal{extent_v}@ = extent::value; + + // \ref{meta.rel}, type relations + template + inline constexpr bool @\libglobal{is_same_v}@ = is_same::value; + template + inline constexpr bool @\libglobal{is_base_of_v}@ = is_base_of::value; + template + inline constexpr bool @\libglobal{is_convertible_v}@ = is_convertible::value; + template + inline constexpr bool @\libglobal{is_nothrow_convertible_v}@ = is_nothrow_convertible::value; + template + inline constexpr bool @\libglobal{is_layout_compatible_v}@ = is_layout_compatible::value; + template + inline constexpr bool is_pointer_interconvertible_base_of_v + = is_pointer_interconvertible_base_of::value; + template + inline constexpr bool @\libglobal{is_invocable_v}@ = is_invocable::value; + template + inline constexpr bool @\libglobal{is_invocable_r_v}@ = is_invocable_r::value; + template + inline constexpr bool @\libglobal{is_nothrow_invocable_v}@ = is_nothrow_invocable::value; + template + inline constexpr bool is_nothrow_invocable_r_v + = is_nothrow_invocable_r::value; + + // \ref{meta.logical}, logical operator traits + template + inline constexpr bool @\libglobal{conjunction_v}@ = conjunction::value; + template + inline constexpr bool @\libglobal{disjunction_v}@ = disjunction::value; + template + inline constexpr bool @\libglobal{negation_v}@ = negation::value; + + // \ref{meta.member}, member relationships + template + constexpr bool is_pointer_interconvertible_with_class(M S::*m) noexcept; + template + constexpr bool is_corresponding_member(M1 S1::*m1, M2 S2::*m2) noexcept; + + // \ref{meta.const.eval}, constant evaluation context + constexpr bool is_constant_evaluated() noexcept; +} +\end{codeblock} + +\rSec2[meta.help]{Helper classes} + +\indexlibrarymember{value_type}{integral_constant}% +\begin{codeblock} +namespace std { + template struct integral_constant { + static constexpr T value = v; + + using value_type = T; + using type = integral_constant; + + constexpr operator value_type() const noexcept { return value; } + constexpr value_type operator()() const noexcept { return value; } + }; +} +\end{codeblock} + +\indexlibraryglobal{integral_constant}% +\indexlibraryglobal{bool_constant}% +\indexlibraryglobal{true_type}% +\indexlibraryglobal{false_type}% +\pnum +The class template \tcode{integral_constant}, +alias template \tcode{bool_constant}, and +its associated \grammarterm{typedef-name}{s} +\tcode{true_type} and \tcode{false_type} +are used as base classes to define +the interface for various type traits. + +\rSec2[meta.unary]{Unary type traits} + +\rSec3[meta.unary.general]{General} + +\pnum +Subclause \ref{meta.unary} contains templates that may be used to query the +properties of a type at compile time. + +\pnum +Each of these templates shall be a +\oldconcept{UnaryTypeTrait}\iref{meta.rqmts} +with a base characteristic of +\tcode{true_type} if the corresponding condition is \tcode{true}, otherwise +\tcode{false_type}. + +\rSec3[meta.unary.cat]{Primary type categories} + +\pnum +The primary type categories correspond to the descriptions given in +subclause~\ref{basic.types} of the \Cpp{} standard. + +\pnum +For any given type \tcode{T}, the result of applying one of these templates to +\tcode{T} and to \cv{}~\tcode{T} shall yield the same result. + +\pnum +\begin{note} +For any given type \tcode{T}, exactly one of the primary type categories +has a \tcode{value} member that evaluates to \tcode{true}. +\end{note} + +\begin{libreqtab3e}{Primary type category predicates}{meta.unary.cat} +\\ \topline +\lhdr{Template} & \chdr{Condition} & \rhdr{Comments} \\\capsep +\endfirsthead +\continuedcaption\\ +\topline +\lhdr{Template} & \chdr{Condition} & \rhdr{Comments} \\ \capsep +\endhead +\indexlibraryglobal{is_void}% +\tcode{template}\br + \tcode{struct is_void;} & +\tcode{T} is \keyword{void} & \\ \rowsep +\indexlibraryglobal{is_null_pointer}% +\tcode{template}\br + \tcode{struct is_null_pointer;} & +\tcode{T} is \tcode{nullptr_t}\iref{basic.fundamental} & \\ \rowsep +\indexlibraryglobal{is_integral}% +\tcode{template}\br + \tcode{struct is_integral;} & +\tcode{T} is an integral type\iref{basic.fundamental} & \\ \rowsep +\indexlibraryglobal{is_floating_point}% +\tcode{template}\br + \tcode{struct is_floating_point;} & +\tcode{T} is a floating-point type\iref{basic.fundamental} & \\ \rowsep +\indexlibraryglobal{is_array}% +\tcode{template}\br + \tcode{struct is_array;} & +\tcode{T} is an array type\iref{basic.compound} of known or unknown extent & +Class template \tcode{array}\iref{array} +is not an array type. \\ \rowsep +\indexlibraryglobal{is_pointer}% +\tcode{template}\br + \tcode{struct is_pointer;} & +\tcode{T} is a pointer type\iref{basic.compound} & +Includes pointers to functions +but not pointers to non-static members. \\ \rowsep +\indexlibraryglobal{is_lvalue_reference}% +\tcode{template}\br + \tcode{struct is_lvalue_reference;} & + \tcode{T} is an lvalue reference type\iref{dcl.ref} & \\ \rowsep +\indexlibraryglobal{is_rvalue_reference}% +\tcode{template}\br + \tcode{struct is_rvalue_reference;} & + \tcode{T} is an rvalue reference type\iref{dcl.ref} & \\ \rowsep +\indexlibraryglobal{is_member_object_pointer}% +\tcode{template}\br + \tcode{struct is_member_object_pointer;}& + \tcode{T} is a pointer to data member & \\ \rowsep +\indexlibraryglobal{is_member_function_pointer}% +\tcode{template}\br + \tcode{struct is_member_function_pointer;}& +\tcode{T} is a pointer to member function & \\ \rowsep +\indexlibraryglobal{is_enum}% +\tcode{template}\br + \tcode{struct is_enum;} & +\tcode{T} is an enumeration type\iref{basic.compound} & \\ \rowsep +\indexlibraryglobal{is_union}% +\tcode{template}\br + \tcode{struct is_union;} & +\tcode{T} is a union type\iref{basic.compound} & \\ \rowsep +\indexlibraryglobal{is_class}% +\tcode{template}\br + \tcode{struct is_class;} & +\tcode{T} is a non-union class type\iref{basic.compound} & \\ \rowsep +\indexlibraryglobal{is_function}% +\tcode{template}\br + \tcode{struct is_function;} & +\tcode{T} is a function type\iref{basic.compound} & \\ +\end{libreqtab3e} + +\rSec3[meta.unary.comp]{Composite type traits} + +\pnum +These templates provide convenient compositions of the primary type +categories, corresponding to the descriptions given in subclause~\ref{basic.types}. + +\pnum +For any given type \tcode{T}, the result of applying one of these templates to +\tcode{T} and to \cv{}~\tcode{T} shall yield the same result. + +\begin{libreqtab3b}{Composite type category predicates}{meta.unary.comp} +\\ \topline +\lhdr{Template} & \chdr{Condition} & \rhdr{Comments} \\ \capsep +\endfirsthead +\continuedcaption\\ +\topline +\lhdr{Template} & \chdr{Condition} & \rhdr{Comments} \\ \capsep +\endhead +\indexlibraryglobal{is_reference}% +\tcode{template}\br + \tcode{struct is_reference;} & + \tcode{T} is an lvalue reference or an rvalue reference & \\ \rowsep +\indexlibraryglobal{is_arithmetic}% +\tcode{template}\br + \tcode{struct is_arithmetic;} & + \tcode{T} is an arithmetic type\iref{basic.fundamental} & \\ \rowsep +\indexlibraryglobal{is_fundamental}% +\tcode{template}\br + \tcode{struct is_fundamental;} & + \tcode{T} is a fundamental type\iref{basic.fundamental} & \\ \rowsep +\indexlibraryglobal{is_object}% +\tcode{template}\br + \tcode{struct is_object;} & + \tcode{T} is an object type\iref{term.object.type} & \\ \rowsep +\indexlibraryglobal{is_scalar}% +\tcode{template}\br + \tcode{struct is_scalar;} & + \tcode{T} is a scalar type\iref{term.scalar.type} & \\ \rowsep +\indexlibraryglobal{is_compound}% +\tcode{template}\br + \tcode{struct is_compound;} & + \tcode{T} is a compound type\iref{basic.compound} & \\ \rowsep +\indexlibraryglobal{is_member_pointer}% +\tcode{template}\br + \tcode{struct is_member_pointer;} & + \tcode{T} is a pointer-to-member type\iref{basic.compound} & \\ +\end{libreqtab3b} + +\rSec3[meta.unary.prop]{Type properties} + +\pnum +These templates provide access to some of the more important +properties of types. + +\pnum +It is unspecified whether the library defines any full or partial +specializations of any of these templates. + +\pnum +For all of the class templates \tcode{X} declared in this subclause, +instantiating that template with a template-argument that is a class +template specialization may result in the implicit instantiation of +the template argument if and only if the semantics of \tcode{X} require that +the argument is a complete type. + +\pnum +For the purpose of defining the templates in this subclause, +a function call expression \tcode{declval()} for any type \tcode{T} +is considered to be a trivial\iref{term.trivial.type,special} function call +that is not an odr-use\iref{term.odr.use} of \tcode{declval} +in the context of the corresponding definition +notwithstanding the restrictions of~\ref{declval}. + +\pnum +For the purpose of defining the templates in this subclause, +let \tcode{\placeholdernc{VAL}} for some type \tcode{T} be +an expression defined as follows: +\begin{itemize} +\item +If \tcode{T} is a reference or function type, +\tcode{\placeholdernc{VAL}} is an expression +with the same type and value category as \tcode{declval()}. +\item +Otherwise, \tcode{\placeholdernc{VAL}} is a prvalue +that initially has type \tcode{T}. +\begin{note} +If \tcode{T} is cv-qualified, +the cv-qualification is subject to adjustment\iref{expr.type}. +\end{note} +\end{itemize} + +\begin{libreqtab3b}{Type property predicates}{meta.unary.prop} +\\ \topline +\lhdr{Template} & \chdr{Condition} & \rhdr{Preconditions} \\ \capsep +\endfirsthead +\continuedcaption\\ +\topline +\lhdr{Template} & \chdr{Condition} & \rhdr{Preconditions} \\ \capsep +\endhead + +\indexlibraryglobal{is_const}% +\tcode{template}\br + \tcode{struct is_const;} & + \tcode{T} is const-qualified\iref{basic.type.qualifier} & \\ \rowsep + +\indexlibraryglobal{is_volatile}% +\tcode{template}\br + \tcode{struct is_volatile;} & + \tcode{T} is volatile-qualified\iref{basic.type.qualifier} & \\ \rowsep + + +\indexlibraryglobal{is_trivial}% +\tcode{template}\br + \tcode{struct is_trivial;} & + \tcode{T} is a trivial type\iref{term.trivial.type} & + \tcode{remove_all_extents_t} shall be a complete + type or \cv{}~\keyword{void}. \\ \rowsep + +\indexlibraryglobal{is_trivially_copyable}% +\tcode{template}\br + \tcode{struct is_trivially_copyable;} & + \tcode{T} is a trivially copyable type\iref{term.trivially.copyable.type} & + \tcode{remove_all_extents_t} shall be a complete type or + \cv{}~\keyword{void}. \\ \rowsep + +\indexlibraryglobal{is_standard_layout}% +\tcode{template}\br + \tcode{struct is_standard_layout;} & + \tcode{T} is a standard-layout type\iref{term.standard.layout.type} & + \tcode{remove_all_extents_t} shall be a complete + type or \cv{}~\keyword{void}. \\ \rowsep + +\indexlibrary{\idxcode{is_empty}!class}% +\tcode{template}\br + \tcode{struct is_empty;} & + \tcode{T} is a class type, but not a union type, with no non-static data + members other than subobjects of zero size, no virtual member functions, + no virtual base classes, and no base class \tcode{B} for + which \tcode{is_empty_v} is \tcode{false}. & + If \tcode{T} is a non-union class type, \tcode{T} shall be a complete type. \\ \rowsep + +\indexlibraryglobal{is_polymorphic}% +\tcode{template}\br + \tcode{struct is_polymorphic;} & + \tcode{T} is a polymorphic class\iref{class.virtual} & + If \tcode{T} is a non-union class type, \tcode{T} shall be a complete type. \\ \rowsep + +\indexlibraryglobal{is_abstract}% +\tcode{template}\br + \tcode{struct is_abstract;} & + \tcode{T} is an abstract class\iref{class.abstract} & + If \tcode{T} is a non-union class type, \tcode{T} shall be a complete type. \\ \rowsep + +\indexlibraryglobal{is_final}% +\tcode{template}\br + \tcode{struct is_final;} & + \tcode{T} is a class type marked with the \grammarterm{class-virt-specifier} + \tcode{final}\iref{class.pre}. +\begin{tailnote} +A union is a class type that + can be marked with \tcode{final}. +\end{tailnote} +& + If \tcode{T} is a class type, \tcode{T} shall be a complete type. \\ \rowsep + +\indexlibraryglobal{is_aggregate}% +\tcode{template}\br + \tcode{struct is_aggregate;} & + \tcode{T} is an aggregate type\iref{dcl.init.aggr} & + \tcode{remove_all_extents_t} shall be a complete type or \cv~\keyword{void}. \\ \rowsep + +\indexlibrary{\idxcode{is_signed}!class}% +\tcode{template}\br + \tcode{struct is_signed;} & + If \tcode{is_arithmetic_v} is \tcode{true}, the same result as + \tcode{T(-1) < T(0)}; + otherwise, \tcode{false} & \\ \rowsep + +\indexlibraryglobal{is_unsigned}% +\tcode{template}\br + \tcode{struct is_unsigned;} & + If \tcode{is_arithmetic_v} is \tcode{true}, the same result as + \tcode{T(0) < T(-1)}; + otherwise, \tcode{false} & \\ \rowsep + +\indexlibraryglobal{is_bounded_array}% +\tcode{template}\br + \tcode{struct is_bounded_array;} & + \tcode{T} is an array type of known bound\iref{dcl.array} + & \\ \rowsep + +\indexlibraryglobal{is_unbounded_array}% +\tcode{template}\br + \tcode{struct is_unbounded_array;} & + \tcode{T} is an array type of unknown bound\iref{dcl.array} + & \\ \rowsep + +\indexlibraryglobal{is_scoped_enum}% +\tcode{template}\br + \tcode{struct is_scoped_enum;} & + \tcode{T} is a scoped enumeration\iref{dcl.enum} + & \\ \rowsep + +\indexlibraryglobal{is_constructible}% +\tcode{template}\br + \tcode{struct is_constructible;} & + For a function type \tcode{T} or + for a \cv{}~\keyword{void} type \tcode{T}, + \tcode{is_constructible_v} is \tcode{false}, + otherwise \seebelow & + \tcode{T} and all types in the template parameter pack \tcode{Args} + shall be complete types, \cv{}~\keyword{void}, + or arrays of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_default_constructible}% +\tcode{template}\br + \tcode{struct is_default_constructible;} & + \tcode{is_constructible_v} is \tcode{true}. & + \tcode{T} shall be a complete type, \cv{}~\keyword{void}, + or an array of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_copy_constructible}% +\tcode{template}\br + \tcode{struct is_copy_constructible;} & + For a referenceable type \tcode{T}\iref{defns.referenceable}, the same result as + \tcode{is_constructible_v}, otherwise \tcode{false}. & + \tcode{T} shall be a complete type, \cv{}~\keyword{void}, + or an array of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_move_constructible}% +\tcode{template}\br + \tcode{struct is_move_constructible;} & + For a referenceable type \tcode{T}, the same result as + \tcode{is_constructible_v}, otherwise \tcode{false}. & + \tcode{T} shall be a complete type, \cv{}~\keyword{void}, + or an array of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_assignable}% +\tcode{template}\br + \tcode{struct is_assignable;} & + The expression \tcode{declval() =} \tcode{declval()} is well-formed + when treated as an unevaluated + operand\iref{term.unevaluated.operand}. Access checking is performed as if in a context + unrelated to \tcode{T} and \tcode{U}. Only the validity of the immediate context + of the assignment expression is considered. +\begin{tailnote} +The compilation of the + expression can result in side effects such as the instantiation of class template + specializations and function template specializations, the generation of + implicitly-defined functions, and so on. Such side effects are not in the ``immediate + context'' and can result in the program being ill-formed. +\end{tailnote} +& + \tcode{T} and \tcode{U} shall be complete types, \cv{}~\keyword{void}, + or arrays of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_copy_assignable}% +\tcode{template}\br + \tcode{struct is_copy_assignable;} & + For a referenceable type \tcode{T}, the same result as + \tcode{is_assignable_v}, otherwise \tcode{false}. & + \tcode{T} shall be a complete type, \cv{}~\keyword{void}, + or an array of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_move_assignable}% +\tcode{template}\br + \tcode{struct is_move_assignable;} & + For a referenceable type \tcode{T}, the same result as + \tcode{is_assignable_v}, otherwise \tcode{false}. & + \tcode{T} shall be a complete type, \cv{}~\keyword{void}, + or an array of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_swappable_with}% +\tcode{template}\br + \tcode{struct is_swappable_with;} & + The expressions \tcode{swap(declval(), declval())} and + \tcode{swap(declval(), declval())} are each well-formed + when treated as an unevaluated operand\iref{term.unevaluated.operand} + in an overload-resolution context + for swappable values\iref{swappable.requirements}. + Access checking is performed as if in a context + unrelated to \tcode{T} and \tcode{U}. + Only the validity of the immediate context + of the \tcode{swap} expressions is considered. + \begin{tailnote} + The compilation of the expressions can result in side effects + such as the instantiation of class template specializations and + function template specializations, + the generation of implicitly-defined functions, and so on. + Such side effects are not in the ``immediate context'' and + can result in the program being ill-formed. + \end{tailnote} +& + \tcode{T} and \tcode{U} shall be complete types, + \cv{}~\keyword{void}, or + arrays of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_swappable}% +\tcode{template}\br + \tcode{struct is_swappable;} & + For a referenceable type \tcode{T}, + the same result as \tcode{is_swappable_with_v}, + otherwise \tcode{false}. & + \tcode{T} shall be a complete type, + \cv{}~\keyword{void}, or + an array of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_destructible}% +\tcode{template}\br + \tcode{struct is_destructible;} & + Either \tcode{T} is a reference type, + or \tcode{T} is a complete object type + for which the expression + \tcode{declval().\~U()} + is well-formed + when treated as an unevaluated operand\iref{term.unevaluated.operand}, + where \tcode{U} is + \tcode{remove_all_extents_t}. & + \tcode{T} shall be a complete type, \cv{}~\keyword{void}, + or an array of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_trivially_constructible}% +\tcode{template}\br + \keyword{struct}\br + \tcode{is_trivially_constructible;} & + \tcode{is_constructible_v} is \tcode{true} and the variable + definition for \tcode{is_constructible}, as defined below, is known to call + no operation that is not trivial\iref{term.trivial.type,special}. & + \tcode{T} and all types in the template parameter pack \tcode{Args} shall be complete types, + \cv{}~\keyword{void}, or arrays of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_trivially_default_constructible}% +\tcode{template}\br + \tcode{struct is_trivially_default_constructible;} & + \tcode{is_trivially_constructible_v} is \tcode{true}. & + \tcode{T} shall be a complete type, + \cv{}~\keyword{void}, or an array of unknown + bound. \\ \rowsep + +\indexlibraryglobal{is_trivially_copy_constructible}% +\tcode{template}\br + \tcode{struct is_trivially_copy_constructible;} & + For a referenceable type \tcode{T}, the same result as + \tcode{is_trivially_constructible_v}, otherwise \tcode{false}. & + \tcode{T} shall be a complete type, + \cv{}~\keyword{void}, or an array of unknown + bound. \\ \rowsep + +\indexlibraryglobal{is_trivially_move_constructible}% +\tcode{template}\br + \tcode{struct is_trivially_move_constructible;} & + For a referenceable type \tcode{T}, the same result as + \tcode{is_trivially_constructible_v}, otherwise \tcode{false}. & + \tcode{T} shall be a complete type, + \cv{}~\keyword{void}, or an array of unknown + bound. \\ \rowsep + +\indexlibraryglobal{is_trivially_assignable}% +\tcode{template}\br + \tcode{struct is_trivially_assignable;} & + \tcode{is_assignable_v} is \tcode{true} and the assignment, as defined by + \tcode{is_assignable}, is known to call no operation that is not + trivial\iref{term.trivial.type,special}. & + \tcode{T} and \tcode{U} shall be complete types, \cv{}~\keyword{void}, + or arrays of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_trivially_copy_assignable}% +\tcode{template}\br + \tcode{struct is_trivially_copy_assignable;} & + For a referenceable type \tcode{T}, the same result as + \tcode{is_trivially_assignable_v}, otherwise \tcode{false}. & + \tcode{T} shall be a complete type, + \cv{}~\keyword{void}, or an array of unknown + bound. \\ \rowsep + +\indexlibraryglobal{is_trivially_move_assignable}% +\tcode{template}\br + \tcode{struct is_trivially_move_assignable;} & + For a referenceable type \tcode{T}, the same result as + \tcode{is_trivially_assignable_v}, otherwise \tcode{false}. & + \tcode{T} shall be a complete type, + \cv{}~\keyword{void}, or an array of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_trivially_destructible}% +\tcode{template}\br + \tcode{struct is_trivially_destructible;} & + \tcode{is_destructible_v} is \tcode{true} and + \tcode{remove_all_extents_t} is either a non-class type or + a class type with a trivial destructor. & + \tcode{T} shall be a complete type, + \cv{}~\keyword{void}, or an array of unknown + bound. \\ \rowsep + +\indexlibraryglobal{is_nothrow_constructible}% +\tcode{template}\br + \tcode{struct is_nothrow_constructible;} & + \tcode{is_constructible_v} is \tcode{true} + and the + variable definition for \tcode{is_constructible}, as defined below, is known not to + throw any exceptions\iref{expr.unary.noexcept}. + & + \tcode{T} and all types in the template parameter pack \tcode{Args} + shall be complete types, \cv{}~\keyword{void}, + or arrays of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_nothrow_default_constructible}% +\tcode{template}\br + \tcode{struct is_nothrow_default_constructible;} & + \tcode{is_nothrow_constructible_v} is \tcode{true}. & + \tcode{T} shall be a complete type, + \cv{}~\keyword{void}, or an array of unknown + bound. \\ \rowsep + +\indexlibraryglobal{is_nothrow_copy_constructible}% +\tcode{template}\br + \tcode{struct is_nothrow_copy_constructible;} & + For a referenceable type \tcode{T}, the same result as + \tcode{is_nothrow_constructible_v}, otherwise \tcode{false}. & + \tcode{T} shall be a complete type, + \cv{}~\keyword{void}, or an array of unknown + bound. \\ \rowsep + +\indexlibraryglobal{is_nothrow_move_constructible}% +\tcode{template}\br + \tcode{struct is_nothrow_move_constructible;} & + For a referenceable type \tcode{T}, the same result as + \tcode{is_nothrow_constructible_v}, otherwise \tcode{false}. & + \tcode{T} shall be a complete type, + \cv{}~\keyword{void}, or an array of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_nothrow_assignable}% +\tcode{template}\br + \tcode{struct is_nothrow_assignable;} & + \tcode{is_assignable_v} is \tcode{true} and the assignment is known not to + throw any exceptions\iref{expr.unary.noexcept}. & + \tcode{T} and \tcode{U} shall be complete types, \cv{}~\keyword{void}, + or arrays of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_nothrow_copy_assignable}% +\tcode{template}\br + \tcode{struct is_nothrow_copy_assignable;} & + For a referenceable type \tcode{T}, the same result as + \tcode{is_nothrow_assignable_v}, otherwise \tcode{false}. & + \tcode{T} shall be a complete type, + \cv{}~\keyword{void}, or an array of unknown + bound. \\ \rowsep + +\indexlibraryglobal{is_nothrow_move_assignable}% +\tcode{template}\br + \tcode{struct is_nothrow_move_assignable;} & + For a referenceable type \tcode{T}, the same result as + \tcode{is_nothrow_assignable_v}, otherwise \tcode{false}. & + \tcode{T} shall be a complete type, + \cv{}~\keyword{void}, or an array of unknown + bound. \\ \rowsep + +\indexlibraryglobal{is_nothrow_swappable_with}% +\tcode{template}\br + \tcode{struct is_nothrow_swappable_with;} & + \tcode{is_swappable_with_v} is \tcode{true} and + each \tcode{swap} expression of the definition of + \tcode{is_swappable_with} is known not to throw + any exceptions\iref{expr.unary.noexcept}. & + \tcode{T} and \tcode{U} shall be complete types, + \cv{}~\keyword{void}, or + arrays of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_nothrow_swappable}% +\tcode{template}\br + \tcode{struct is_nothrow_swappable;} & + For a referenceable type \tcode{T}, + the same result as \tcode{is_nothrow_swappable_with_v}, + otherwise \tcode{false}. & + \tcode{T} shall be a complete type, + \cv{}~\keyword{void}, or + an array of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_nothrow_destructible}% +\tcode{template}\br + \tcode{struct is_nothrow_destructible;} & + \tcode{is_destructible_v} is \tcode{true} and the indicated destructor is known + not to throw any exceptions\iref{expr.unary.noexcept}. & + \tcode{T} shall be a complete type, + \cv{}~\keyword{void}, or an array of unknown + bound. \\ \rowsep + +\indexlibraryglobal{has_virtual_destructor}% +\tcode{template}\br + \tcode{struct has_virtual_destructor;} & + \tcode{T} has a virtual destructor\iref{class.dtor} & + If \tcode{T} is a non-union class type, \tcode{T} shall be a complete type. \\ \rowsep + +\indexlibraryglobal{has_unique_object_representations}% +\tcode{template}\br + \tcode{struct has_unique_object_representations;} & + For an array type \tcode{T}, the same result as + \tcode{has_unique_object_representations_v>}, + otherwise \seebelow. & + \tcode{T} shall be a complete type, \cv{}~\keyword{void}, or + an array of unknown bound. \\ \rowsep + +\indexlibraryglobal{reference_constructs_from_temporary}% +\tcode{template}\br + \tcode{struct reference_constructs_from_temporary;} & + \tcode{conjunction_v, is_constructible>} + is \tcode{true}, and + the initialization \tcode{T t(\exposidnc{VAL});} binds \tcode{t} to + a temporary object whose lifetime is extended\iref{class.temporary}. & + \tcode{T} and \tcode{U} shall be + complete types, \cv{}~\keyword{void}, or arrays of unknown bound. \\ \rowsep + +\indexlibraryglobal{reference_converts_from_temporary}% +\tcode{template}\br + \tcode{struct reference_converts_from_temporary;} & + \tcode{conjunction_v, is_convertible>} is \tcode{true}, + and the initialization \tcode{T t = \exposidnc{VAL};} binds \tcode{t} to + a temporary object whose lifetime is extended\iref{class.temporary}. & + \tcode{T} and \tcode{U} shall be + complete types, \cv{}~\keyword{void}, or arrays of unknown bound. \\ \rowsep + +\end{libreqtab3b} + +\pnum +\begin{example} +\begin{codeblock} +is_const_v // \tcode{true} +is_const_v // \tcode{false} +is_const_v // \tcode{false} +is_const_v // \tcode{false} +is_const_v // \tcode{true} +\end{codeblock} +\end{example} + +\pnum +\begin{example} +\begin{codeblock} +remove_const_t // \tcode{volatile int} +remove_const_t // \tcode{const int*} +remove_const_t // \tcode{const int\&} +remove_const_t // \tcode{int[3]} +\end{codeblock} +\end{example} + +\pnum +\begin{example} +\begin{codeblock} +// Given: +struct P final { }; +union U1 { }; +union U2 final { }; + +// the following assertions hold: +static_assert(!is_final_v); +static_assert(is_final_v

()(a, b)}, +\tcode{(a > b) == greater

()(a, b)}, and so forth. +\end{note} +For template specializations \tcode{less}, \tcode{greater}, +\tcode{less_equal}, and \tcode{greater_equal}, +if the call operator calls a built-in operator comparing pointers, +the call operator yields a result consistent +with the implementation-defined strict total order over pointers. -\rSec3[allocator.members]{Members} +\rSec3[comparisons.equal.to]{Class template \tcode{equal_to}} -\pnum -Except for the destructor, member functions of the default allocator shall not introduce -data races\iref{intro.multithread} as a result of concurrent calls to those member -functions from different threads. Calls to these functions that allocate or deallocate a -particular unit of storage shall occur in a single total order, and each such -deallocation call shall happen before the next allocation (if any) in this order. +\indexlibraryglobal{equal_to}% +\begin{itemdecl} +template struct equal_to { + constexpr bool operator()(const T& x, const T& y) const; +}; +\end{itemdecl} -\indexlibrarymember{allocate}{allocator}% +\indexlibrarymember{operator()}{equal_to}% \begin{itemdecl} -[[nodiscard]] constexpr T* allocate(size_t n); +constexpr bool operator()(const T& x, const T& y) const; \end{itemdecl} \begin{itemdescr} -\pnum -\mandates -\tcode{T} is not an incomplete type\iref{term.incomplete.type}. - \pnum \returns -A pointer to the initial element of an array of \tcode{n} \tcode{T}. +\tcode{x == y}. +\end{itemdescr} -\pnum -\throws -\tcode{bad_array_new_length} if -\tcode{numeric_limits::max() / sizeof(T) < n}, or -\tcode{bad_alloc} if the storage cannot be obtained. +\indexlibraryglobal{equal_to<>}% +\begin{itemdecl} +template<> struct equal_to { + template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) == std::forward(u)); -\pnum -\remarks -The storage for the array -is obtained by calling \tcode{::operator new}\iref{new.delete}, -but it is unspecified when or how often this -function is called. -This function starts the lifetime of the array object, -but not that of any of the array elements. -\end{itemdescr} + using is_transparent = @\unspec@; +}; +\end{itemdecl} -\indexlibrarymember{allocate_at_least}{allocator}% +\indexlibrarymember{operator()}{equal_to<>}% \begin{itemdecl} -[[nodiscard]] constexpr allocation_result allocate_at_least(size_t n); +template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) == std::forward(u)); \end{itemdecl} \begin{itemdescr} -\pnum -\mandates -\tcode{T} is not an incomplete type\iref{term.incomplete.type}. - \pnum \returns -\tcode{allocation_result\{ptr, count\}}, -where \tcode{ptr} is a pointer to -the initial element of an array of \tcode{count} \tcode{T} and -$\tcode{count} \geq \tcode{n}$. +\tcode{std::forward(t) == std::forward(u)}. +\end{itemdescr} -\pnum -\throws -\tcode{bad_array_new_length} -if $\tcode{numeric_limits::max() / sizeof(T)} < \tcode{n}$, -or \tcode{bad_alloc} if the storage cannot be obtained. +\rSec3[comparisons.not.equal.to]{Class template \tcode{not_equal_to}} -\pnum -\remarks -The storage for the array is obtained by calling \tcode{::operator new}, -but it is unspecified when or how often this function is called. -This function starts the lifetime of the array object, -but not that of any of the array elements. -\end{itemdescr} +\indexlibraryglobal{not_equal_to}% +\begin{itemdecl} +template struct not_equal_to { + constexpr bool operator()(const T& x, const T& y) const; +}; +\end{itemdecl} -\indexlibrarymember{deallocate}{allocator}% +\indexlibrarymember{operator()}{not_equal_to}% \begin{itemdecl} -constexpr void deallocate(T* p, size_t n); +constexpr bool operator()(const T& x, const T& y) const; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\begin{itemize} -\item -If \tcode{p} is memory that was obtained by a call to \tcode{allocate_at_least}, -let \tcode{ret} be the value returned and -\tcode{req} be the value passed as the first argument to that call. -\tcode{p} is equal to \tcode{ret.ptr} and -\tcode{n} is a value such that $\tcode{req} \leq \tcode{n} \leq \tcode{ret.count}$. -\item -Otherwise, \tcode{p} is a pointer value obtained from \tcode{allocate}. -\tcode{n} equals the value passed as the first argument -to the invocation of \tcode{allocate} which returned \tcode{p}. -\end{itemize} - -\pnum -\effects -Deallocates the storage referenced by \tcode{p}. - -\pnum -\remarks -Uses -\tcode{::operator delete}\iref{new.delete}, -but it is unspecified -when this function is called. +\returns +\tcode{x != y}. \end{itemdescr} -\rSec3[allocator.globals]{Operators} +\indexlibraryglobal{not_equal_to<>}% +\begin{itemdecl} +template<> struct not_equal_to { + template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) != std::forward(u)); + + using is_transparent = @\unspec@; +}; +\end{itemdecl} -\indexlibrarymember{operator==}{allocator}% +\indexlibrarymember{operator()}{not_equal_to<>}% \begin{itemdecl} -template - constexpr bool operator==(const allocator&, const allocator&) noexcept; +template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) != std::forward(u)); \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{true}. +\tcode{std::forward(t) != std::forward(u)}. \end{itemdescr} -\rSec2[specialized.addressof]{\tcode{addressof}} +\rSec3[comparisons.greater]{Class template \tcode{greater}} + +\indexlibraryglobal{greater}% +\begin{itemdecl} +template struct greater { + constexpr bool operator()(const T& x, const T& y) const; +}; +\end{itemdecl} -\indexlibraryglobal{addressof}% +\indexlibrarymember{operator()}{greater}% \begin{itemdecl} -template constexpr T* addressof(T& r) noexcept; +constexpr bool operator()(const T& x, const T& y) const; \end{itemdecl} \begin{itemdescr} \pnum \returns -The actual address of the object or function referenced by \tcode{r}, even in the -presence of an overloaded \tcode{operator\&}. - -\pnum -\remarks -An expression \tcode{addressof(E)} -is a constant subexpression\iref{defns.const.subexpr} -if \tcode{E} is an lvalue constant subexpression. +\tcode{x > y}. \end{itemdescr} -\rSec2[c.malloc]{C library memory allocation} +\indexlibraryglobal{greater<>}% +\begin{itemdecl} +template<> struct greater { + template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) > std::forward(u)); -\pnum -\begin{note} -The header \libheaderref{cstdlib} -declares the functions described in this subclause. -\end{note} + using is_transparent = @\unspec@; +}; +\end{itemdecl} -\indexlibraryglobal{aligned_alloc}% -\indexlibraryglobal{calloc}% -\indexlibraryglobal{malloc}% -\indexlibraryglobal{realloc}% +\indexlibrarymember{operator()}{greater<>}% \begin{itemdecl} -void* aligned_alloc(size_t alignment, size_t size); -void* calloc(size_t nmemb, size_t size); -void* malloc(size_t size); -void* realloc(void* ptr, size_t size); +template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) > std::forward(u)); \end{itemdecl} \begin{itemdescr} \pnum -\effects -These functions have the semantics specified in the C standard library. +\returns +\tcode{std::forward(t) > std::forward(u)}. +\end{itemdescr} -\pnum -\remarks -These functions do not attempt to allocate -storage by calling \tcode{::operator new()}\iref{new.delete}. -\indexlibrarymember{new}{operator}% +\rSec3[comparisons.less]{Class template \tcode{less}} -\pnum -These functions implicitly create objects\iref{intro.object} -in the returned region of storage and -return a pointer to a suitable created object. -In the case of \tcode{calloc} and \tcode{realloc}, -the objects are created before the storage is zeroed or copied, respectively. -\end{itemdescr} +\indexlibraryglobal{less}% +\begin{itemdecl} +template struct less { + constexpr bool operator()(const T& x, const T& y) const; +}; +\end{itemdecl} -\indexlibraryglobal{free}% +\indexlibrarymember{operator()}{less}% \begin{itemdecl} -void free(void* ptr); +constexpr bool operator()(const T& x, const T& y) const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -This function has the semantics specified in the C standard library. - -\pnum -\remarks -This function does not attempt to -deallocate storage by calling -\tcode{::operator delete()}\indexlibrarymember{delete}{operator}. +\returns +\tcode{x < y}. \end{itemdescr} -\xrefc{7.22.3} - -\rSec1[smartptr]{Smart pointers} +\indexlibraryglobal{less<>}% +\begin{itemdecl} +template<> struct less { + template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) < std::forward(u)); -\rSec2[unique.ptr]{Unique-ownership pointers} + using is_transparent = @\unspec@; +}; +\end{itemdecl} -\rSec3[unique.ptr.general]{General} +\indexlibrarymember{operator()}{less<>}% +\begin{itemdecl} +template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) < std::forward(u)); +\end{itemdecl} +\begin{itemdescr} \pnum -A \defn{unique pointer} is an object that owns another object and -manages that other object through a pointer. More precisely, a unique pointer -is an object \textit{u} that stores a pointer to a second object \textit{p} and -will dispose of \textit{p} when \textit{u} is itself destroyed (e.g., when -leaving block scope\iref{stmt.dcl}). In this context, \textit{u} is said -to \defn{own} \tcode{p}. +\returns +\tcode{std::forward(t) < std::forward(u)}. +\end{itemdescr} -\pnum -The mechanism by which \textit{u} disposes of \textit{p} is known as -\textit{p}'s associated \defn{deleter}, a function object whose correct -invocation results in \textit{p}'s appropriate disposition (typically its deletion). +\rSec3[comparisons.greater.equal]{Class template \tcode{greater_equal}} -\pnum -Let the notation \textit{u.p} denote the pointer stored by \textit{u}, and -let \textit{u.d} denote the associated deleter. Upon request, \textit{u} can -\defn{reset} (replace) \textit{u.p} and \textit{u.d} with another pointer and -deleter, but properly disposes of its owned object via the associated -deleter before such replacement is considered completed. +\indexlibraryglobal{greater_equal}% +\begin{itemdecl} +template struct greater_equal { + constexpr bool operator()(const T& x, const T& y) const; +}; +\end{itemdecl} -\pnum -Each object of a type \tcode{U} instantiated from the \tcode{unique_ptr} template -specified in \ref{unique.ptr} has the strict ownership semantics, specified above, -of a unique pointer. In partial satisfaction of these semantics, each such \tcode{U} -is \oldconcept{MoveConstructible} and \oldconcept{MoveAssignable}, but is not -\oldconcept{CopyConstructible} nor \oldconcept{CopyAssignable}. -The template parameter \tcode{T} of \tcode{unique_ptr} may be an incomplete type. +\indexlibrarymember{operator()}{greater_equal}% +\begin{itemdecl} +constexpr bool operator()(const T& x, const T& y) const; +\end{itemdecl} +\begin{itemdescr} \pnum -\begin{note} -The uses -of \tcode{unique_ptr} include providing exception safety for -dynamically allocated memory, passing ownership of dynamically allocated -memory to a function, and returning dynamically allocated memory from a -function. -\end{note} +\returns +\tcode{x >= y}. +\end{itemdescr} -\rSec3[unique.ptr.dltr]{Default deleters} +\indexlibraryglobal{greater_equal<>}% +\begin{itemdecl} +template<> struct greater_equal { + template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) >= std::forward(u)); -\rSec4[unique.ptr.dltr.general]{In general} + using is_transparent = @\unspec@; +}; +\end{itemdecl} -\pnum -The class template \tcode{default_delete} serves as the default deleter (destruction policy) -for the class template \tcode{unique_ptr}. +\indexlibrarymember{operator()}{greater_equal<>}% +\begin{itemdecl} +template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) >= std::forward(u)); +\end{itemdecl} +\begin{itemdescr} \pnum -The template parameter \tcode{T} of \tcode{default_delete} may be -an incomplete type. +\returns +\tcode{std::forward(t) >= std::forward(u)}. +\end{itemdescr} -\rSec4[unique.ptr.dltr.dflt]{\tcode{default_delete}} +\rSec3[comparisons.less.equal]{Class template \tcode{less_equal}} -\begin{codeblock} -namespace std { - template struct default_delete { - constexpr default_delete() noexcept = default; - template constexpr default_delete(const default_delete&) noexcept; - constexpr void operator()(T*) const; - }; -} -\end{codeblock} +\indexlibraryglobal{less_equal}% +\begin{itemdecl} +template struct less_equal { + constexpr bool operator()(const T& x, const T& y) const; +}; +\end{itemdecl} -\indexlibraryctor{default_delete}% +\indexlibrarymember{operator()}{less_equal}% \begin{itemdecl} -template constexpr default_delete(const default_delete& other) noexcept; +constexpr bool operator()(const T& x, const T& y) const; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{U*} is implicitly convertible to \tcode{T*}. - -\pnum -\effects -Constructs a \tcode{default_delete} object -from another \tcode{default_delete} object. +\returns +\tcode{x <= y}. \end{itemdescr} -\indexlibrarymember{operator()}{default_delete}% +\indexlibraryglobal{less_equal<>}% \begin{itemdecl} -constexpr void operator()(T* ptr) const; +template<> struct less_equal { + template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) <= std::forward(u)); + + using is_transparent = @\unspec@; +}; \end{itemdecl} -\begin{itemdescr} -\pnum -\mandates -\tcode{T} is a complete type. +\indexlibrarymember{operator()}{less_equal<>}% +\begin{itemdecl} +template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) <= std::forward(u)); +\end{itemdecl} +\begin{itemdescr} \pnum -\effects -Calls \keyword{delete} on \tcode{ptr}. +\returns +\tcode{std::forward(t) <= std::forward(u)}. \end{itemdescr} -\rSec4[unique.ptr.dltr.dflt1]{\tcode{default_delete}} +\rSec3[comparisons.three.way]{Class \tcode{compare_three_way}} +\indexlibraryglobal{compare_three_way}% \begin{codeblock} namespace std { - template struct default_delete { - constexpr default_delete() noexcept = default; - template constexpr default_delete(const default_delete&) noexcept; - template constexpr void operator()(U* ptr) const; + struct compare_three_way { + template + constexpr auto operator()(T&& t, U&& u) const; + + using is_transparent = @\unspec@; }; } \end{codeblock} -\indexlibraryctor{default_delete} -\begin{itemdecl} -template constexpr default_delete(const default_delete& other) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{U(*)[]} is convertible to \tcode{T(*)[]}. - -\pnum -\effects -Constructs a \tcode{default_delete} object from another \tcode{default_delete} object. -\end{itemdescr} - -\indexlibrarymember{operator()}{default_delete}% \begin{itemdecl} -template constexpr void operator()(U* ptr) const; +template + constexpr auto operator()(T&& t, U&& u) const; \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{U(*)[]} is convertible to \tcode{T(*)[]}. +\tcode{T} and \tcode{U} satisfy \libconcept{three_way_comparable_with}. \pnum -\mandates -\tcode{U} is a complete type. +\expects +If the expression \tcode{std::forward(t) <=> std::forward(u)} results in +a call to a built-in operator \tcode{<=>} comparing pointers of type \tcode{P}, +the conversion sequences from both \tcode{T} and \tcode{U} to \tcode{P} +are equality-preserving\iref{concepts.equality}; +otherwise, \tcode{T} and \tcode{U} model \libconcept{three_way_comparable_with}. \pnum \effects -Calls \tcode{delete[]} on \tcode{ptr}. +\begin{itemize} +\item + If the expression \tcode{std::forward(t) <=> std::forward(u)} results in + a call to a built-in operator \tcode{<=>} comparing pointers of type \tcode{P}, + returns \tcode{strong_ordering::less} + if (the converted value of) \tcode{t} precedes \tcode{u} + in the implementation-defined strict total order + over pointers\iref{defns.order.ptr}, + \tcode{strong_ordering::greater} + if \tcode{u} precedes \tcode{t}, and + otherwise \tcode{strong_ordering::equal}. +\item + Otherwise, equivalent to: \tcode{return std::forward(t) <=> std::forward(u);} +\end{itemize} \end{itemdescr} -\rSec3[unique.ptr.single]{\tcode{unique_ptr} for single objects} - -\rSec4[unique.ptr.single.general]{General} +\rSec2[range.cmp]{Concept-constrained comparisons} -\indexlibraryglobal{unique_ptr}% +\indexlibraryglobal{equal_to}% \begin{codeblock} -namespace std { - template> class unique_ptr { - public: - using pointer = @\seebelow@; - using element_type = T; - using deleter_type = D; - - // \ref{unique.ptr.single.ctor}, constructors - constexpr unique_ptr() noexcept; - constexpr explicit unique_ptr(type_identity_t p) noexcept; - constexpr unique_ptr(type_identity_t p, @\seebelow@ d1) noexcept; - constexpr unique_ptr(type_identity_t p, @\seebelow@ d2) noexcept; - constexpr unique_ptr(unique_ptr&& u) noexcept; - constexpr unique_ptr(nullptr_t) noexcept; - template - constexpr unique_ptr(unique_ptr&& u) noexcept; - - // \ref{unique.ptr.single.dtor}, destructor - constexpr ~unique_ptr(); - - // \ref{unique.ptr.single.asgn}, assignment - constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; - template - constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; - constexpr unique_ptr& operator=(nullptr_t) noexcept; - - // \ref{unique.ptr.single.observers}, observers - constexpr add_lvalue_reference_t operator*() const noexcept(@\seebelow@); - constexpr pointer operator->() const noexcept; - constexpr pointer get() const noexcept; - constexpr deleter_type& get_deleter() noexcept; - constexpr const deleter_type& get_deleter() const noexcept; - constexpr explicit operator bool() const noexcept; - - // \ref{unique.ptr.single.modifiers}, modifiers - constexpr pointer release() noexcept; - constexpr void reset(pointer p = pointer()) noexcept; - constexpr void swap(unique_ptr& u) noexcept; +struct ranges::equal_to { + template + constexpr bool operator()(T&& t, U&& u) const; - // disable copy from lvalue - unique_ptr(const unique_ptr&) = delete; - unique_ptr& operator=(const unique_ptr&) = delete; - }; -} + using is_transparent = @\unspecnc@; +}; \end{codeblock} -\pnum -The default type for the template parameter \tcode{D} is -\tcode{default_delete}. A client-supplied template argument -\tcode{D} shall be a function -object type\iref{function.objects}, lvalue reference to function, or -lvalue reference to function object type -for which, given -a value \tcode{d} of type \tcode{D} and a value -\tcode{ptr} of type \tcode{unique_ptr::pointer}, the expression -\tcode{d(ptr)} is valid and has the effect of disposing of the -pointer as appropriate for that deleter. - -\pnum -If the deleter's type \tcode{D} is not a reference type, \tcode{D} shall meet -the \oldconcept{Destructible} requirements (\tref{cpp17.destructible}). - -\pnum -If the \grammarterm{qualified-id} \tcode{remove_reference_t::pointer} is valid and denotes a -type\iref{temp.deduct}, then \tcode{unique_ptr::pointer} shall be a synonym for \tcode{remove_reference_t::pointer}. Otherwise -\tcode{unique_ptr::pointer} shall be a synonym for \tcode{element_type*}. The type \tcode{unique_ptr::pointer} shall -meet the \oldconcept{NullablePointer} requirements (\tref{cpp17.nullablepointer}). - -\pnum -\begin{example} -Given an allocator type \tcode{X} (\tref{cpp17.allocator}) and -letting \tcode{A} be a synonym for \tcode{allocator_traits}, the types \tcode{A::pointer}, -\tcode{A::const_pointer}, \tcode{A::void_pointer}, and \tcode{A::const_void_pointer} -may be used as \tcode{unique_ptr::pointer}. -\end{example} - -\rSec4[unique.ptr.single.ctor]{Constructors} - -\indexlibraryctor{unique_ptr}% \begin{itemdecl} -constexpr unique_ptr() noexcept; -constexpr unique_ptr(nullptr_t) noexcept; +template + constexpr bool operator()(T&& t, U&& u) const; \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{is_pointer_v} is \tcode{false} and -\tcode{is_default_constructible_v} is \tcode{true}. +\tcode{T} and \tcode{U} satisfy \libconcept{equality_comparable_with}. \pnum \expects -\tcode{D} meets the \oldconcept{DefaultConstructible} requirements (\tref{cpp17.defaultconstructible}), -and that construction does not throw an exception. +If the expression \tcode{std::forward(t) == std::forward(u)} +results in a call to a built-in operator \tcode{==} comparing pointers of type +\tcode{P}, the conversion sequences from both \tcode{T} and \tcode{U} to \tcode{P} +are equality-preserving\iref{concepts.equality}; +otherwise, \tcode{T} and \tcode{U} model \libconcept{equality_comparable_with}. \pnum \effects -Constructs a \tcode{unique_ptr} object that owns -nothing, value-initializing the stored pointer and the stored deleter. +\begin{itemize} +\item + If the expression \tcode{std::forward(t) == std::forward(u)} results in + a call to a built-in operator \tcode{==} comparing pointers: + returns \tcode{false} if either (the converted value of) \tcode{t} precedes + \tcode{u} or \tcode{u} precedes \tcode{t} in the implementation-defined strict + total order over pointers\iref{defns.order.ptr} and otherwise \tcode{true}. -\pnum -\ensures -\tcode{get() == nullptr}. \tcode{get_deleter()} -returns a reference to the stored deleter. +\item + Otherwise, equivalent to: + \tcode{return std::forward(t) == std::forward(u);} +\end{itemize} \end{itemdescr} -\indexlibraryctor{unique_ptr}% +\indexlibraryglobal{not_equal_to}% +\begin{codeblock} +struct ranges::not_equal_to { + template + constexpr bool operator()(T&& t, U&& u) const; + + using is_transparent = @\unspecnc@; +}; +\end{codeblock} + \begin{itemdecl} -constexpr explicit unique_ptr(type_identity_t p) noexcept; +template + constexpr bool operator()(T&& t, U&& u) const; \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{is_pointer_v} is \tcode{false} and -\tcode{is_default_constructible_v} is \tcode{true}. - -\pnum -\expects -\tcode{D} meets the \oldconcept{DefaultConstructible} requirements (\tref{cpp17.defaultconstructible}), -and that construction does not throw an exception. +\tcode{T} and \tcode{U} satisfy \libconcept{equality_comparable_with}. \pnum \effects -Constructs a \tcode{unique_ptr} which owns -\tcode{p}, initializing the stored pointer with \tcode{p} and -value-initializing the stored deleter. - -\pnum -\ensures -\tcode{get() == p}. \tcode{get_deleter()} -returns a reference to the stored deleter. +Equivalent to: +\begin{codeblock} +return !ranges::equal_to{}(std::forward(t), std::forward(u)); +\end{codeblock} \end{itemdescr} -\indexlibraryctor{unique_ptr}% +\indexlibraryglobal{greater}% +\begin{codeblock} +struct ranges::greater { + template + constexpr bool operator()(T&& t, U&& u) const; + + using is_transparent = @\unspecnc@; +}; +\end{codeblock} + \begin{itemdecl} -constexpr unique_ptr(type_identity_t p, const D& d) noexcept; -constexpr unique_ptr(type_identity_t p, remove_reference_t&& d) noexcept; +template + constexpr bool operator()(T&& t, U&& u) const; \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{is_constructible_v} is \tcode{true}. - -\pnum -\expects -For the first constructor, if \tcode{D} is not a reference type, -\tcode{D} meets the \oldconcept{CopyConstructible} requirements and -such construction does not exit via an exception. -For the second constructor, if \tcode{D} is not a reference type, -\tcode{D} meets the \oldconcept{MoveConstructible} requirements and -such construction does not exit via an exception. +\tcode{T} and \tcode{U} satisfy \libconcept{totally_ordered_with}. \pnum \effects -Constructs a \tcode{unique_ptr} object which owns \tcode{p}, initializing -the stored pointer with \tcode{p} and initializing the deleter -from \tcode{std::forward(d)}. - -\pnum -\ensures -\tcode{get() == p}. -\tcode{get_deleter()} returns a reference to the stored -deleter. If \tcode{D} is a reference type then \tcode{get_deleter()} -returns a reference to the lvalue \tcode{d}. - -\pnum -\remarks -If \tcode{D} is a reference type, -the second constructor is defined as deleted. - -\pnum -\begin{example} +Equivalent to: \begin{codeblock} -D d; -unique_ptr p1(new int, D()); // \tcode{D} must be \oldconcept{MoveConstructible} -unique_ptr p2(new int, d); // \tcode{D} must be \oldconcept{CopyConstructible} -unique_ptr p3(new int, d); // \tcode{p3} holds a reference to \tcode{d} -unique_ptr p4(new int, D()); // error: rvalue deleter object combined - // with reference deleter type +return ranges::less{}(std::forward(u), std::forward(t)); \end{codeblock} -\end{example} \end{itemdescr} -\indexlibraryctor{unique_ptr}% +\indexlibraryglobal{less}% +\begin{codeblock} +struct ranges::less { + template + constexpr bool operator()(T&& t, U&& u) const; + + using is_transparent = @\unspecnc@; +}; +\end{codeblock} + \begin{itemdecl} -constexpr unique_ptr(unique_ptr&& u) noexcept; +template + constexpr bool operator()(T&& t, U&& u) const; \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{is_move_constructible_v} is \tcode{true}. +\tcode{T} and \tcode{U} satisfy \libconcept{totally_ordered_with}. \pnum \expects -If \tcode{D} is not a reference type, -\tcode{D} meets the \oldconcept{MoveConstructible} -requirements (\tref{cpp17.moveconstructible}). -Construction -of the deleter from an rvalue of type \tcode{D} does not -throw an exception. +If the expression \tcode{std::forward(t) < std::forward(u)} results in a +call to a built-in operator \tcode{<} comparing pointers of type \tcode{P}, the +conversion sequences from both \tcode{T} and \tcode{U} to \tcode{P} are +equality-preserving\iref{concepts.equality}; +otherwise, \tcode{T} and \tcode{U} model \libconcept{totally_ordered_with}. +For any expressions +\tcode{ET} and \tcode{EU} such that \tcode{decltype((ET))} is \tcode{T} and +\tcode{decltype((EU))} is \tcode{U}, exactly one of +\tcode{ranges::less\{\}(ET, EU)}, +\tcode{ranges::less\{\}(EU, ET)}, or +\tcode{ranges::equal_to\{\}(ET, EU)} +is \tcode{true}. \pnum \effects -Constructs a \tcode{unique_ptr} from -\tcode{u}. If \tcode{D} is a reference type, this -deleter is copy constructed from \tcode{u}'s deleter; otherwise, this -deleter is move constructed from \tcode{u}'s deleter. -\begin{note} -The -construction of the deleter can be implemented with \tcode{std::forward}. -\end{note} +\begin{itemize} +\item +If the expression \tcode{std::forward(t) < std::forward(u)} results in a +call to a built-in operator \tcode{<} comparing pointers: +returns \tcode{true} if (the converted value of) \tcode{t} precedes \tcode{u} in +the implementation-defined strict total order over pointers\iref{defns.order.ptr} +and otherwise \tcode{false}. -\pnum -\ensures -\tcode{get()} yields the value \tcode{u.get()} -yielded before the construction. \tcode{u.get() == nullptr}. -\tcode{get_deleter()} returns a reference -to the stored deleter that was constructed from -\tcode{u.get_deleter()}. If \tcode{D} is a reference type then -\tcode{get_deleter()} and \tcode{u.get_deleter()} both reference -the same lvalue deleter. +\item +Otherwise, equivalent to: +\tcode{return std::forward(t) < std::forward(u);} +\end{itemize} \end{itemdescr} -\indexlibraryctor{unique_ptr}% +\indexlibraryglobal{greater_equal}% +\begin{codeblock} +struct ranges::greater_equal { + template + constexpr bool operator()(T&& t, U&& u) const; + + using is_transparent = @\unspecnc@; +}; +\end{codeblock} + \begin{itemdecl} -template constexpr unique_ptr(unique_ptr&& u) noexcept; +template + constexpr bool operator()(T&& t, U&& u) const; \end{itemdecl} \begin{itemdescr} \pnum \constraints -\begin{itemize} -\item \tcode{unique_ptr::pointer} is implicitly convertible to \tcode{pointer}, -\item \tcode{U} is not an array type, and -\item either \tcode{D} is a reference type and \tcode{E} is the same type as \tcode{D}, or -\tcode{D} is not a reference type and \tcode{E} is implicitly convertible to \tcode{D}. -\end{itemize} - -\pnum -\expects -If \tcode{E} is not a reference type, -construction of the deleter from an rvalue of type \tcode{E} -is well-formed and does not throw an exception. -Otherwise, \tcode{E} is a reference type and -construction of the deleter from an lvalue of type \tcode{E} -is well-formed and does not throw an exception. +\tcode{T} and \tcode{U} satisfy \libconcept{totally_ordered_with}. \pnum \effects -Constructs a \tcode{unique_ptr} from \tcode{u}. -If \tcode{E} is a reference type, this deleter is copy constructed from -\tcode{u}'s deleter; otherwise, this deleter is move constructed from \tcode{u}'s -deleter. -\begin{note} -The deleter constructor can be implemented with -\tcode{std::forward}. -\end{note} - -\pnum -\ensures -\tcode{get()} yields the value \tcode{u.get()} -yielded before the construction. \tcode{u.get() == nullptr}. -\tcode{get_deleter()} returns a reference -to the stored deleter that was constructed from -\tcode{u.get_deleter()}. +Equivalent to: +\begin{codeblock} +return !ranges::less{}(std::forward(t), std::forward(u)); +\end{codeblock} \end{itemdescr} -\rSec4[unique.ptr.single.dtor]{Destructor} - -\indexlibrarydtor{unique_ptr}% +\indexlibraryglobal{less_equal}% \begin{itemdecl} -constexpr ~unique_ptr(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\tcode{if (get()) get_deleter()(get());} -\begin{note} -The use of \tcode{default_delete} requires \tcode{T} to be a complete type. -\end{note} - -\pnum -\remarks -The behavior is undefined -if the evaluation of \tcode{get_deleter()(get())} throws an exception. -\end{itemdescr} +struct ranges::less_equal { + template + constexpr bool operator()(T&& t, U&& u) const; -\rSec4[unique.ptr.single.asgn]{Assignment} + using is_transparent = @\unspecnc@; +}; +\end{itemdecl} -\indexlibrarymember{operator=}{unique_ptr}% \begin{itemdecl} -constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; +template + constexpr bool operator()(T&& t, U&& u) const; \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{is_move_assignable_v} is \tcode{true}. - -\pnum -\expects -If \tcode{D} is not a reference type, \tcode{D} meets the -\oldconcept{MoveAssignable} requirements (\tref{cpp17.moveassignable}) and assignment -of the deleter from an rvalue of type \tcode{D} does not throw an exception. -Otherwise, \tcode{D} is a reference type; -\tcode{remove_reference_t} meets the \oldconcept{CopyAssignable} -requirements and assignment of the deleter from an -lvalue of type \tcode{D} does not throw an exception. +\tcode{T} and \tcode{U} satisfy \libconcept{totally_ordered_with}. \pnum \effects -Calls \tcode{reset(u.release())} followed by -\tcode{get_deleter() = std::forward(u.get_dele\-ter())}. - -\pnum -\ensures -If \tcode{this != addressof(u)}, -\tcode{u.get() == nullptr}, -otherwise \tcode{u.get()} is unchanged. - -\pnum -\returns -\tcode{*this}. +Equivalent to: +\begin{codeblock} +return !ranges::less{}(std::forward(u), std::forward(t)); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator=}{unique_ptr}% -\begin{itemdecl} -template constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\begin{itemize} -\item \tcode{unique_ptr::pointer} is implicitly convertible to \tcode{pointer}, and -\item \tcode{U} is not an array type, and -\item \tcode{is_assignable_v} is \tcode{true}. -\end{itemize} +\rSec2[logical.operations]{Logical operations} -\pnum -\expects -If \tcode{E} is not a reference type, -assignment of the deleter from an rvalue of type \tcode{E} -is well-formed and does not throw an exception. -Otherwise, \tcode{E} is a reference type and -assignment of the deleter from an lvalue of type \tcode{E} -is well-formed and does not throw an exception. +\rSec3[logical.operations.general]{General} \pnum -\effects -Calls \tcode{reset(u.release())} followed by -\tcode{get_deleter() = std::forward(u.get_dele\-ter())}. +The library provides basic function object classes for all of the logical +operators in the language\iref{expr.log.and,expr.log.or,expr.unary.op}. -\pnum -\ensures -\tcode{u.get() == nullptr}. +\rSec3[logical.operations.and]{Class template \tcode{logical_and}} -\pnum -\returns -\tcode{*this}. -\end{itemdescr} +\indexlibraryglobal{logical_and}% +\begin{itemdecl} +template struct logical_and { + constexpr bool operator()(const T& x, const T& y) const; +}; +\end{itemdecl} -\indexlibrarymember{operator=}{unique_ptr}% +\indexlibrarymember{operator()}{logical_and}% \begin{itemdecl} -constexpr unique_ptr& operator=(nullptr_t) noexcept; +constexpr bool operator()(const T& x, const T& y) const; \end{itemdecl} \begin{itemdescr} -\pnum -\effects -As if by \tcode{reset()}. - -\pnum -\ensures -\tcode{get() == nullptr}. - \pnum \returns -\tcode{*this}. +\tcode{x \&\& y}. \end{itemdescr} -\rSec4[unique.ptr.single.observers]{Observers} +\indexlibraryglobal{logical_and<>}% +\begin{itemdecl} +template<> struct logical_and { + template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) && std::forward(u)); + + using is_transparent = @\unspec@; +}; +\end{itemdecl} -\indexlibrarymember{operator*}{unique_ptr}% +\indexlibrarymember{operator()}{logical_and<>}% \begin{itemdecl} -constexpr add_lvalue_reference_t operator*() const noexcept(noexcept(*declval())); +template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) && std::forward(u)); \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\tcode{get() != nullptr}. - \pnum \returns -\tcode{*get()}. - +\tcode{std::forward(t) \&\& std::forward(u)}. \end{itemdescr} -\indexlibrarymember{operator->}{unique_ptr}% +\rSec3[logical.operations.or]{Class template \tcode{logical_or}} + +\indexlibraryglobal{logical_or}% \begin{itemdecl} -constexpr pointer operator->() const noexcept; +template struct logical_or { + constexpr bool operator()(const T& x, const T& y) const; +}; \end{itemdecl} -\begin{itemdescr} -\pnum -\expects -\tcode{get() != nullptr}. - -\pnum -\returns -\tcode{get()}. - -\pnum -\begin{note} -The use of this function typically requires that \tcode{T} be a complete type. -\end{note} -\end{itemdescr} - -\indexlibrarymember{get}{unique_ptr}% +\indexlibrarymember{operator()}{logical_or}% \begin{itemdecl} -constexpr pointer get() const noexcept; +constexpr bool operator()(const T& x, const T& y) const; \end{itemdecl} \begin{itemdescr} \pnum \returns -The stored pointer. +\tcode{x || y}. \end{itemdescr} -\indexlibrarymember{get_deleter}{unique_ptr}% +\indexlibraryglobal{logical_or<>}% +\begin{itemdecl} +template<> struct logical_or { + template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) || std::forward(u)); + + using is_transparent = @\unspec@; +}; +\end{itemdecl} + +\indexlibrarymember{operator()}{logical_or<>}% \begin{itemdecl} -constexpr deleter_type& get_deleter() noexcept; -constexpr const deleter_type& get_deleter() const noexcept; +template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) || std::forward(u)); \end{itemdecl} \begin{itemdescr} \pnum \returns -A reference to the stored deleter. +\tcode{std::forward(t) || std::forward(u)}. \end{itemdescr} -\indexlibrarymember{operator bool}{unique_ptr}% +\rSec3[logical.operations.not]{Class template \tcode{logical_not}} + +\indexlibraryglobal{logical_not}% \begin{itemdecl} -constexpr explicit operator bool() const noexcept; +template struct logical_not { + constexpr bool operator()(const T& x) const; +}; +\end{itemdecl} + +\indexlibrarymember{operator()}{logical_not}% +\begin{itemdecl} +constexpr bool operator()(const T& x) const; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{get() != nullptr}. +\tcode{!x}. \end{itemdescr} -\rSec4[unique.ptr.single.modifiers]{Modifiers} +\indexlibraryglobal{logical_not<>}% +\begin{itemdecl} +template<> struct logical_not { + template constexpr auto operator()(T&& t) const + -> decltype(!std::forward(t)); + + using is_transparent = @\unspec@; +}; +\end{itemdecl} -\indexlibrarymember{release}{unique_ptr}% +\indexlibrarymember{operator()}{logical_not<>}% \begin{itemdecl} -constexpr pointer release() noexcept; +template constexpr auto operator()(T&& t) const + -> decltype(!std::forward(t)); \end{itemdecl} \begin{itemdescr} -\pnum -\ensures -\tcode{get() == nullptr}. - \pnum \returns -The value \tcode{get()} had at the start of -the call to \tcode{release}. +\tcode{!std::forward(t)}. \end{itemdescr} -\indexlibrarymember{reset}{unique_ptr}% -\begin{itemdecl} -constexpr void reset(pointer p = pointer()) noexcept; -\end{itemdecl} -\begin{itemdescr} -\pnum -\effects -Assigns \tcode{p} to the stored pointer, and then, -with the old value of the stored pointer, \tcode{old_p}, -evaluates \tcode{if (old_p) get_deleter()(old_p);} -\begin{note} -The order of these operations is significant -because the call to \tcode{get_deleter()} might destroy \tcode{*this}. -\end{note} +\rSec2[bitwise.operations]{Bitwise operations} -\pnum -\ensures -\tcode{get() == p}. -\begin{note} -The postcondition does not hold if the call to \tcode{get_deleter()} -destroys \tcode{*this} since \tcode{this->get()} is no longer a valid expression. -\end{note} +\rSec3[bitwise.operations.general]{General} \pnum -\remarks -The behavior is undefined -if the evaluation of \tcode{get_deleter()(old_p)} throws an exception. -\end{itemdescr} +The library provides basic function object classes for all of the bitwise +operators in the language\iref{expr.bit.and,expr.or,expr.xor,expr.unary.op}. + +\rSec3[bitwise.operations.and]{Class template \tcode{bit_and}} + +\indexlibraryglobal{bit_and}% +\begin{itemdecl} +template struct bit_and { + constexpr T operator()(const T& x, const T& y) const; +}; +\end{itemdecl} -\indexlibrarymember{swap}{unique_ptr}% +\indexlibrarymember{operator()}{bit_and}% \begin{itemdecl} -constexpr void swap(unique_ptr& u) noexcept; +constexpr T operator()(const T& x, const T& y) const; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{get_deleter()} is swappable\iref{swappable.requirements} and -does not throw an exception under \tcode{swap}. +\returns +\tcode{x \& y}. +\end{itemdescr} -\pnum -\effects -Invokes \tcode{swap} on the stored pointers and on the stored -deleters of \tcode{*this} and \tcode{u}. -\end{itemdescr} - -\rSec3[unique.ptr.runtime]{\tcode{unique_ptr} for array objects with a runtime length} - -\rSec4[unique.ptr.runtime.general]{General} - -\indexlibraryglobal{unique_ptr}% -\begin{codeblock} -namespace std { - template class unique_ptr { - public: - using pointer = @\seebelow@; - using element_type = T; - using deleter_type = D; - - // \ref{unique.ptr.runtime.ctor}, constructors - constexpr unique_ptr() noexcept; - template constexpr explicit unique_ptr(U p) noexcept; - template constexpr unique_ptr(U p, @\seebelow@ d) noexcept; - template constexpr unique_ptr(U p, @\seebelow@ d) noexcept; - constexpr unique_ptr(unique_ptr&& u) noexcept; - template - constexpr unique_ptr(unique_ptr&& u) noexcept; - constexpr unique_ptr(nullptr_t) noexcept; - - // destructor - constexpr ~unique_ptr(); - - // assignment - constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; - template - constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; - constexpr unique_ptr& operator=(nullptr_t) noexcept; - - // \ref{unique.ptr.runtime.observers}, observers - constexpr T& operator[](size_t i) const; - constexpr pointer get() const noexcept; - constexpr deleter_type& get_deleter() noexcept; - constexpr const deleter_type& get_deleter() const noexcept; - constexpr explicit operator bool() const noexcept; - - // \ref{unique.ptr.runtime.modifiers}, modifiers - constexpr pointer release() noexcept; - template constexpr void reset(U p) noexcept; - constexpr void reset(nullptr_t = nullptr) noexcept; - constexpr void swap(unique_ptr& u) noexcept; - - // disable copy from lvalue - unique_ptr(const unique_ptr&) = delete; - unique_ptr& operator=(const unique_ptr&) = delete; - }; -} -\end{codeblock} - -\pnum -A specialization for array types is provided with a slightly altered -interface. - -\begin{itemize} -\item Conversions between different types of -\tcode{unique_ptr} -that would be disallowed for the corresponding pointer-to-array types, -and conversions to or from the non-array forms of -\tcode{unique_ptr}, produce an ill-formed program. - -\item Pointers to types derived from \tcode{T} are -rejected by the constructors, and by \tcode{reset}. - -\item The observers \tcode{operator*} and -\tcode{operator->} are not provided. - -\item The indexing observer \tcode{operator[]} is provided. - -\item The default deleter will call \tcode{delete[]}. -\end{itemize} - -\pnum -Descriptions are provided below only for members that -differ from the primary template. - -\pnum -The template argument \tcode{T} shall be a complete type. +\indexlibraryglobal{bit_and<>}% +\begin{itemdecl} +template<> struct bit_and { + template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) & std::forward(u)); -\rSec4[unique.ptr.runtime.ctor]{Constructors} + using is_transparent = @\unspec@; +}; +\end{itemdecl} -\indexlibraryctor{unique_ptr}% +\indexlibrarymember{operator()}{bit_and<>}% \begin{itemdecl} -template constexpr explicit unique_ptr(U p) noexcept; +template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) & std::forward(u)); \end{itemdecl} \begin{itemdescr} \pnum -This constructor behaves the same as -the constructor in the primary template that -takes a single parameter of type \tcode{pointer}. - -\pnum -\constraints -\begin{itemize} -\item \tcode{U} is the same type as \tcode{pointer}, or -\item \tcode{pointer} is the same type as \tcode{element_type*}, -\tcode{U} is a pointer type \tcode{V*}, and -\tcode{V(*)[]} is convertible to \tcode{element_type(*)[]}. -\end{itemize} +\returns +\tcode{std::forward(t) \& std::forward(u)}. \end{itemdescr} -\indexlibraryctor{unique_ptr}% +\rSec3[bitwise.operations.or]{Class template \tcode{bit_or}} + +\indexlibraryglobal{bit_or}% \begin{itemdecl} -template constexpr unique_ptr(U p, @\seebelow@ d) noexcept; -template constexpr unique_ptr(U p, @\seebelow@ d) noexcept; +template struct bit_or { + constexpr T operator()(const T& x, const T& y) const; +}; \end{itemdecl} -\begin{itemdescr} -\pnum -These constructors behave the same as -the constructors in the primary template that -take a parameter of type \tcode{pointer} and a second parameter. - -\pnum -\constraints -\begin{itemize} -\item \tcode{U} is the same type as \tcode{pointer}, -\item \tcode{U} is \tcode{nullptr_t}, or -\item \tcode{pointer} is the same type as \tcode{element_type*}, - \tcode{U} is a pointer type \tcode{V*}, and - \tcode{V(*)[]} is convertible to \tcode{element_type(*)[]}. -\end{itemize} -\end{itemdescr} - -\indexlibraryctor{unique_ptr}% +\indexlibrarymember{operator()}{bit_or}% \begin{itemdecl} -template constexpr unique_ptr(unique_ptr&& u) noexcept; +constexpr T operator()(const T& x, const T& y) const; \end{itemdecl} \begin{itemdescr} \pnum -This constructor behaves the same as in the primary template. - -\pnum -\constraints -Where \tcode{UP} is \tcode{unique_ptr}: -\begin{itemize} -\item \tcode{U} is an array type, and -\item \tcode{pointer} is the same type as \tcode{element_type*}, and -\item \tcode{UP::pointer} is the same type as \tcode{UP::element_type*}, and -\item \tcode{UP::element_type(*)[]} is convertible to \tcode{element_type(*)[]}, and -\item either \tcode{D} is a reference type and \tcode{E} is the same type as \tcode{D}, - or \tcode{D} is not a reference type and \tcode{E} is implicitly convertible to \tcode{D}. -\end{itemize} - -\begin{note} -This replaces the \constraints specification of the primary template. -\end{note} +\returns +\tcode{x | y}. \end{itemdescr} -\rSec4[unique.ptr.runtime.asgn]{Assignment} - -\indexlibrarymember{operator=}{unique_ptr}% +\indexlibraryglobal{bit_or<>}% \begin{itemdecl} -template constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -This operator behaves the same as in the primary template. - -\pnum -\constraints -Where \tcode{UP} is \tcode{unique_ptr}: -\begin{itemize} -\item \tcode{U} is an array type, and -\item \tcode{pointer} is the same type as \tcode{element_type*}, and -\item \tcode{UP::pointer} is the same type as \tcode{UP::element_type*}, and -\item \tcode{UP::element_type(*)[]} is convertible to \tcode{element_type(*)[]}, and -\item \tcode{is_assignable_v} is \tcode{true}. -\end{itemize} - -\begin{note} -This replaces the \constraints specification of the primary template. -\end{note} -\end{itemdescr} +template<> struct bit_or { + template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) | std::forward(u)); -\rSec4[unique.ptr.runtime.observers]{Observers} + using is_transparent = @\unspec@; +}; +\end{itemdecl} -\indexlibrarymember{operator[]}{unique_ptr}% +\indexlibrarymember{operator()}{bit_or<>}% \begin{itemdecl} -constexpr T& operator[](size_t i) const; +template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) | std::forward(u)); \end{itemdecl} \begin{itemdescr} -\pnum -\expects -$\tcode{i} <$ the -number of elements in the array to which -the stored pointer points. - \pnum \returns -\tcode{get()[i]}. +\tcode{std::forward(t) | std::forward(u)}. \end{itemdescr} -\rSec4[unique.ptr.runtime.modifiers]{Modifiers} +\rSec3[bitwise.operations.xor]{Class template \tcode{bit_xor}} -\indexlibrarymember{reset}{unique_ptr}% +\indexlibraryglobal{bit_xor}% \begin{itemdecl} -constexpr void reset(nullptr_t p = nullptr) noexcept; +template struct bit_xor { + constexpr T operator()(const T& x, const T& y) const; +}; \end{itemdecl} -\begin{itemdescr} -\pnum -\effects -Equivalent to \tcode{reset(pointer())}. -\end{itemdescr} - -\indexlibrarymember{reset}{unique_ptr}% +\indexlibrarymember{operator()}{bit_xor}% \begin{itemdecl} -constexpr template void reset(U p) noexcept; +constexpr T operator()(const T& x, const T& y) const; \end{itemdecl} \begin{itemdescr} \pnum -This function behaves the same as -the \tcode{reset} member of the primary template. - -\pnum -\constraints -\begin{itemize} -\item \tcode{U} is the same type as \tcode{pointer}, or -\item \tcode{pointer} is the same type as \tcode{element_type*}, - \tcode{U} is a pointer type \tcode{V*}, and - \tcode{V(*)[]} is convertible to \tcode{element_type(*)[]}. -\end{itemize} +\returns +\tcode{x \caret{} y}. \end{itemdescr} -\rSec3[unique.ptr.create]{Creation} - -\indexlibraryglobal{make_unique}% +\indexlibraryglobal{bit_xor<>}% \begin{itemdecl} -template constexpr unique_ptr make_unique(Args&&... args); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{T} is not an array type. - -\pnum -\returns -\tcode{unique_ptr(new T(std::forward(args)...))}. +template<> struct bit_xor { + template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) ^ std::forward(u)); -\end{itemdescr} + using is_transparent = @\unspec@; +}; +\end{itemdecl} -\indexlibraryglobal{make_unique}% +\indexlibrarymember{operator()}{bit_xor<>}% \begin{itemdecl} -template constexpr unique_ptr make_unique(size_t n); +template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) ^ std::forward(u)); \end{itemdecl} \begin{itemdescr} -\pnum -\constraints -\tcode{T} is an array of unknown bound. - \pnum \returns -\tcode{unique_ptr(new remove_extent_t[n]())}. - +\tcode{std::forward(t) \caret{} std::forward(u)}. \end{itemdescr} -\indexlibraryglobal{make_unique}% +\rSec3[bitwise.operations.not]{Class template \tcode{bit_not}} + \begin{itemdecl} -template @\unspec@ make_unique(Args&&...) = delete; +template struct bit_not { + constexpr T operator()(const T& x) const; +}; \end{itemdecl} -\begin{itemdescr} -\pnum -\constraints -\tcode{T} is an array of known bound. - -\end{itemdescr} - -\indexlibraryglobal{make_unique}% +\indexlibrarymember{operator()}{bit_not}% \begin{itemdecl} -template constexpr unique_ptr make_unique_for_overwrite(); +constexpr T operator()(const T& x) const; \end{itemdecl} \begin{itemdescr} -\pnum -\constraints -\tcode{T} is not an array type. - \pnum \returns -\tcode{unique_ptr(new T)}. +\tcode{\~{}x}. \end{itemdescr} -\indexlibraryglobal{make_unique}% +\indexlibraryglobal{bit_not<>}% \begin{itemdecl} -template constexpr unique_ptr make_unique_for_overwrite(size_t n); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{T} is an array of unknown bound. +template<> struct bit_not { + template constexpr auto operator()(T&& t) const + -> decltype(~std::forward(t)); -\pnum -\returns -\tcode{unique_ptr(new remove_extent_t[n])}. -\end{itemdescr} + using is_transparent = @\unspec@; +}; +\end{itemdecl} -\indexlibraryglobal{make_unique}% +\indexlibrarymember{operator()}{bit_not<>}% \begin{itemdecl} -template @\unspec@ make_unique_for_overwrite(Args&&...) = delete; +template constexpr auto operator()(T&&) const + -> decltype(~std::forward(t)); \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{T} is an array of known bound. +\returns +\tcode{\~{}std::forward(t)}. \end{itemdescr} -\rSec3[unique.ptr.special]{Specialized algorithms} -\indexlibrary{\idxcode{swap(unique_ptr\&, unique_ptr\&)}}% +\rSec2[func.identity]{Class \tcode{identity}} + +\indexlibraryglobal{identity}% \begin{itemdecl} -template constexpr void swap(unique_ptr& x, unique_ptr& y) noexcept; +struct identity { + template + constexpr T&& operator()(T&& t) const noexcept; + + using is_transparent = @\unspec@; +}; + +template + constexpr T&& operator()(T&& t) const noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\constraints -\tcode{is_swappable_v} is \tcode{true}. - \pnum \effects -Calls \tcode{x.swap(y)}. +Equivalent to: \tcode{return std::forward(t);} \end{itemdescr} -\indexlibrarymember{operator==}{unique_ptr}% -\begin{itemdecl} -template - constexpr bool operator==(const unique_ptr& x, const unique_ptr& y); -\end{itemdecl} -\begin{itemdescr} -\pnum -\returns -\tcode{x.get() == y.get()}. -\end{itemdescr} +\rSec2[func.not.fn]{Function template \tcode{not_fn}} -\indexlibrarymember{operator<}{unique_ptr}% +\indexlibraryglobal{not_fn}% \begin{itemdecl} -template - bool operator<(const unique_ptr& x, const unique_ptr& y); +template constexpr @\unspec@ not_fn(F&& f); \end{itemdecl} \begin{itemdescr} \pnum -Let \tcode{CT} denote -\begin{codeblock} -common_type_t::pointer, - typename unique_ptr::pointer> -\end{codeblock} +In the text that follows: +\begin{itemize} +\item \tcode{g} is a value of the result of a \tcode{not_fn} invocation, +\item \tcode{FD} is the type \tcode{decay_t}, +\item \tcode{fd} is the target object of \tcode{g}\iref{func.def} + of type \tcode{FD}, + direct-non-list-initialized with \tcode{std::forward(f)}, +\item \tcode{call_args} is an argument pack + used in a function call expression\iref{expr.call} of \tcode{g}. +\end{itemize} \pnum \mandates -\begin{itemize} -\item \tcode{unique_ptr::pointer} is implicitly convertible to \tcode{CT} and -\item \tcode{unique_ptr::pointer} is implicitly convertible to \tcode{CT}. -\end{itemize} +\tcode{is_constructible_v \&\& is_move_constructible_v} +is \tcode{true}. \pnum \expects -The specialization -\tcode{less} is a function object type\iref{function.objects} that -induces a strict weak ordering\iref{alg.sorting} on the pointer values. +\tcode{FD} meets the \oldconcept{MoveConstructible} requirements. \pnum \returns -\tcode{less()(x.get(), y.get())}. -\end{itemdescr} - -\indexlibrarymember{operator>}{unique_ptr}% -\begin{itemdecl} -template - bool operator>(const unique_ptr& x, const unique_ptr& y); -\end{itemdecl} +A perfect forwarding call wrapper\iref{term.perfect.forwarding.call.wrapper} \tcode{g} +with call pattern \tcode{!invoke(fd, call_args...)}. -\begin{itemdescr} \pnum -\returns -\tcode{y < x}. +\throws +Any exception thrown by the initialization of \tcode{fd}. \end{itemdescr} -\indexlibrarymember{operator<=}{unique_ptr}% -\begin{itemdecl} -template - bool operator<=(const unique_ptr& x, const unique_ptr& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{!(y < x)}. -\end{itemdescr} +\rSec2[func.bind.partial]{Function templates \tcode{bind_front} and \tcode{bind_back}} -\indexlibrarymember{operator>=}{unique_ptr}% +\indexlibraryglobal{bind_front}% +\indexlibraryglobal{bind_back}% \begin{itemdecl} -template - bool operator>=(const unique_ptr& x, const unique_ptr& y); +template + constexpr @\unspec@ bind_front(F&& f, Args&&... args); +template + constexpr @\unspec@ bind_back(F&& f, Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{!(x < y)}. -\end{itemdescr} - -\indexlibrarymember{operator<=>}{unique_ptr}% -\begin{itemdecl} -template - requires @\libconcept{three_way_comparable_with}@::pointer, - typename unique_ptr::pointer> - compare_three_way_result_t::pointer, - typename unique_ptr::pointer> - operator<=>(const unique_ptr& x, const unique_ptr& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{compare_three_way()(x.get(), y.get())}. -\end{itemdescr} - -\indexlibrarymember{operator==}{unique_ptr}% -\begin{itemdecl} -template - constexpr bool operator==(const unique_ptr& x, nullptr_t) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{!x}. -\end{itemdescr} - -\indexlibrarymember{operator<}{unique_ptr}% -\begin{itemdecl} -template - constexpr bool operator<(const unique_ptr& x, nullptr_t); -template - constexpr bool operator<(nullptr_t, const unique_ptr& x); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -The specialization \tcode{less::pointer>} is -a function object type\iref{function.objects} that induces a strict weak -ordering\iref{alg.sorting} on the pointer values. +Within this subclause: +\begin{itemize} +\item \tcode{g} is a value of +the result of a \tcode{bind_front} or \tcode{bind_back} invocation, +\item \tcode{FD} is the type \tcode{decay_t}, +\item \tcode{fd} is the target object of \tcode{g}\iref{func.def} + of type \tcode{FD}, + direct-non-list-initialized with \tcode{std::forward(f)}, +\item \tcode{BoundArgs} is a pack + that denotes \tcode{decay_t...}, +\item \tcode{bound_args} is + a pack of bound argument entities of \tcode{g}\iref{func.def} + of types \tcode{BoundArgs...}, + direct-non-list-initialized with \tcode{std::forward(args)...}, + respectively, and +\item \tcode{call_args} is an argument pack used in + a function call expression\iref{expr.call} of \tcode{g}. +\end{itemize} \pnum -\returns -The first function template returns -\begin{codeblock} -less::pointer>()(x.get(), nullptr) -\end{codeblock} -The second function template returns +\mandates \begin{codeblock} -less::pointer>()(nullptr, x.get()) +is_constructible_v && +is_move_constructible_v && +(is_constructible_v && ...) && +(is_move_constructible_v && ...) \end{codeblock} -\end{itemdescr} - -\indexlibrarymember{operator>}{unique_ptr}% -\begin{itemdecl} -template - constexpr bool operator>(const unique_ptr& x, nullptr_t); -template - constexpr bool operator>(nullptr_t, const unique_ptr& x); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The first function template returns \tcode{nullptr < x}. -The second function template returns \tcode{x < nullptr}. -\end{itemdescr} - -\indexlibrarymember{operator<=}{unique_ptr}% -\begin{itemdecl} -template - constexpr bool operator<=(const unique_ptr& x, nullptr_t); -template - constexpr bool operator<=(nullptr_t, const unique_ptr& x); -\end{itemdecl} +is \tcode{true}. -\begin{itemdescr} \pnum -\returns -The first function template returns \tcode{!(nullptr < x)}. -The second function template returns \tcode{!(x < nullptr)}. -\end{itemdescr} - -\indexlibrarymember{operator>=}{unique_ptr}% -\begin{itemdecl} -template - constexpr bool operator>=(const unique_ptr& x, nullptr_t); -template - constexpr bool operator>=(nullptr_t, const unique_ptr& x); -\end{itemdecl} +\expects +\tcode{FD} meets the \oldconcept{MoveConstructible} requirements. +For each $\tcode{T}_i$ in \tcode{BoundArgs}, +if $\tcode{T}_i$ is an object type, +$\tcode{T}_i$ meets the \oldconcept{MoveConstructible} requirements. -\begin{itemdescr} \pnum \returns -The first function template returns \tcode{!(x < nullptr)}. -The second function template returns \tcode{!(nullptr < x)}. -\end{itemdescr} - -\indexlibrarymember{operator<=>}{unique_ptr}% -\begin{itemdecl} -template - requires @\libconcept{three_way_comparable}@::pointer> - constexpr compare_three_way_result_t::pointer> - operator<=>(const unique_ptr& x, nullptr_t); -\end{itemdecl} +A perfect forwarding call wrapper\iref{term.perfect.forwarding.call.wrapper} \tcode{g} +with call pattern: +\begin{itemize} +\item +\tcode{invoke(fd, bound_args..., call_args...)} +for a \tcode{bind_front} invocation, or +\item +\tcode{invoke(fd, call_args..., bound_args...)} +for a \tcode{bind_back} invocation. +\end{itemize} -\begin{itemdescr} \pnum -\returns -\begin{codeblock} -compare_three_way()(x.get(), static_cast::pointer>(nullptr)). -\end{codeblock} +\throws +Any exception thrown by +the initialization of the state entities of \tcode{g}\iref{func.def}. \end{itemdescr} -\rSec3[unique.ptr.io]{I/O} - -\indexlibrarymember{operator<<}{unique_ptr}% -\begin{itemdecl} -template - basic_ostream& operator<<(basic_ostream& os, const unique_ptr& p); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{os << p.get()} is a valid expression. +\rSec2[func.bind]{Function object binders}% -\pnum -\effects -Equivalent to: \tcode{os << p.get();} +\rSec3[func.bind.general]{General}% +\indextext{function object!binders|(} \pnum -\returns -\tcode{os}. -\end{itemdescr} - -\rSec2[util.sharedptr]{Shared-ownership pointers} +Subclause \ref{func.bind} describes a uniform mechanism for binding +arguments of callable objects. -\rSec3[util.smartptr.weak.bad]{Class \tcode{bad_weak_ptr}}% -\indextext{smart pointers|(}% +\rSec3[func.bind.isbind]{Class template \tcode{is_bind_expression}} -\indexlibraryglobal{bad_weak_ptr}% +\indexlibraryglobal{is_bind_expression}% \begin{codeblock} namespace std { - class bad_weak_ptr : public exception { - public: - // see \ref{exception} for the specification of the special member functions - const char* what() const noexcept override; - }; + template struct is_bind_expression; // see below } \end{codeblock} \pnum -An exception of type \tcode{bad_weak_ptr} is thrown by the \tcode{shared_ptr} -constructor taking a \tcode{weak_ptr}. - -\indexlibrarymember{what}{bad_weak_ptr}% -\begin{itemdecl} -const char* what() const noexcept override; -\end{itemdecl} +The class template \tcode{is_bind_expression} can be used to detect function objects +generated by \tcode{bind}. The function template \tcode{bind} +uses \tcode{is_bind_expression} to detect subexpressions. -\begin{itemdescr} \pnum -\returns -An \impldef{return value of \tcode{bad_weak_ptr::what}} \ntbs{}. -\end{itemdescr} - -\rSec3[util.smartptr.shared]{Class template \tcode{shared_ptr}} - -\rSec4[util.smartptr.shared.general]{General} +Specializations of the \tcode{is_bind_expression} template shall meet +the \oldconcept{UnaryTypeTrait} requirements\iref{meta.rqmts}. The implementation +provides a definition that has a base characteristic of +\tcode{true_type} if \tcode{T} is a type returned from \tcode{bind}, +otherwise it has a base characteristic of \tcode{false_type}. +A program may specialize this template for a program-defined type \tcode{T} +to have a base characteristic of \tcode{true_type} to indicate that +\tcode{T} should be treated as a subexpression in a \tcode{bind} call. -\pnum -\indexlibraryglobal{shared_ptr}% -The \tcode{shared_ptr} class template stores a pointer, usually obtained -via \keyword{new}. \tcode{shared_ptr} implements semantics of shared ownership; -the last remaining owner of the pointer is responsible for destroying -the object, or otherwise releasing the resources associated with the stored pointer. A -\tcode{shared_ptr} is said to be empty if it does not own a pointer. +\rSec3[func.bind.isplace]{Class template \tcode{is_placeholder}} +\indexlibraryglobal{is_placeholder}% \begin{codeblock} namespace std { - template class shared_ptr { - public: - using element_type = remove_extent_t; - using weak_type = weak_ptr; - - // \ref{util.smartptr.shared.const}, constructors - constexpr shared_ptr() noexcept; - constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { } - template - explicit shared_ptr(Y* p); - template - shared_ptr(Y* p, D d); - template - shared_ptr(Y* p, D d, A a); - template - shared_ptr(nullptr_t p, D d); - template - shared_ptr(nullptr_t p, D d, A a); - template - shared_ptr(const shared_ptr& r, element_type* p) noexcept; - template - shared_ptr(shared_ptr&& r, element_type* p) noexcept; - shared_ptr(const shared_ptr& r) noexcept; - template - shared_ptr(const shared_ptr& r) noexcept; - shared_ptr(shared_ptr&& r) noexcept; - template - shared_ptr(shared_ptr&& r) noexcept; - template - explicit shared_ptr(const weak_ptr& r); - template - shared_ptr(unique_ptr&& r); - - // \ref{util.smartptr.shared.dest}, destructor - ~shared_ptr(); - - // \ref{util.smartptr.shared.assign}, assignment - shared_ptr& operator=(const shared_ptr& r) noexcept; - template - shared_ptr& operator=(const shared_ptr& r) noexcept; - shared_ptr& operator=(shared_ptr&& r) noexcept; - template - shared_ptr& operator=(shared_ptr&& r) noexcept; - template - shared_ptr& operator=(unique_ptr&& r); - - // \ref{util.smartptr.shared.mod}, modifiers - void swap(shared_ptr& r) noexcept; - void reset() noexcept; - template - void reset(Y* p); - template - void reset(Y* p, D d); - template - void reset(Y* p, D d, A a); - - // \ref{util.smartptr.shared.obs}, observers - element_type* get() const noexcept; - T& operator*() const noexcept; - T* operator->() const noexcept; - element_type& operator[](ptrdiff_t i) const; - long use_count() const noexcept; - explicit operator bool() const noexcept; - template - bool owner_before(const shared_ptr& b) const noexcept; - template - bool owner_before(const weak_ptr& b) const noexcept; - }; - - template - shared_ptr(weak_ptr) -> shared_ptr; - template - shared_ptr(unique_ptr) -> shared_ptr; -} -\end{codeblock} - -\pnum -Specializations of \tcode{shared_ptr} shall be \oldconcept{CopyConstructible}, -\oldconcept{CopyAssignable}, and \oldconcept{\-Less\-Than\-Comparable}, allowing their use in standard -containers. Specializations of \tcode{shared_ptr} shall be -contextually convertible to \tcode{bool}, -allowing their use in boolean expressions and declarations in conditions. - -\pnum -The template parameter \tcode{T} of \tcode{shared_ptr} -may be an incomplete type. -\begin{note} -\tcode{T} can be a function type. -\end{note} - -\pnum -\begin{example} -\begin{codeblock} -if (shared_ptr px = dynamic_pointer_cast(py)) { - // do something with \tcode{px} + template struct is_placeholder; // see below } \end{codeblock} -\end{example} - -\pnum -For purposes of determining the presence of a data race, member functions shall -access and modify only the \tcode{shared_ptr} and \tcode{weak_ptr} objects -themselves and not objects they refer to. Changes in \tcode{use_count()} do not -reflect modifications that can introduce data races. \pnum -For the purposes of subclause \ref{smartptr}, -a pointer type \tcode{Y*} is said to be -\defnx{compatible with}{compatible with!\idxcode{shared_ptr}} -a pointer type \tcode{T*} when either -\tcode{Y*} is convertible to \tcode{T*} or -\tcode{Y} is \tcode{U[N]} and \tcode{T} is \cv{}~\tcode{U[]}. - -\rSec4[util.smartptr.shared.const]{Constructors} +The class template \tcode{is_placeholder} can be used to detect the standard placeholders +\tcode{_1}, \tcode{_2}, and so on. The function template \tcode{bind} uses +\tcode{is_placeholder} to detect placeholders. \pnum -In the constructor definitions below, -enables \tcode{shared_from_this} with \tcode{p}, -for a pointer \tcode{p} of type \tcode{Y*}, -means that if \tcode{Y} has an unambiguous and accessible base class -that is a specialization of \tcode{enable_shared_from_this}\iref{util.smartptr.enab}, -then \tcode{remove_cv_t*} shall be implicitly convertible to \tcode{T*} and -the constructor evaluates the statement: -\begin{codeblock} -if (p != nullptr && p->weak_this.expired()) - p->weak_this = shared_ptr>(*this, const_cast*>(p)); -\end{codeblock} -The assignment to the \tcode{weak_this} member is not atomic and -conflicts with any potentially concurrent access to the same object\iref{intro.multithread}. +Specializations of the \tcode{is_placeholder} template shall meet +the \oldconcept{UnaryTypeTrait} requirements\iref{meta.rqmts}. The implementation +provides a definition that has the base characteristic of +\tcode{integral_constant} if \tcode{T} is the type of +\tcode{std::placeholders::_\placeholder{J}}, otherwise it has a +base characteristic of \tcode{integral_constant}. A program +may specialize this template for a program-defined type \tcode{T} to +have a base characteristic of \tcode{integral_constant} +with \tcode{N > 0} to indicate that \tcode{T} should be +treated as a placeholder type. -\indexlibraryctor{shared_ptr}% -\begin{itemdecl} -constexpr shared_ptr() noexcept; -\end{itemdecl} +\rSec3[func.bind.bind]{Function template \tcode{bind}} +\indexlibrary{\idxcode{bind}|(} -\begin{itemdescr} \pnum -\ensures -\tcode{use_count() == 0 \&\& get() == nullptr}. -\end{itemdescr} +In the text that follows: +\begin{itemize} +\item \tcode{g} is a value of the result of a \tcode{bind} invocation, +\item \tcode{FD} is the type \tcode{decay_t}, +\item \tcode{fd} is an lvalue that + is a target object of \tcode{g}\iref{func.def} of type \tcode{FD} + direct-non-list-initialized with \tcode{std::forward(f)}, +\item $\tcode{T}_i$ is the $i^\text{th}$ type in the template parameter pack \tcode{BoundArgs}, +\item $\tcode{TD}_i$ is the type \tcode{decay_t<$\tcode{T}_i$>}, +\item $\tcode{t}_i$ is the $i^\text{th}$ argument in the function parameter pack \tcode{bound_args}, +\item $\tcode{td}_i$ is a bound argument entity + of \tcode{g}\iref{func.def} of type $\tcode{TD}_i$ + direct-non-list-initialized with + \tcode{std::forward<\brk{}$\tcode{T}_i$>($\tcode{t}_i$)}, +\item $\tcode{U}_j$ is the $j^\text{th}$ deduced type of the \tcode{UnBoundArgs\&\&...} parameter + of the argument forwarding call wrapper, and +\item $\tcode{u}_j$ is the $j^\text{th}$ argument associated with $\tcode{U}_j$. +\end{itemize} -\indexlibraryctor{shared_ptr}% +\indexlibraryglobal{bind}% \begin{itemdecl} -template explicit shared_ptr(Y* p); +template + constexpr @\unspec@ bind(F&& f, BoundArgs&&... bound_args); +template + constexpr @\unspec@ bind(F&& f, BoundArgs&&... bound_args); \end{itemdecl} \begin{itemdescr} -\pnum -\constraints -When \tcode{T} is an array type, -the expression \tcode{delete[] p} is well-formed and either -\tcode{T} is \tcode{U[N]} and \tcode{Y(*)[N]} is convertible to \tcode{T*}, or -\tcode{T} is \tcode{U[]} and \tcode{Y(*)[]} is convertible to \tcode{T*}. -When \tcode{T} is not an array type, -the expression \tcode{delete p} is well-formed and -\tcode{Y*} is convertible to \tcode{T*}. - \pnum \mandates -\tcode{Y} is a complete type. +\tcode{is_constructible_v} is \tcode{true}. For each $\tcode{T}_i$ +in \tcode{BoundArgs}, \tcode{is_cons\-tructible_v<$\tcode{TD}_i$, $\tcode{T}_i$>} is \tcode{true}. \pnum \expects -The expression -\tcode{delete[] p}, when \tcode{T} is an array type, or -\tcode{delete p}, when \tcode{T} is not an array type, -has well-defined behavior, and -does not throw exceptions. +\tcode{FD} and each $\tcode{TD}_i$ meet +the \oldconcept{MoveConstructible} and \oldconcept{Destructible} requirements. +\tcode{\placeholdernc{INVOKE}(fd, $\tcode{w}_1$, $\tcode{w}_2$, $\dotsc$, +$\tcode{w}_N$)}\iref{func.require} is a valid expression for some +values $\tcode{w}_1$, $\tcode{w}_2$, $\dotsc{}$, $\tcode{w}_N$, where +$N$ has the value \tcode{sizeof...(bound_args)}. \pnum -\effects -When \tcode{T} is not an array type, -constructs a \tcode{shared_ptr} object -that owns the pointer \tcode{p}. -Otherwise, constructs a \tcode{shared_ptr} -that owns \tcode{p} and a deleter of an -unspecified type that calls \tcode{delete[] p}. -When \tcode{T} is not an array type, -enables \tcode{shared_from_this} with \tcode{p}. -If an exception is thrown, \tcode{delete p} is called -when \tcode{T} is not an array type, \tcode{delete[] p} otherwise. +\returns +An argument forwarding call wrapper \tcode{g}\iref{func.require}. +A program that attempts to invoke a volatile-qualified \tcode{g} +is ill-formed. +When \tcode{g} is not volatile-qualified, invocation of +\tcode{g($\tcode{u}_1$, $\tcode{u}_2$, $\dotsc$, $\tcode{u}_M$)} +is expression-equivalent\iref{defns.expression.equivalent} to +\begin{codeblock} +@\placeholdernc{INVOKE}@(static_cast<@$\tcode{V}_\tcode{fd}$@>(@$\tcode{v}_\tcode{fd}$@), + static_cast<@$\tcode{V}_1$@>(@$\tcode{v}_1$@), static_cast<@$\tcode{V}_2$@>(@$\tcode{v}_2$@), @$\dotsc$@, static_cast<@$\tcode{V}_N$@>(@$\tcode{v}_N$@)) +\end{codeblock} +for the first overload, and +\begin{codeblock} +@\placeholdernc{INVOKE}@(static_cast<@$\tcode{V}_\tcode{fd}$@>(@$\tcode{v}_\tcode{fd}$@), + static_cast<@$\tcode{V}_1$@>(@$\tcode{v}_1$@), static_cast<@$\tcode{V}_2$@>(@$\tcode{v}_2$@), @$\dotsc$@, static_cast<@$\tcode{V}_N$@>(@$\tcode{v}_N$@)) +\end{codeblock} +for the second overload, +where the values and types of the target argument $\tcode{v}_\tcode{fd}$ and +of the bound arguments +$\tcode{v}_1$, $\tcode{v}_2$, $\dotsc$, $\tcode{v}_N$ are determined as specified below. \pnum -\ensures -\tcode{use_count() == 1 \&\& get() == p}. +\throws +Any exception thrown by the initialization of +the state entities of \tcode{g}. \pnum -\throws -\tcode{bad_alloc}, or an \impldef{exception type when \tcode{shared_ptr} -constructor fails} exception when a resource other than memory cannot be obtained. +\begin{note} +If all of \tcode{FD} and $\tcode{TD}_i$ meet +the requirements of \oldconcept{CopyConstructible}, then +the return type meets the requirements of \oldconcept{CopyConstructible}. +\end{note} \end{itemdescr} -\indexlibraryctor{shared_ptr}% -\begin{itemdecl} -template shared_ptr(Y* p, D d); -template shared_ptr(Y* p, D d, A a); -template shared_ptr(nullptr_t p, D d); -template shared_ptr(nullptr_t p, D d, A a); -\end{itemdecl} - -\begin{itemdescr} \pnum -\constraints -\tcode{is_move_constructible_v} is \tcode{true}, and -\tcode{d(p)} is a well-formed expression. -For the first two overloads: - +\indextext{bound arguments}% +The values of the \term{bound arguments} $\tcode{v}_1$, $\tcode{v}_2$, $\dotsc$, $\tcode{v}_N$ and their +corresponding types $\tcode{V}_1$, $\tcode{V}_2$, $\dotsc$, $\tcode{V}_N$ depend on the +types $\tcode{TD}_i$ derived from +the call to \tcode{bind} and the +cv-qualifiers \cv{} of the call wrapper \tcode{g} as follows: \begin{itemize} -\item -If \tcode{T} is an array type, then either -\tcode{T} is \tcode{U[N]} and \tcode{Y(*)[N]} is convertible to \tcode{T*}, or -\tcode{T} is \tcode{U[]} and \tcode{Y(*)[]} is convertible to \tcode{T*}. - -\item -If \tcode{T} is not an array type, then \tcode{Y*} is convertible to \tcode{T*}. -\end{itemize} +\item if $\tcode{TD}_i$ is \tcode{reference_wrapper}, the +argument is \tcode{$\tcode{td}_i$.get()} and its type $\tcode{V}_i$ is \tcode{T\&}; -\pnum -\expects -Construction of \tcode{d} and a deleter of type \tcode{D} -initialized with \tcode{std::move(d)} do not throw exceptions. -The expression \tcode{d(p)} -has well-defined behavior and does not throw exceptions. -\tcode{A} meets the \oldconcept{Allocator} requirements (\tref{cpp17.allocator}). +\item if the value of \tcode{is_bind_expression_v<$\tcode{TD}_i$>} +is \tcode{true}, the argument is +\begin{codeblock} +static_cast<@\cv{} $\tcode{TD}_i$@&>(@$\tcode{td}_i$@)(std::forward<@$\tcode{U}_j$@>(@$\tcode{u}_j$@)...) +\end{codeblock} +and its type $\tcode{V}_i$ is +\tcode{invoke_result_t<\cv{} $\tcode{TD}_i$\&, $\tcode{U}_j$...>\&\&}; -\pnum -\effects -Constructs a \tcode{shared_ptr} object that owns the -object \tcode{p} and the deleter \tcode{d}. -When \tcode{T} is not an array type, -the first and second constructors enable \tcode{shared_from_this} with \tcode{p}. -The second and fourth constructors shall use a copy of \tcode{a} to -allocate memory for internal use. -If an exception is thrown, \tcode{d(p)} is called. +\item if the value \tcode{j} of \tcode{is_placeholder_v<$\tcode{TD}_i$>} +is not zero, the argument is \tcode{std::forward<$\tcode{U}_j$>($\tcode{u}_j$)} +and its type $\tcode{V}_i$ +is \tcode{$\tcode{U}_j$\&\&}; -\pnum -\ensures -\tcode{use_count() == 1 \&\& get() == p}. +\item otherwise, the value is $\tcode{td}_i$ and its type $\tcode{V}_i$ +is \tcode{\cv{} $\tcode{TD}_i$\&}. +\end{itemize} \pnum -\throws -\tcode{bad_alloc}, or an \impldef{exception type when \tcode{shared_ptr} -constructor fails} exception -when a resource other than memory cannot be obtained. -\end{itemdescr} +The value of the target argument $\tcode{v}_\tcode{fd}$ is \tcode{fd} and +its corresponding type $\tcode{V}_\tcode{fd}$ is \tcode{\cv{} FD\&}. +\indexlibrary{\idxcode{bind}|)}% -\indexlibraryctor{shared_ptr}% -\begin{itemdecl} -template shared_ptr(const shared_ptr& r, element_type* p) noexcept; -template shared_ptr(shared_ptr&& r, element_type* p) noexcept; -\end{itemdecl} +\rSec3[func.bind.place]{Placeholders} -\begin{itemdescr} -\pnum -\effects -Constructs a \tcode{shared_ptr} instance that -stores \tcode{p} and shares ownership with -the initial value of \tcode{r}. +\indexlibraryglobal{placeholders}% +\indexlibrary{1@\tcode{_1}}% +\begin{codeblock} +namespace std::placeholders { + // M is the \impldef{number of placeholders for bind expressions} number of placeholders + @\seebelow@ _1; + @\seebelow@ _2; + . + . + . + @\seebelow@ _M; +} +\end{codeblock} \pnum -\ensures -\tcode{get() == p}. -For the second overload, -\tcode{r} is empty and \tcode{r.get() == nullptr}. +All placeholder types meet the \oldconcept{DefaultConstructible} and +\oldconcept{CopyConstructible} requirements, and +their default constructors and copy/move +constructors are constexpr functions that +do not throw exceptions. It is \impldef{assignability of placeholder +objects} whether +placeholder types meet the \oldconcept{CopyAssignable} requirements, +but if so, their copy assignment operators are +constexpr functions that do not throw exceptions. \pnum -\begin{note} -Use of this constructor leads to a dangling pointer -unless \tcode{p} remains valid -at least until the ownership group of \tcode{r} is destroyed. -\end{note} +Placeholders should be defined as: +\begin{codeblock} +inline constexpr @\unspec@ _1{}; +\end{codeblock} +If they are not, they are declared as: +\begin{codeblock} +extern @\unspec@ _1; +\end{codeblock}% +\indextext{function object!binders|)} -\pnum -\begin{note} -This constructor allows creation of an empty -\tcode{shared_ptr} instance with a non-null stored pointer. -\end{note} -\end{itemdescr} +\rSec2[func.memfn]{Function template \tcode{mem_fn}}% +\indextext{function object!\idxcode{mem_fn}|(} -\indexlibraryctor{shared_ptr}% +\indexlibraryglobal{mem_fn}% \begin{itemdecl} -shared_ptr(const shared_ptr& r) noexcept; -template shared_ptr(const shared_ptr& r) noexcept; +template constexpr @\unspec@ mem_fn(R T::* pm) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -For the second constructor, \tcode{Y*} is compatible with \tcode{T*}. - -\pnum -\effects -If \tcode{r} is empty, constructs -an empty \tcode{shared_ptr} object; otherwise, constructs -a \tcode{shared_ptr} object that shares ownership with \tcode{r}. - -\pnum -\ensures -\tcode{get() == r.get() \&\& use_count() == r.use_count()}. +\returns +A simple call wrapper\iref{term.simple.call.wrapper} \tcode{fn} +with call pattern \tcode{invoke(pmd, call_args...)}, where +\tcode{pmd} is the target object of \tcode{fn} of type \tcode{R T::*} +direct-non-list-initialized with \tcode{pm}, and +\tcode{call_args} is an argument pack +used in a function call expression\iref{expr.call} of \tcode{fn}. \end{itemdescr} +\indextext{function object!\idxcode{mem_fn}|)} -\indexlibraryctor{shared_ptr}% -\begin{itemdecl} -shared_ptr(shared_ptr&& r) noexcept; -template shared_ptr(shared_ptr&& r) noexcept; -\end{itemdecl} +\rSec2[func.wrap]{Polymorphic function wrappers}% -\begin{itemdescr} -\pnum -\constraints -For the second constructor, \tcode{Y*} is compatible with \tcode{T*}. +\rSec3[func.wrap.general]{General}% +\indextext{function object!wrapper|(} \pnum -\effects -Move constructs a \tcode{shared_ptr} instance from \tcode{r}. +Subclause \ref{func.wrap} describes polymorphic wrapper classes that +encapsulate arbitrary callable objects. + +\rSec3[func.wrap.badcall]{Class \tcode{bad_function_call}}% +\indexlibraryglobal{bad_function_call}% \pnum -\ensures -\tcode{*this} contains the old value of -\tcode{r}. \tcode{r} is empty, and \tcode{r.get() == nullptr}. -\end{itemdescr} +An exception of type \tcode{bad_function_call} is thrown by +\tcode{function::operator()}\iref{func.wrap.func.inv} +when the function wrapper object has no target. + +\begin{codeblock} +namespace std { + class bad_function_call : public exception { + public: + // see \ref{exception} for the specification of the special member functions + const char* what() const noexcept override; + }; +} +\end{codeblock} -\indexlibraryctor{shared_ptr}% -\indexlibraryglobal{weak_ptr}% +\indexlibrarymember{what}{bad_function_call}% \begin{itemdecl} -template explicit shared_ptr(const weak_ptr& r); +const char* what() const noexcept override; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{Y*} is compatible with \tcode{T*}. +\returns +An +\impldef{return value of \tcode{bad_function_call::what}} \ntbs{}. +\end{itemdescr} -\pnum -\effects -Constructs a \tcode{shared_ptr} object that shares ownership with -\tcode{r} and stores a copy of the pointer stored in \tcode{r}. -If an exception is thrown, the constructor has no effect. +\rSec3[func.wrap.func]{Class template \tcode{function}} -\pnum -\ensures -\tcode{use_count() == r.use_count()}. +\rSec4[func.wrap.func.general]{General} +\indexlibraryglobal{function}% -\pnum -\throws -\tcode{bad_weak_ptr} when \tcode{r.expired()}. -\end{itemdescr} +\indexlibrarymember{result_type}{function}% +\begin{codeblock} +namespace std { + template class function; // \notdef -\indexlibraryctor{shared_ptr}% -\indexlibraryglobal{unique_ptr}% -\begin{itemdecl} -template shared_ptr(unique_ptr&& r); -\end{itemdecl} + template + class function { + public: + using result_type = R; -\begin{itemdescr} -\pnum -\constraints -\tcode{Y*} is compatible with \tcode{T*} and -\tcode{unique_ptr::pointer} is convertible to \tcode{element_type*}. + // \ref{func.wrap.func.con}, construct/copy/destroy + function() noexcept; + function(nullptr_t) noexcept; + function(const function&); + function(function&&) noexcept; + template function(F&&); -\pnum -\effects -If \tcode{r.get() == nullptr}, equivalent to \tcode{shared_ptr()}. -Otherwise, if \tcode{D} is not a reference type, -equivalent to \tcode{shared_ptr(r.release(), std::move(r.get_deleter()))}. -Otherwise, equivalent to \tcode{shared_ptr(r.release(), ref(r.get_deleter()))}. -If an exception is thrown, the constructor has no effect. -\end{itemdescr} + function& operator=(const function&); + function& operator=(function&&); + function& operator=(nullptr_t) noexcept; + template function& operator=(F&&); + template function& operator=(reference_wrapper) noexcept; -\rSec4[util.smartptr.shared.dest]{Destructor} + ~function(); -\indexlibrarydtor{shared_ptr}% -\begin{itemdecl} -~shared_ptr(); -\end{itemdecl} + // \ref{func.wrap.func.mod}, function modifiers + void swap(function&) noexcept; -\begin{itemdescr} -\pnum -\effects -\begin{itemize} -\item If \tcode{*this} is empty or shares ownership with another -\tcode{shared_ptr} instance (\tcode{use_count() > 1}), there are no side effects. + // \ref{func.wrap.func.cap}, function capacity + explicit operator bool() const noexcept; -\item -Otherwise, if \tcode{*this} owns an object -\tcode{p} and a deleter \tcode{d}, \tcode{d(p)} is called. + // \ref{func.wrap.func.inv}, function invocation + R operator()(ArgTypes...) const; -\item Otherwise, \tcode{*this} owns a pointer \tcode{p}, -and \tcode{delete p} is called. -\end{itemize} -\end{itemdescr} + // \ref{func.wrap.func.targ}, function target access + const type_info& target_type() const noexcept; + template T* target() noexcept; + template const T* target() const noexcept; + }; -\pnum -\begin{note} -Since the destruction of \tcode{*this} -decreases the number of instances that share ownership with \tcode{*this} -by one, -after \tcode{*this} has been destroyed -all \tcode{shared_ptr} instances that shared ownership with -\tcode{*this} will report a \tcode{use_count()} that is one less -than its previous value. -\end{note} + template + function(R(*)(ArgTypes...)) -> function; -\rSec4[util.smartptr.shared.assign]{Assignment} + template function(F) -> function<@\seebelow@>; +} +\end{codeblock} -\indexlibrarymember{operator=}{shared_ptr}% -\begin{itemdecl} -shared_ptr& operator=(const shared_ptr& r) noexcept; -template shared_ptr& operator=(const shared_ptr& r) noexcept; -\end{itemdecl} +\pnum +The \tcode{function} class template provides polymorphic wrappers that +generalize the notion of a function pointer. Wrappers can store, copy, +and call arbitrary callable objects\iref{func.def}, given a call +signature\iref{func.def}. -\begin{itemdescr} \pnum -\effects -Equivalent to \tcode{shared_ptr(r).swap(*this)}. +\indextext{callable type}% +A callable type\iref{func.def} \tcode{F} +is \defn{Lvalue-Callable} for argument +types \tcode{ArgTypes} +and return type \tcode{R} +if the expression +\tcode{\placeholdernc{INVOKE}(declval(), declval()...)}, +considered as an unevaluated operand\iref{term.unevaluated.operand}, is +well-formed\iref{func.require}. \pnum -\returns -\tcode{*this}. +The \tcode{function} class template is a call +wrapper\iref{func.def} whose call signature\iref{func.def} +is \tcode{R(ArgTypes...)}. \pnum \begin{note} -The use count updates caused by the temporary object -construction and destruction are not observable side -effects, so the implementation can meet the effects (and the -implied guarantees) via different means, without creating a -temporary. In particular, in the example: -\begin{codeblock} -shared_ptr p(new int); -shared_ptr q(p); -p = p; -q = p; -\end{codeblock} -both assignments can be no-ops. +The types deduced by the deduction guides for \tcode{function} +might change in future revisions of \Cpp{}. \end{note} -\end{itemdescr} -\indexlibrarymember{operator=}{shared_ptr}% +\rSec4[func.wrap.func.con]{Constructors and destructor} + +\indexlibraryctor{function}% \begin{itemdecl} -shared_ptr& operator=(shared_ptr&& r) noexcept; -template shared_ptr& operator=(shared_ptr&& r) noexcept; +function() noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to \tcode{shared_ptr(std::move(r)).swap(*this)}. - -\pnum -\returns -\tcode{*this}. +\ensures +\tcode{!*this}. \end{itemdescr} -\indexlibrarymember{operator=}{shared_ptr}% +\indexlibraryctor{function}% \begin{itemdecl} -template shared_ptr& operator=(unique_ptr&& r); +function(nullptr_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to \tcode{shared_ptr(std::move(r)).swap(*this)}. - -\pnum -\returns -\tcode{*this}. +\ensures +\tcode{!*this}. \end{itemdescr} -\rSec4[util.smartptr.shared.mod]{Modifiers} - -\indexlibrarymember{swap}{shared_ptr}% +\indexlibraryctor{function}% \begin{itemdecl} -void swap(shared_ptr& r) noexcept; +function(const function& f); \end{itemdecl} \begin{itemdescr} +\pnum +\ensures +\tcode{!*this} if \tcode{!f}; otherwise, +the target object of \tcode{*this} is a copy of \tcode{f.target()}. \pnum -\effects -Exchanges the contents of \tcode{*this} and \tcode{r}. +\throws +Nothing if \tcode{f}'s target is +a specialization of \tcode{reference_wrapper} or +a function pointer. Otherwise, may throw \tcode{bad_alloc} +or any exception thrown by the copy constructor of the stored callable object. + +\pnum +\recommended +Implementations should avoid the use of +dynamically allocated memory for small callable objects, for example, where +\tcode{f}'s target is an object holding only a pointer or reference +to an object and a member function pointer. \end{itemdescr} -\indexlibrarymember{reset}{shared_ptr}% +\indexlibraryctor{function}% \begin{itemdecl} -void reset() noexcept; +function(function&& f) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to \tcode{shared_ptr().swap(*this)}. +\ensures +If \tcode{!f}, \tcode{*this} has no target; +otherwise, the target of \tcode{*this} is equivalent to +the target of \tcode{f} before the construction, and +\tcode{f} is in a valid state with an unspecified value. + +\pnum +\recommended +Implementations should avoid the use of +dynamically allocated memory for small callable objects, for example, +where \tcode{f}'s target is an object holding only a pointer or reference +to an object and a member function pointer. \end{itemdescr} -\indexlibrarymember{reset}{shared_ptr}% +\indexlibraryctor{function}% \begin{itemdecl} -template void reset(Y* p); +template function(F&& f); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to \tcode{shared_ptr(p).swap(*this)}. +Let \tcode{FD} be \tcode{decay_t}. + +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_same_v, function>} is \tcode{false}, and +\item +\tcode{FD} is Lvalue-Callable\iref{func.wrap.func} for argument types +\tcode{ArgTypes...} and return type \tcode{R}. +\end{itemize} + +\pnum +\mandates +\begin{itemize} +\item +\tcode{is_copy_constructible_v} is \tcode{true}, and +\item +\tcode{is_constructible_v} is \tcode{true}. +\end{itemize} + +\pnum +\expects +\tcode{FD} meets the \oldconcept{CopyConstructible} requirements. + +\pnum +\ensures +\tcode{!*this} is \tcode{true} if any of the following hold: +\begin{itemize} +\item \tcode{f} is a null function pointer value. +\item \tcode{f} is a null member pointer value. +\item \tcode{remove_cvref_t} is +a specialization of the \tcode{function} class template, and +\tcode{!f} is \tcode{true}. +\end{itemize} + +\pnum +Otherwise, \tcode{*this} has a target object of type \tcode{FD} +direct-non-list-initialized with \tcode{std::forward(f)}. + +\pnum +\throws +Nothing if \tcode{FD} is +a specialization of \tcode{reference_wrapper} or +a function pointer type. +Otherwise, may throw \tcode{bad_alloc} or +any exception thrown by the initialization of the target object. + +\pnum +\recommended +Implementations should avoid the use of +dynamically allocated memory for small callable objects, for example, +where \tcode{f} refers to an object holding only a pointer or +reference to an object and a member function pointer. \end{itemdescr} -\indexlibrarymember{reset}{shared_ptr}% + \begin{itemdecl} -template void reset(Y* p, D d); +template function(F) -> function<@\seebelow@>; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to \tcode{shared_ptr(p, d).swap(*this)}. +\constraints +\tcode{\&F::operator()} is well-formed when treated as an unevaluated operand and +\tcode{decltype(\brk{}\&F::operator())} is of the form +\tcode{R(G::*)(A...)}~\cv{}~\tcode{\opt{\&}~\opt{noexcept}} +for a class type \tcode{G}. + +\pnum +\remarks +The deduced type is \tcode{function}. + +\pnum +\begin{example} +\begin{codeblock} +void f() { + int i{5}; + function g = [&](double) { return i; }; // deduces \tcode{function} +} +\end{codeblock} +\end{example} \end{itemdescr} -\indexlibrarymember{reset}{shared_ptr}% +\indexlibrarymember{operator=}{function}% \begin{itemdecl} -template void reset(Y* p, D d, A a); +function& operator=(const function& f); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to \tcode{shared_ptr(p, d, a).swap(*this)}. +As if by \tcode{function(f).swap(*this);} + +\pnum +\returns +\tcode{*this}. \end{itemdescr} -\rSec4[util.smartptr.shared.obs]{Observers} -\indexlibrarymember{get}{shared_ptr}% +\indexlibrarymember{operator=}{function}% \begin{itemdecl} -element_type* get() const noexcept; +function& operator=(function&& f); \end{itemdecl} \begin{itemdescr} +\pnum +\effects +Replaces the target of \tcode{*this} +with the target of \tcode{f}. + \pnum \returns -The stored pointer. +\tcode{*this}. \end{itemdescr} -\indexlibrarymember{operator*}{shared_ptr}% +\indexlibrarymember{operator=}{function}% \begin{itemdecl} -T& operator*() const noexcept; +function& operator=(nullptr_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{get() != 0}. +\effects +If \tcode{*this != nullptr}, destroys the target of \keyword{this}. \pnum -\returns -\tcode{*get()}. +\ensures +\tcode{!(*this)}. \pnum -\remarks -When \tcode{T} is an array type or \cv{}~\keyword{void}, -it is unspecified whether this -member function is declared. If it is declared, it is unspecified what its -return type is, except that the declaration (although not necessarily the -definition) of the function shall be well-formed. +\returns +\tcode{*this}. \end{itemdescr} -\indexlibrarymember{operator->}{shared_ptr}% +\indexlibrarymember{operator=}{function}% \begin{itemdecl} -T* operator->() const noexcept; +template function& operator=(F&& f); \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{get() != 0}. +\constraints +\tcode{decay_t} is Lvalue-Callable\iref{func.wrap.func} +for argument types \tcode{ArgTypes...} and return type \tcode{R}. \pnum -\returns -\tcode{get()}. +\effects +As if by: \tcode{function(std::forward(f)).swap(*this);} \pnum -\remarks -When \tcode{T} is an array type, -it is unspecified whether this member function is declared. -If it is declared, it is unspecified what its return type is, -except that the declaration (although not necessarily the definition) -of the function shall be well-formed. +\returns +\tcode{*this}. \end{itemdescr} -\indexlibrarymember{operator[]}{shared_ptr}% +\indexlibrarymember{operator=}{function}% \begin{itemdecl} -element_type& operator[](ptrdiff_t i) const; +template function& operator=(reference_wrapper f) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{get() != 0 \&\& i >= 0}. -If \tcode{T} is \tcode{U[N]}, \tcode{i < N}. +\effects +As if by: \tcode{function(f).swap(*this);} \pnum \returns -\tcode{get()[i]}. +\tcode{*this}. +\end{itemdescr} -\pnum -\throws -Nothing. +\indexlibrarydtor{function}% +\begin{itemdecl} +~function(); +\end{itemdecl} +\begin{itemdescr} \pnum -\remarks -When \tcode{T} is not an array type, -it is unspecified whether this member function is declared. -If it is declared, it is unspecified what its return type is, -except that the declaration (although not necessarily the definition) -of the function shall be well-formed. +\effects +If \tcode{*this != nullptr}, destroys the target of \keyword{this}. \end{itemdescr} -\indexlibrarymember{use_count}{shared_ptr}% +\rSec4[func.wrap.func.mod]{Modifiers} + +\indexlibrarymember{swap}{function}% \begin{itemdecl} -long use_count() const noexcept; +void swap(function& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\sync -None. +\effects +Interchanges the target objects of \tcode{*this} and \tcode{other}. +\end{itemdescr} + +\rSec4[func.wrap.func.cap]{Capacity} + +\indexlibrarymember{operator bool}{function}% +\begin{itemdecl} +explicit operator bool() const noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum \returns -The number of \tcode{shared_ptr} objects, \tcode{*this} included, -that share ownership with \tcode{*this}, or \tcode{0} when \tcode{*this} is -empty. +\tcode{true} if \tcode{*this} has a target, otherwise \tcode{false}. +\end{itemdescr} -\pnum -\begin{note} -\tcode{get() == nullptr} -does not imply a specific return value of \tcode{use_count()}. -\end{note} +\rSec4[func.wrap.func.inv]{Invocation} + +\indexlibrary{\idxcode{function}!invocation}% +\indexlibrarymember{operator()}{function}% +\begin{itemdecl} +R operator()(ArgTypes... args) const; +\end{itemdecl} +\begin{itemdescr} \pnum -\begin{note} -\tcode{weak_ptr::lock()} -can affect the return value of \tcode{use_count()}. -\end{note} +\returns +\tcode{\placeholdernc{INVOKE}(f, std::forward(args)...)}\iref{func.require}, +where \tcode{f} is the target object\iref{func.def} of \tcode{*this}. \pnum -\begin{note} -When multiple threads -might affect the return value of \tcode{use_count()}, -the result is approximate. -In particular, \tcode{use_count() == 1} does not imply that accesses through -a previously destroyed \tcode{shared_ptr} have in any sense completed. -\end{note} +\throws +\tcode{bad_function_call} if \tcode{!*this}; otherwise, any +exception thrown by the target object. \end{itemdescr} -\indexlibrarymember{operator bool}{shared_ptr}% +\rSec4[func.wrap.func.targ]{Target access} + +\indexlibrarymember{target_type}{function}% \begin{itemdecl} -explicit operator bool() const noexcept; +const type_info& target_type() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{get() != 0}. +If \tcode{*this} has a target of type \tcode{T}, + \tcode{typeid(T)}; otherwise, \tcode{typeid(void)}. \end{itemdescr} -\indexlibrarymember{owner_before}{shared_ptr}% +\indexlibrarymember{target}{function}% \begin{itemdecl} -template bool owner_before(const shared_ptr& b) const noexcept; -template bool owner_before(const weak_ptr& b) const noexcept; +template T* target() noexcept; +template const T* target() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -An unspecified value such that -\begin{itemize} -\item \tcode{x.owner_before(y)} defines a strict weak ordering as defined in~\ref{alg.sorting}; - -\item under the equivalence relation defined by \tcode{owner_before}, -\tcode{!a.owner_before(b) \&\& !b.owner_before(a)}, two \tcode{shared_ptr} or -\tcode{weak_ptr} instances are equivalent if and only if they share ownership or -are both empty. -\end{itemize} - +If \tcode{target_type() == typeid(T)} +a pointer to the stored function target; otherwise a null pointer. \end{itemdescr} -\rSec4[util.smartptr.shared.create]{Creation} - -\pnum -The common requirements that apply to all -\tcode{make_shared}, -\tcode{allocate_shared}, -\tcode{make_shared_for_overwrite}, and -\tcode{allocate_shared_for_overwrite} overloads, -unless specified otherwise, are described below. +\rSec4[func.wrap.func.nullptr]{Null pointer comparison operator functions} -\indexlibraryglobal{make_shared}% -\indexlibraryglobal{allocate_shared}% +\indexlibrarymember{operator==}{function}% \begin{itemdecl} -template - shared_ptr make_shared(@\placeholdernc{args}@); -template - shared_ptr allocate_shared(const A& a, @\placeholdernc{args}@); -template - shared_ptr make_shared_for_overwrite(@\placeholdernc{args}@); -template - shared_ptr allocate_shared_for_overwrite(const A& a, @\placeholdernc{args}@); +template + bool operator==(const function& f, nullptr_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{A} meets the \oldconcept{Allocator} requirements (\tref{cpp17.allocator}). +\returns +\tcode{!f}. +\end{itemdescr} -\pnum -\effects -Allocates memory for an object of type \tcode{T} -(or \tcode{U[N]} when \tcode{T} is \tcode{U[]}, -where \tcode{N} is determined from \placeholder{args} as specified by the concrete overload). -The object is initialized from \placeholder{args} as specified by the concrete overload. -The \tcode{allocate_shared} and \tcode{allocate_shared_for_overwrite} templates -use a copy of \tcode{a} -(rebound for an unspecified \tcode{value_type}) to allocate memory. -If an exception is thrown, the functions have no effect. +\rSec4[func.wrap.func.alg]{Specialized algorithms} -\pnum -\ensures -\tcode{r.get() != 0 \&\& r.use_count() == 1}, -where \tcode{r} is the return value. +\indexlibrarymember{swap}{function}% +\begin{itemdecl} +template + void swap(function& f1, function& f2) noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -\returns -A \tcode{shared_ptr} instance that stores and owns the address of -the newly constructed object. +\effects +As if by: \tcode{f1.swap(f2);} +\end{itemdescr}% -\pnum -\throws -\tcode{bad_alloc}, or -an exception thrown from \tcode{allocate} or from the initialization of the object. +\rSec3[func.wrap.move]{Move only wrapper} + +\rSec4[func.wrap.move.general]{General} \pnum -\remarks +The header provides partial specializations of \tcode{move_only_function} +for each combination of the possible replacements +of the placeholders \cv{}, \placeholder{ref}, and \placeholder{noex} where \begin{itemize} \item - Implementations should perform no more than one memory allocation. - \begin{note} - This provides efficiency equivalent to an intrusive smart pointer. - \end{note} -\item - When an object of an array type \tcode{U} is specified to have - an initial value of \tcode{u} (of the same type), - this shall be interpreted to mean that - each array element of the object has as its initial value - the corresponding element from \tcode{u}. -\item - When an object of an array type is specified to have - a default initial value, - this shall be interpreted to mean that each array element of the object - has a default initial value. -\item - When a (sub)object of a non-array type \tcode{U} is specified to have - an initial value of \tcode{v}, or \tcode{U(l...)}, - where \tcode{l...} is a list of constructor arguments, - \tcode{make_shared} shall initialize this (sub)object - via the expression \tcode{::new(pv) U(v)} or \tcode{::new(pv) U(l...)} respectively, - where \tcode{pv} has type \tcode{void*} and points to storage - suitable to hold an object of type \tcode{U}. -\item - When a (sub)object of a non-array type \tcode{U} is specified to have - an initial value of \tcode{v}, or \tcode{U(l...)}, - where \tcode{l...} is a list of constructor arguments, - \tcode{allocate_shared} shall initialize this (sub)object - via the expression - \begin{itemize} - \item \tcode{allocator_traits::construct(a2, pv, v)} or - \item \tcode{allocator_traits::construct(a2, pv, l...)} - \end{itemize} - respectively, - where \tcode{pv} points to storage - suitable to hold an object of type \tcode{U} and - \tcode{a2} of type \tcode{A2} is a rebound copy of - the allocator \tcode{a} passed to \tcode{allocate_shared} - such that its \tcode{value_type} is \tcode{remove_cv_t}. -\item - When a (sub)object of non-array type \tcode{U} is specified to have - a default initial value, - \tcode{make_shared} shall initialize this (sub)object - via the expression \tcode{::new(pv) U()}, - where \tcode{pv} has type \tcode{void*} and points to storage - suitable to hold an object of type \tcode{U}. -\item - When a (sub)object of non-array type \tcode{U} is specified to have - a default initial value, - \tcode{allocate_shared} shall initialize this (sub)object - via the expression \tcode{allocator_traits::construct(a2, pv)}, - where \tcode{pv} points to storage - suitable to hold an object of type \tcode{U} and - \tcode{a2} of type \tcode{A2} is a rebound copy of - the allocator \tcode{a} passed to \tcode{allocate_shared} - such that its \tcode{value_type} is \tcode{remove_cv_t}. -\item - When a (sub)object of non-array type \tcode{U} is initialized by - \tcode{make_shared_for_overwrite} or\linebreak % avoid Overfull - \tcode{allocate_shared_for_overwrite}, - it is initialized via the expression \tcode{::new(pv) U}, - where \tcode{pv} has type \tcode{void*} and - points to storage suitable to hold an object of type \tcode{U}. +\cv{} is either const or empty, \item - Array elements are initialized in ascending order of their addresses. +\placeholder{ref} is either \tcode{\&}, \tcode{\&\&}, or empty, and \item - When the lifetime of the object managed by the return value ends, or - when the initialization of an array element throws an exception, - the initialized elements are destroyed in the reverse order - of their original construction. +\placeholder{noex} is either \tcode{true} or \tcode{false}. +\end{itemize} + +\pnum +For each of the possible combinations of the placeholders mentioned above, +there is a placeholder \placeholder{inv-quals} defined as follows: +\begin{itemize} \item - When a (sub)object of non-array type \tcode{U} - that was initialized by \tcode{make_shared} is to be destroyed, - it is destroyed via the expression \tcode{pv->\~{}U()} where - \tcode{pv} points to that object of type \tcode{U}. +If \placeholder{ref} is empty, let \placeholder{inv-quals} be \tcode{\cv{}\&}, \item - When a (sub)object of non-array type \tcode{U} - that was initialized by \tcode{allocate_shared} is to be destroyed, - it is destroyed via the expression - \tcode{allocator_traits::destroy(a2, pv)} where - \tcode{pv} points to that object of type \tcode{remove_cv_t} and - \tcode{a2} of type \tcode{A2} is a rebound copy of - the allocator \tcode{a} passed to \tcode{allocate_shared} - such that its \tcode{value_type} is \tcode{remove_cv_t}. +otherwise, let \placeholder{inv-quals} be \cv{} \placeholder{ref}. \end{itemize} -\begin{note} -These functions will typically allocate more memory than \tcode{sizeof(T)} to -allow for internal bookkeeping structures such as reference counts. -\end{note} -\end{itemdescr} -\indexlibraryglobal{make_shared}% -\indexlibraryglobal{allocate_shared}% -\begin{itemdecl} -template - shared_ptr make_shared(Args&&... args); // \tcode{T} is not array -template - shared_ptr allocate_shared(const A& a, Args&&... args); // \tcode{T} is not array -\end{itemdecl} +\rSec4[func.wrap.move.class]{Class template \tcode{move_only_function}} -\begin{itemdescr} -\pnum -\constraints -\tcode{T} is not an array type. +\indexlibraryglobal{move_only_function}% +\begin{codeblock} +namespace std { + template class move_only_function; // \notdef -\pnum -\returns -A \tcode{shared_ptr} to an object of type \tcode{T} -with an initial value \tcode{T(forward(args)...)}. + template + class move_only_function { + public: + using result_type = R; -\pnum -\remarks -The \tcode{shared_ptr} constructors called by these functions -enable \tcode{shared_from_this} -with the address of the newly constructed object of type \tcode{T}. + // \ref{func.wrap.move.ctor}, constructors, assignment, and destructor + move_only_function() noexcept; + move_only_function(nullptr_t) noexcept; + move_only_function(move_only_function&&) noexcept; + template move_only_function(F&&); + template + explicit move_only_function(in_place_type_t, Args&&...); + template + explicit move_only_function(in_place_type_t, initializer_list, Args&&...); -\pnum -\begin{example} -\begin{codeblock} -shared_ptr p = make_shared(); // \tcode{shared_ptr} to \tcode{int()} -shared_ptr> q = make_shared>(16, 1); - // \tcode{shared_ptr} to vector of \tcode{16} elements with value \tcode{1} -\end{codeblock} -\end{example} -\end{itemdescr} + move_only_function& operator=(move_only_function&&); + move_only_function& operator=(nullptr_t) noexcept; + template move_only_function& operator=(F&&); -\indexlibraryglobal{make_shared}% -\indexlibraryglobal{allocate_shared}% -\begin{itemdecl} -template shared_ptr - make_shared(size_t N); // \tcode{T} is \tcode{U[]} -template - shared_ptr allocate_shared(const A& a, size_t N); // \tcode{T} is \tcode{U[]} -\end{itemdecl} + ~move_only_function(); -\begin{itemdescr} -\pnum -\constraints -\tcode{T} is of the form \tcode{U[]}. + // \ref{func.wrap.move.inv}, invocation + explicit operator bool() const noexcept; + R operator()(ArgTypes...) @\cv{}@ @\placeholder{ref}@ noexcept(@\placeholder{noex}@); -\pnum -\returns -A \tcode{shared_ptr} to an object of type \tcode{U[N]} -with a default initial value, -where \tcode{U} is \tcode{remove_extent_t}. + // \ref{func.wrap.move.util}, utility + void swap(move_only_function&) noexcept; + friend void swap(move_only_function&, move_only_function&) noexcept; + friend bool operator==(const move_only_function&, nullptr_t) noexcept; -\pnum -\begin{example} -\begin{codeblock} -shared_ptr p = make_shared(1024); - // \tcode{shared_ptr} to a value-initialized \tcode{double[1024]} -shared_ptr q = make_shared(6); - // \tcode{shared_ptr} to a value-initialized \tcode{double[6][2][2]} + private: + template + static constexpr bool @\exposid{is-callable-from}@ = @\seebelow@; // \expos + }; +} \end{codeblock} -\end{example} -\end{itemdescr} - -\indexlibraryglobal{make_shared}% -\indexlibraryglobal{allocate_shared}% -\begin{itemdecl} -template - shared_ptr make_shared(); // \tcode{T} is \tcode{U[N]} -template - shared_ptr allocate_shared(const A& a); // \tcode{T} is \tcode{U[N]} -\end{itemdecl} -\begin{itemdescr} \pnum -\constraints -\tcode{T} is of the form \tcode{U[N]}. +The \tcode{move_only_function} class template provides polymorphic wrappers +that generalize the notion of a callable object\iref{func.def}. +These wrappers can store, move, and call arbitrary callable objects, +given a call signature. \pnum -\returns -A \tcode{shared_ptr} to an object of type \tcode{T} -with a default initial value. +\recommended +Implementations should avoid the use of dynamically allocated memory +for a small contained value. +\begin{note} +Such small-object optimization can only be applied to a type \tcode{T} +for which \tcode{is_nothrow_move_constructible_v} is \tcode{true}. +\end{note} -\pnum -\begin{example} -\begin{codeblock} -shared_ptr p = make_shared(); - // \tcode{shared_ptr} to a value-initialized \tcode{double[1024]} -shared_ptr q = make_shared(); - // \tcode{shared_ptr} to a value-initialized \tcode{double[6][2][2]} -\end{codeblock} -\end{example} -\end{itemdescr} +\rSec4[func.wrap.move.ctor]{Constructors, assignment, and destructor} -\indexlibraryglobal{make_shared}% -\indexlibraryglobal{allocate_shared}% +\indexlibrarymember{\exposid{is-callable-from}}{move_only_function}% \begin{itemdecl} -template - shared_ptr make_shared(size_t N, - const remove_extent_t& u); // \tcode{T} is \tcode{U[]} -template - shared_ptr allocate_shared(const A& a, size_t N, - const remove_extent_t& u); // \tcode{T} is \tcode{U[]} +template + static constexpr bool @\exposid{is-callable-from}@ = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{T} is of the form \tcode{U[]}. - -\pnum -\returns -A \tcode{shared_ptr} to an object of type \tcode{U[N]}, -where \tcode{U} is \tcode{remove_extent_t} and -each array element has an initial value of \tcode{u}. - -\pnum -\begin{example} +If \placeholder{noex} is \tcode{true}, +\tcode{\exposid{is-callable-from}} is equal to: \begin{codeblock} -shared_ptr p = make_shared(1024, 1.0); - // \tcode{shared_ptr} to a \tcode{double[1024]}, where each element is \tcode{1.0} -shared_ptr q = make_shared(6, {1.0, 0.0}); - // \tcode{shared_ptr} to a \tcode{double[6][2]}, where each \tcode{double[2]} element is \tcode{\{1.0, 0.0\}} -shared_ptr[]> r = make_shared[]>(4, {1, 2}); - // \tcode{shared_ptr} to a \tcode{vector[4]}, where each vector has contents \tcode{\{1, 2\}} +is_nothrow_invocable_r_v && +is_nothrow_invocable_r_v +\end{codeblock} +Otherwise, \tcode{\exposid{is-callable-from}} is equal to: +\begin{codeblock} +is_invocable_r_v && +is_invocable_r_v \end{codeblock} -\end{example} \end{itemdescr} -\indexlibraryglobal{make_shared}% -\indexlibraryglobal{allocate_shared}% +\indexlibraryctor{move_only_function}% \begin{itemdecl} -template - shared_ptr make_shared(const remove_extent_t& u); // \tcode{T} is \tcode{U[N]} -template - shared_ptr allocate_shared(const A& a, - const remove_extent_t& u); // \tcode{T} is \tcode{U[N]} +move_only_function() noexcept; +move_only_function(nullptr_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{T} is of the form \tcode{U[N]}. +\ensures +\tcode{*this} has no target object. +\end{itemdescr} -\pnum -\returns -A \tcode{shared_ptr} to an object of type \tcode{T}, -where each array element of type \tcode{remove_extent_t} -has an initial value of \tcode{u}. +\indexlibraryctor{move_only_function}% +\begin{itemdecl} +move_only_function(move_only_function&& f) noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -\begin{example} -\begin{codeblock} -shared_ptr p = make_shared(1.0); - // \tcode{shared_ptr} to a \tcode{double[1024]}, where each element is \tcode{1.0} -shared_ptr q = make_shared({1.0, 0.0}); - // \tcode{shared_ptr} to a \tcode{double[6][2]}, where each double[2] element is \tcode{\{1.0, 0.0\}} -shared_ptr[4]> r = make_shared[4]>({1, 2}); - // \tcode{shared_ptr} to a \tcode{vector[4]}, where each vector has contents \tcode{\{1, 2\}} -\end{codeblock} -\end{example} +\ensures +The target object of \tcode{*this} is +the target object \tcode{f} had before construction, and +\tcode{f} is in a valid state with an unspecified value. \end{itemdescr} -\indexlibraryglobal{make_shared}% -\indexlibraryglobal{allocate_shared}% +\indexlibraryctor{move_only_function}% \begin{itemdecl} -template - shared_ptr make_shared_for_overwrite(); -template - shared_ptr allocate_shared_for_overwrite(const A& a); +template move_only_function(F&& f); \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{T} is not an array of unknown bound. +Let \tcode{VT} be \tcode{decay_t}. \pnum -\returns -A \tcode{shared_ptr} to an object of type \tcode{T}. +\constraints +\begin{itemize} +\item +\tcode{remove_cvref_t} is not the same type as \tcode{move_only_function}, and +\item +\tcode{remove_cvref_t} is not a specialization of \tcode{in_place_type_t}, and +\item +\tcode{\exposid{is-callable-from}} is \tcode{true}. +\end{itemize} \pnum -\begin{example} -\begin{codeblock} -struct X { double data[1024]; }; -shared_ptr p = make_shared_for_overwrite(); - // \tcode{shared_ptr} to a default-initialized \tcode{X}, where each element in \tcode{X::data} has an indeterminate value - -shared_ptr q = make_shared_for_overwrite(); - // \tcode{shared_ptr} to a default-initialized \tcode{double[1024]}, where each element has an indeterminate value -\end{codeblock} -\end{example} -\end{itemdescr} - -\indexlibraryglobal{make_shared}% -\indexlibraryglobal{allocate_shared}% -\begin{itemdecl} -template - shared_ptr make_shared_for_overwrite(size_t N); -template - shared_ptr allocate_shared_for_overwrite(const A& a, size_t N); -\end{itemdecl} +\mandates +\tcode{is_constructible_v} is \tcode{true}. -\begin{itemdescr} \pnum -\constraints -\tcode{T} is an array of unknown bound. +\expects +\tcode{VT} meets the \oldconcept{Destructible} requirements, and +if \tcode{is_move_constructible_v} is \tcode{true}, +\tcode{VT} meets the \oldconcept{MoveConstructible} requirements. \pnum -\returns -A \tcode{shared_ptr} to an object of type \tcode{U[N]}, -where \tcode{U} is \tcode{remove_extent_t}. +\ensures +\tcode{*this} has no target object if any of the following hold: +\begin{itemize} +\item +\tcode{f} is a null function pointer value, or +\item +\tcode{f} is a null member pointer value, or +\item +\tcode{remove_cvref_t} is a specialization of +the \tcode{move_only_function} class template, +and \tcode{f} has no target object. +\end{itemize} +Otherwise, \tcode{*this} has a target object of type \tcode{VT} +direct-non-list-initialized with \tcode{std::forward(f)}. \pnum -\begin{example} -\begin{codeblock} -shared_ptr p = make_shared_for_overwrite(1024); - // \tcode{shared_ptr} to a default-initialized \tcode{double[1024]}, where each element has an indeterminate value -\end{codeblock} -\end{example} +\throws +Any exception thrown by the initialization of the target object. +May throw \tcode{bad_alloc} unless \tcode{VT} is +a function pointer or a specialization of \tcode{reference_wrapper}. \end{itemdescr} -\rSec4[util.smartptr.shared.cmp]{Comparison} - -\indexlibrarymember{operator==}{shared_ptr}% +\indexlibraryctor{move_only_function}% \begin{itemdecl} -template - bool operator==(const shared_ptr& a, const shared_ptr& b) noexcept; +template + explicit move_only_function(in_place_type_t, Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{a.get() == b.get()}. -\end{itemdescr} +Let \tcode{VT} be \tcode{decay_t}. -\indexlibrarymember{operator==}{shared_ptr}% -\begin{itemdecl} -template - bool operator==(const shared_ptr& a, nullptr_t) noexcept; -\end{itemdecl} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_constructible_v} is \tcode{true}, and +\item +\tcode{\exposid{is-callable-from}} is \tcode{true}. +\end{itemize} -\begin{itemdescr} \pnum -\returns -\tcode{!a}. -\end{itemdescr} +\mandates +\tcode{VT} is the same type as \tcode{T}. -\indexlibrarymember{operator<=>}{shared_ptr}% -\begin{itemdecl} -template - strong_ordering operator<=>(const shared_ptr& a, const shared_ptr& b) noexcept; -\end{itemdecl} +\pnum +\expects +\tcode{VT} meets the \oldconcept{Destructible} requirements, and +if \tcode{is_move_constructible_v} is \tcode{true}, +\tcode{VT} meets the \oldconcept{MoveConstructible} requirements. -\begin{itemdescr} \pnum -\returns -\tcode{compare_three_way()(a.get(), b.get())}. +\ensures +\tcode{*this} has a target object of type \tcode{VT} +direct-non-list-initialized with \tcode{std::forward\brk{}(args)...}. \pnum -\begin{note} -Defining a comparison operator function allows \tcode{shared_ptr} objects -to be used as keys in associative containers. -\end{note} +\throws +Any exception thrown by the initialization of the target object. +May throw \tcode{bad_alloc} unless \tcode{VT} is +a function pointer or a specialization of \tcode{reference_wrapper}. \end{itemdescr} -\indexlibrarymember{operator<=>}{shared_ptr}% +\indexlibraryctor{move_only_function}% \begin{itemdecl} -template - strong_ordering operator<=>(const shared_ptr& a, nullptr_t) noexcept; +template + explicit move_only_function(in_place_type_t, initializer_list ilist, Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\begin{codeblock} -compare_three_way()(a.get(), static_cast::element_type*>(nullptr). -\end{codeblock} -\end{itemdescr} - -\rSec4[util.smartptr.shared.spec]{Specialized algorithms} - -\indexlibrarymember{swap}{shared_ptr}% -\begin{itemdecl} -template - void swap(shared_ptr& a, shared_ptr& b) noexcept; -\end{itemdecl} +Let \tcode{VT} be \tcode{decay_t}. -\begin{itemdescr} \pnum -\effects -Equivalent to \tcode{a.swap(b)}. -\end{itemdescr} - -\rSec4[util.smartptr.shared.cast]{Casts} - -\indexlibrarymember{static_pointer_cast}{shared_ptr}% -\begin{itemdecl} -template - shared_ptr static_pointer_cast(const shared_ptr& r) noexcept; -template - shared_ptr static_pointer_cast(shared_ptr&& r) noexcept; -\end{itemdecl} +\constraints +\begin{itemize} +\item +\tcode{is_constructible_v\&, ArgTypes...>} is +\tcode{true}, and +\item +\tcode{\exposid{is-callable-from}} is \tcode{true}. +\end{itemize} -\begin{itemdescr} \pnum \mandates -The expression \tcode{static_cast((U*)nullptr)} is well-formed. +\tcode{VT} is the same type as \tcode{T}. \pnum -\returns -\begin{codeblock} -shared_ptr(@\placeholder{R}@, static_cast::element_type*>(r.get())) -\end{codeblock} -where \tcode{\placeholder{R}} is \tcode{r} for the first overload, and -\tcode{std::move(r)} for the second. +\expects +\tcode{VT} meets the \oldconcept{Destructible} requirements, and +if \tcode{is_move_constructible_v} is \tcode{true}, +\tcode{VT} meets the \oldconcept{MoveConstructible} requirements. \pnum -\begin{note} -The seemingly equivalent expression -\tcode{shared_ptr(static_cast(r.get()))} -will eventually result in undefined behavior, attempting to delete the -same object twice. -\end{note} +\ensures +\tcode{*this} has a target object of type \tcode{VT} +direct-non-list-initialized with +\tcode{ilist, std::for\-ward(args)...}. + +\pnum +\throws +Any exception thrown by the initialization of the target object. +May throw \tcode{bad_alloc} unless \tcode{VT} is +a function pointer or a specialization of \tcode{reference_wrapper}. \end{itemdescr} -\indexlibrarymember{dynamic_pointer_cast}{shared_ptr}% +\indexlibrarymember{operator=}{move_only_function}% \begin{itemdecl} -template - shared_ptr dynamic_pointer_cast(const shared_ptr& r) noexcept; -template - shared_ptr dynamic_pointer_cast(shared_ptr&& r) noexcept; +move_only_function& operator=(move_only_function&& f); \end{itemdecl} \begin{itemdescr} \pnum -\mandates -The expression \tcode{dynamic_cast((U*)nullptr)} is well-formed. -The expression \tcode{dynamic_cast::element_type*>(r.get())} is well-formed. - -\pnum -\expects -The expression \tcode{dynamic_cast::element_type*>(r.get())} has well-defined behavior. +\effects +Equivalent to: \tcode{move_only_function(std::move(f)).swap(*this);} \pnum \returns -\begin{itemize} -\item When \tcode{dynamic_cast::element_type*>(r.get())} - returns a non-null value \tcode{p}, - \tcode{shared_ptr(\placeholder{R}, p)}, - where \tcode{\placeholder{R}} is \tcode{r} for the first overload, and - \tcode{std::move(r)} for the second. -\item Otherwise, \tcode{shared_ptr()}. -\end{itemize} - -\pnum -\begin{note} -The seemingly equivalent expression -\tcode{shared_ptr(dynamic_cast(r.get()))} will eventually result in -undefined behavior, attempting to delete the same object twice. -\end{note} +\tcode{*this}. \end{itemdescr} -\indexlibrarymember{const_pointer_cast}{shared_ptr}% +\indexlibrarymember{operator=}{move_only_function}% \begin{itemdecl} -template - shared_ptr const_pointer_cast(const shared_ptr& r) noexcept; -template - shared_ptr const_pointer_cast(shared_ptr&& r) noexcept; +move_only_function& operator=(nullptr_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\mandates -The expression \tcode{const_cast((U*)nullptr)} is well-formed. +\effects +Destroys the target object of \tcode{*this}, if any. \pnum \returns -\begin{codeblock} -shared_ptr(@\placeholder{R}@, const_cast::element_type*>(r.get())) -\end{codeblock} -where \tcode{\placeholder{R}} is \tcode{r} for the first overload, and -\tcode{std::move(r)} for the second. - -\pnum -\begin{note} -The seemingly equivalent expression -\tcode{shared_ptr(const_cast(r.get()))} will eventually result in -undefined behavior, attempting to delete the same object twice. -\end{note} +\tcode{*this}. \end{itemdescr} -\indexlibrarymember{reinterpret_pointer_cast}{shared_ptr}% +\indexlibrarymember{operator=}{move_only_function}% \begin{itemdecl} -template - shared_ptr reinterpret_pointer_cast(const shared_ptr& r) noexcept; -template - shared_ptr reinterpret_pointer_cast(shared_ptr&& r) noexcept; +template move_only_function& operator=(F&& f); \end{itemdecl} \begin{itemdescr} \pnum -\mandates -The expression \tcode{reinterpret_cast((U*)nullptr)} is well-formed. +\effects +Equivalent to: \tcode{move_only_function(std::forward(f)).swap(*this);} \pnum \returns -\begin{codeblock} -shared_ptr(@\placeholder{R}@, reinterpret_cast::element_type*>(r.get())) -\end{codeblock} -where \tcode{\placeholder{R}} is \tcode{r} for the first overload, and -\tcode{std::move(r)} for the second. - -\pnum -\begin{note} -The seemingly equivalent expression -\tcode{shared_ptr(reinterpret_cast(r.get()))} will eventually result in -undefined behavior, attempting to delete the same object twice. -\end{note} +\tcode{*this}. \end{itemdescr} -\rSec4[util.smartptr.getdeleter]{\tcode{get_deleter}} - -\indexlibrarymember{get_deleter}{shared_ptr}% +\indexlibrarydtor{move_only_function}% \begin{itemdecl} -template - D* get_deleter(const shared_ptr& p) noexcept; +~move_only_function(); \end{itemdecl} \begin{itemdescr} \pnum -\returns -If \tcode{p} owns a deleter \tcode{d} of type cv-unqualified -\tcode{D}, returns \tcode{addressof(d)}; otherwise returns \keyword{nullptr}. -The returned -pointer remains valid as long as there exists a \tcode{shared_ptr} instance -that owns \tcode{d}. -\begin{note} -It is unspecified whether the pointer -remains valid longer than that. This can happen if the implementation doesn't destroy -the deleter until all \tcode{weak_ptr} instances that share ownership with -\tcode{p} have been destroyed. -\end{note} +\effects +Destroys the target object of \tcode{*this}, if any. \end{itemdescr} -\rSec4[util.smartptr.shared.io]{I/O} +\rSec4[func.wrap.move.inv]{Invocation} -\indexlibrarymember{operator<<}{shared_ptr}% +\indexlibrarymember{operator bool}{move_only_function}% \begin{itemdecl} -template - basic_ostream& operator<<(basic_ostream& os, const shared_ptr& p); +explicit operator bool() const noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\effects -As if by: \tcode{os <{}< p.get();} - \pnum \returns -\tcode{os}. +\tcode{true} if \tcode{*this} has a target object, otherwise \tcode{false}. \end{itemdescr} -\rSec3[util.smartptr.weak]{Class template \tcode{weak_ptr}} - -\rSec4[util.smartptr.weak.general]{General} - -\pnum -\indexlibraryglobal{weak_ptr}% -The \tcode{weak_ptr} class template stores a weak reference to an object -that is already managed by a \tcode{shared_ptr}. To access the object, a -\tcode{weak_ptr} can be converted to a \tcode{shared_ptr} using the member -function \tcode{lock}. - -\begin{codeblock} -namespace std { - template class weak_ptr { - public: - using element_type = remove_extent_t; - - // \ref{util.smartptr.weak.const}, constructors - constexpr weak_ptr() noexcept; - template - weak_ptr(const shared_ptr& r) noexcept; - weak_ptr(const weak_ptr& r) noexcept; - template - weak_ptr(const weak_ptr& r) noexcept; - weak_ptr(weak_ptr&& r) noexcept; - template - weak_ptr(weak_ptr&& r) noexcept; - - // \ref{util.smartptr.weak.dest}, destructor - ~weak_ptr(); - - // \ref{util.smartptr.weak.assign}, assignment - weak_ptr& operator=(const weak_ptr& r) noexcept; - template - weak_ptr& operator=(const weak_ptr& r) noexcept; - template - weak_ptr& operator=(const shared_ptr& r) noexcept; - weak_ptr& operator=(weak_ptr&& r) noexcept; - template - weak_ptr& operator=(weak_ptr&& r) noexcept; - - // \ref{util.smartptr.weak.mod}, modifiers - void swap(weak_ptr& r) noexcept; - void reset() noexcept; - - // \ref{util.smartptr.weak.obs}, observers - long use_count() const noexcept; - bool expired() const noexcept; - shared_ptr lock() const noexcept; - template - bool owner_before(const shared_ptr& b) const noexcept; - template - bool owner_before(const weak_ptr& b) const noexcept; - }; - - template - weak_ptr(shared_ptr) -> weak_ptr; -} -\end{codeblock} - -\pnum -Specializations of \tcode{weak_ptr} shall be \oldconcept{CopyConstructible} and -\oldconcept{CopyAssignable}, allowing their use in standard -containers. The template parameter \tcode{T} of \tcode{weak_ptr} may be an -incomplete type. - -\rSec4[util.smartptr.weak.const]{Constructors} - -\indexlibraryctor{weak_ptr}% +\indexlibrarymember{operator()}{move_only_function}% \begin{itemdecl} -constexpr weak_ptr() noexcept; +R operator()(ArgTypes... args) @\cv{}@ @\placeholder{ref}@ noexcept(@\placeholder{noex}@); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Constructs an empty \tcode{weak_ptr} object that stores a null pointer value. +\expects +\tcode{*this} has a target object. \pnum -\ensures -\tcode{use_count() == 0}. +\effects +Equivalent to: +\begin{codeblock} +return @\placeholder{INVOKE}@(static_cast(f), std::forward(args)...); +\end{codeblock} +where \tcode{f} is an lvalue designating the target object of \tcode{*this} and +\tcode{F} is the type of \tcode{f}. \end{itemdescr} -\indexlibraryctor{weak_ptr}% +\rSec4[func.wrap.move.util]{Utility} + +\indexlibrarymember{swap}{move_only_function}% \begin{itemdecl} -weak_ptr(const weak_ptr& r) noexcept; -template weak_ptr(const weak_ptr& r) noexcept; -template weak_ptr(const shared_ptr& r) noexcept; +void swap(move_only_function& other) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\constraints -For the second and third constructors, \tcode{Y*} is compatible with \tcode{T*}. - \pnum \effects -If \tcode{r} is empty, constructs -an empty \tcode{weak_ptr} object that stores a null pointer value; -otherwise, constructs -a \tcode{weak_ptr} object that shares ownership -with \tcode{r} and stores a copy of the pointer stored in \tcode{r}. - -\pnum -\ensures -\tcode{use_count() == r.use_count()}. +Exchanges the target objects of \tcode{*this} and \tcode{other}. \end{itemdescr} -\indexlibraryctor{weak_ptr}% +\indexlibrarymember{swap}{move_only_function}% \begin{itemdecl} -weak_ptr(weak_ptr&& r) noexcept; -template weak_ptr(weak_ptr&& r) noexcept; +friend void swap(move_only_function& f1, move_only_function& f2) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\constraints -For the second constructor, \tcode{Y*} is compatible with \tcode{T*}. - \pnum \effects -Move constructs a \tcode{weak_ptr} instance from \tcode{r}. - -\pnum -\ensures -\tcode{*this} contains the old value of \tcode{r}. -\tcode{r} is empty, stores a null pointer value, and \tcode{r.use_count() == 0}. +Equivalent to \tcode{f1.swap(f2)}. \end{itemdescr} -\rSec4[util.smartptr.weak.dest]{Destructor} - -\indexlibrarydtor{weak_ptr}% +\indexlibrarymember{operator==}{move_only_function}% \begin{itemdecl} -~weak_ptr(); +friend bool operator==(const move_only_function& f, nullptr_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Destroys this \tcode{weak_ptr} object but has no -effect on the object its stored pointer points to. +\returns +\tcode{true} if \tcode{f} has no target object, otherwise \tcode{false}. \end{itemdescr} +\indextext{function object!wrapper|)} -\rSec4[util.smartptr.weak.assign]{Assignment} +\rSec2[func.search]{Searchers} -\indexlibrarymember{operator=}{weak_ptr}% -\begin{itemdecl} -weak_ptr& operator=(const weak_ptr& r) noexcept; -template weak_ptr& operator=(const weak_ptr& r) noexcept; -template weak_ptr& operator=(const shared_ptr& r) noexcept; -\end{itemdecl} +\rSec3[func.search.general]{General} -\begin{itemdescr} \pnum -\effects -Equivalent to \tcode{weak_ptr(r).swap(*this)}. +Subclause \ref{func.search} provides function object types\iref{function.objects} for +operations that search for a sequence \range{pat\textunderscore\nobreak first}{pat_last} in another +sequence \range{first}{last} that is provided to the object's function call +operator. The first sequence (the pattern to be searched for) is provided to +the object's constructor, and the second (the sequence to be searched) is +provided to the function call operator. \pnum -\returns -\tcode{*this}. +Each specialization of a class template specified in \ref{func.search} +shall meet the \oldconcept{CopyConst\-ruct\-ible} and \oldconcept{CopyAssignable} requirements. +Template parameters named +\begin{itemize} +\item \tcode{ForwardIterator}, +\item \tcode{ForwardIterator1}, +\item \tcode{ForwardIterator2}, +\item \tcode{RandomAccessIterator}, +\item \tcode{RandomAccessIterator1}, +\item \tcode{RandomAccessIterator2}, and +\item \tcode{BinaryPredicate} +\end{itemize} +of templates specified in +\ref{func.search} shall meet the same requirements and semantics as +specified in \ref{algorithms.general}. +Template parameters named \tcode{Hash} shall meet the \oldconcept{Hash} +requirements (\tref{cpp17.hash}). \pnum -\remarks -The implementation may meet the effects (and the -implied guarantees) via different means, without creating a temporary object. -\end{itemdescr} +The Boyer-Moore searcher implements the Boyer-Moore search algorithm. +The Boyer-Moore-Horspool searcher implements the Boyer-Moore-Horspool search algorithm. +In general, the Boyer-Moore searcher will use more memory and give better runtime performance than Boyer-Moore-Horspool. -\indexlibrarymember{operator=}{weak_ptr}% -\begin{itemdecl} -weak_ptr& operator=(weak_ptr&& r) noexcept; -template weak_ptr& operator=(weak_ptr&& r) noexcept; -\end{itemdecl} +\rSec3[func.search.default]{Class template \tcode{default_searcher}} -\begin{itemdescr} -\pnum -\effects -Equivalent to \tcode{weak_ptr(std::move(r)).swap(*this)}. +\indexlibraryglobal{default_searcher}% +\begin{codeblock} +namespace std { + template> + class default_searcher { + public: + constexpr default_searcher(ForwardIterator1 pat_first, ForwardIterator1 pat_last, + BinaryPredicate pred = BinaryPredicate()); -\pnum -\returns -\tcode{*this}. -\end{itemdescr} + template + constexpr pair + operator()(ForwardIterator2 first, ForwardIterator2 last) const; + + private: + ForwardIterator1 pat_first_; // \expos + ForwardIterator1 pat_last_; // \expos + BinaryPredicate pred_; // \expos + }; +} +\end{codeblock} -\rSec4[util.smartptr.weak.mod]{Modifiers} -\indexlibrarymember{swap}{weak_ptr}% +\indexlibraryctor{default_searcher}% \begin{itemdecl} -void swap(weak_ptr& r) noexcept; +constexpr default_searcher(ForwardIterator pat_first, ForwardIterator pat_last, + BinaryPredicate pred = BinaryPredicate()); \end{itemdecl} \begin{itemdescr} \pnum \effects -Exchanges the contents of \tcode{*this} and \tcode{r}. +% FIXME: The mbox prevents TeX from adding a bizarre hyphen after pat_last_. +Constructs a \tcode{default_searcher} object, initializing \tcode{pat_first_} +with \tcode{pat_first}, \mbox{\tcode{pat_last_}} with \tcode{pat_last}, and +\tcode{pred_} with \tcode{pred}. + +\pnum +\throws +Any exception thrown by the copy constructor of \tcode{BinaryPredicate} or +\tcode{ForwardIterator1}. \end{itemdescr} -\indexlibrarymember{reset}{weak_ptr}% +\indexlibrarymember{operator()}{default_searcher}% \begin{itemdecl} -void reset() noexcept; +template + constexpr pair + operator()(ForwardIterator2 first, ForwardIterator2 last) const; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to \tcode{weak_ptr().swap(*this)}. +Returns a pair of iterators \tcode{i} and \tcode{j} such that +\begin{itemize} +\item \tcode{i == search(first, last, pat_first_, pat_last_, pred_)}, and +\item if \tcode{i == last}, then \tcode{j == last}, +otherwise \tcode{j == next(i, distance(pat_first_, pat_last_))}. +\end{itemize} \end{itemdescr} -\rSec4[util.smartptr.weak.obs]{Observers} -\indexlibrarymember{use_count}{weak_ptr}% -\begin{itemdecl} -long use_count() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{0} if \tcode{*this} is empty; -otherwise, the number of \tcode{shared_ptr} instances -that share ownership with \tcode{*this}. -\end{itemdescr} - -\indexlibrarymember{expired}{weak_ptr}% -\begin{itemdecl} -bool expired() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{use_count() == 0}. -\end{itemdescr} - -\indexlibrarymember{lock}{weak_ptr}% -\begin{itemdecl} -shared_ptr lock() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{expired() ?\ shared_ptr() :\ shared_ptr(*this)}, executed atomically. -\end{itemdescr} - -\indexlibrarymember{owner_before}{weak_ptr}% -\begin{itemdecl} -template bool owner_before(const shared_ptr& b) const noexcept; -template bool owner_before(const weak_ptr& b) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -An unspecified value such that -\begin{itemize} -\item \tcode{x.owner_before(y)} defines a strict weak ordering as defined in~\ref{alg.sorting}; - -\item under the equivalence relation defined by \tcode{owner_before}, -\tcode{!a.owner_before(b) \&\& !b.owner_before(a)}, two \tcode{shared_ptr} or -\tcode{weak_ptr} instances are equivalent if and only if they share ownership or are -both empty. -\end{itemize} -\end{itemdescr} - - -\rSec4[util.smartptr.weak.spec]{Specialized algorithms} - -\indexlibrarymember{swap}{weak_ptr}% -\begin{itemdecl} -template - void swap(weak_ptr& a, weak_ptr& b) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to \tcode{a.swap(b)}. -\end{itemdescr} - -\rSec3[util.smartptr.ownerless]{Class template \tcode{owner_less}} - -\pnum -The class template \tcode{owner_less} allows ownership-based mixed comparisons of shared -and weak pointers. - -\indexlibraryglobal{owner_less}% -\begin{codeblock} -namespace std { - template struct owner_less; - - template struct owner_less> { - bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; - bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; - bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; - }; - - template struct owner_less> { - bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; - bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; - bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; - }; - - template<> struct owner_less { - template - bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; - template - bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; - template - bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; - template - bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; - - using is_transparent = @\unspec@; - }; -} -\end{codeblock} - -\indexlibrarymember{operator()}{owner_less}% -\pnum -\tcode{operator()(x, y)} returns \tcode{x.owner_before(y)}. -\begin{note} -Note that -\begin{itemize} -\item \tcode{operator()} defines a strict weak ordering as defined in~\ref{alg.sorting}; - -\item -two \tcode{shared_ptr} or \tcode{weak_ptr} instances are equivalent -under the equivalence relation defined by \tcode{operator()}, -\tcode{!operator()(a, b) \&\& !operator()(b, a)}, -if and only if they share ownership or are both empty. -\end{itemize} -\end{note} - -\rSec3[util.smartptr.enab]{Class template \tcode{enable_shared_from_this}} - -\pnum -\indexlibraryglobal{enable_shared_from_this}% -A class \tcode{T} can inherit from \tcode{enable_shared_from_this} -to inherit the \tcode{shared_from_this} member functions that obtain -a \tcode{shared_ptr} instance pointing to \tcode{*this}. - -\pnum -\begin{example} -\begin{codeblock} -struct X: public enable_shared_from_this { }; - -int main() { - shared_ptr p(new X); - shared_ptr q = p->shared_from_this(); - assert(p == q); - assert(!p.owner_before(q) && !q.owner_before(p)); // p and q share ownership -} -\end{codeblock} -\end{example} - -\begin{codeblock} -namespace std { - template class enable_shared_from_this { - protected: - constexpr enable_shared_from_this() noexcept; - enable_shared_from_this(const enable_shared_from_this&) noexcept; - enable_shared_from_this& operator=(const enable_shared_from_this&) noexcept; - ~enable_shared_from_this(); - - public: - shared_ptr shared_from_this(); - shared_ptr shared_from_this() const; - weak_ptr weak_from_this() noexcept; - weak_ptr weak_from_this() const noexcept; - - private: - mutable weak_ptr weak_this; // \expos - }; -} -\end{codeblock} - -\pnum -The template parameter \tcode{T} of \tcode{enable_shared_from_this} -may be an incomplete type. - -\indexlibraryctor{enable_shared_from_this}% -\begin{itemdecl} -constexpr enable_shared_from_this() noexcept; -enable_shared_from_this(const enable_shared_from_this&) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Value-initializes \tcode{weak_this}. -\end{itemdescr} - -\indexlibrarymember{operator=}{enable_shared_from_this}% -\begin{itemdecl} -enable_shared_from_this& operator=(const enable_shared_from_this&) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{*this}. - -\pnum -\begin{note} -\tcode{weak_this} is not changed. -\end{note} -\end{itemdescr} - -\indexlibraryglobal{shared_ptr}% -\indexlibrarymember{shared_from_this}{enable_shared_from_this}% -\begin{itemdecl} -shared_ptr shared_from_this(); -shared_ptr shared_from_this() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{shared_ptr(weak_this)}. -\end{itemdescr} - -\indexlibraryglobal{weak_ptr}% -\indexlibrarymember{weak_from_this}{enable_shared_from_this}% -\begin{itemdecl} -weak_ptr weak_from_this() noexcept; -weak_ptr weak_from_this() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{weak_this}. -\end{itemdescr} - -\rSec2[util.smartptr.hash]{Smart pointer hash support} - -\indexlibrarymember{hash}{unique_ptr}% -\begin{itemdecl} -template struct hash>; -\end{itemdecl} - -\begin{itemdescr} -\pnum -Letting \tcode{UP} be \tcode{unique_ptr}, -the specialization \tcode{hash} is enabled\iref{unord.hash} -if and only if \tcode{hash} is enabled. -When enabled, for an object \tcode{p} of type \tcode{UP}, -\tcode{hash()(p)} evaluates to -the same value as \tcode{hash()(p.get())}. -The member functions are not guaranteed to be \keyword{noexcept}. -\end{itemdescr} - -\indexlibrarymember{hash}{shared_ptr}% -\begin{itemdecl} -template struct hash>; -\end{itemdecl} - -\begin{itemdescr} -\pnum -For an object \tcode{p} of type \tcode{shared_ptr}, -\tcode{hash>()(p)} evaluates to -the same value as \tcode{hash::element_type*>()(p.get())}. -\end{itemdescr}% -\indextext{smart pointers|)} - -\rSec2[smartptr.adapt]{Smart pointer adaptors} - -\rSec3[out.ptr.t]{Class template \tcode{out_ptr_t}} - -\pnum -\tcode{out_ptr_t} is a class template used to adapt types -such as smart pointers\iref{smartptr} -for functions that use output pointer parameters. - -\pnum -\begin{example} -\begin{codeblock} -#include -#include - -int fopen_s(std::FILE** f, const char* name, const char* mode); - -struct fclose_deleter { - void operator()(std::FILE* f) const noexcept { - std::fclose(f); - } -}; - -int main(int, char*[]) { - constexpr const char* file_name = "ow.o"; - std::unique_ptr file_ptr; - int err = fopen_s(std::out_ptr(file_ptr), file_name, "r+b"); - if (err != 0) - return 1; - // \tcode{*file_ptr} is valid - return 0; -} -\end{codeblock} -\tcode{unique_ptr} can be used with \tcode{out_ptr} -to be passed into an output pointer-style function, -without needing to hold onto an intermediate pointer value and -manually delete it on error or failure. -\end{example} +\rSec3[func.search.bm]{Class template \tcode{boyer_moore_searcher}} -\indexlibraryglobal{out_ptr_t}% +\indexlibraryglobal{boyer_moore_searcher}% \begin{codeblock} namespace std { - template - class out_ptr_t { + template::value_type>, + class BinaryPredicate = equal_to<>> + class boyer_moore_searcher { public: - explicit out_ptr_t(Smart&, Args...); - out_ptr_t(const out_ptr_t&) = delete; - - ~out_ptr_t(); + boyer_moore_searcher(RandomAccessIterator1 pat_first, + RandomAccessIterator1 pat_last, + Hash hf = Hash(), + BinaryPredicate pred = BinaryPredicate()); - operator Pointer*() const noexcept; - operator void**() const noexcept; + template + pair + operator()(RandomAccessIterator2 first, RandomAccessIterator2 last) const; private: - Smart& s; // \expos - tuple a; // \expos - Pointer p; // \expos + RandomAccessIterator1 pat_first_; // \expos + RandomAccessIterator1 pat_last_; // \expos + Hash hash_; // \expos + BinaryPredicate pred_; // \expos }; } \end{codeblock} -\pnum -\tcode{Pointer} shall meet the \oldconcept{NullablePointer} requirements. -If \tcode{Smart} is a specialization of \tcode{shared_ptr} and -\tcode{sizeof...(Args) == 0}, -the program is ill-formed. -\begin{note} -It is typically a user error to reset a \tcode{shared_ptr} -without specifying a deleter, -as \tcode{shared_ptr} will replace a custom deleter upon usage of \tcode{reset}, -as specified in \ref{util.smartptr.shared.mod}. -\end{note} - -\pnum -Program-defined specializations of \tcode{out_ptr_t} -that depend on at least one program-defined type -need not meet the requirements for the primary template. - -\pnum -Evaluations of the conversion functions -on the same object may conflict\iref{intro.races}. - -\indexlibraryctor{out_ptr_t}% -\begin{itemdecl} -explicit out_ptr_t(Smart& smart, Args... args); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \tcode{s} with \tcode{smart}, -\tcode{a} with \tcode{std::forward(args)...}, and -value-initializes \tcode{p}. - -\pnum -\begin{note} -The constructor is not \tcode{noexcept} -to allow for a variety of non-terminating and safe implementation strategies. -For example, an implementation can allocate -a \tcode{shared_ptr}'s internal node in the constructor and -let implementation-defined exceptions escape safely. -The destructor can then move the allocated control block in directly and -avoid any other exceptions. -\end{note} -\end{itemdescr} - -\indexlibrarydtor{out_ptr_t}% -\begin{itemdecl} -~out_ptr_t(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{SP} be -\tcode{\exposid{POINTER_OF_OR}(Smart, Pointer)}\iref{memory.general}. - -\pnum -\effects -Equivalent to: -\begin{itemize} -\item -% pretend to \item that there is real text here, but undo the vertical spacing -\mbox{}\vspace{-\baselineskip}\vspace{-\parskip} -\begin{codeblock} -if (p) { - apply([&](auto&&... args) { - s.reset(static_cast(p), std::forward(args)...); }, std::move(a)); -} -\end{codeblock} -if the expression -\tcode{s.reset(static_cast(p), std::forward(args)...)} -is well-\linebreak formed; -\item -otherwise, -\begin{codeblock} -if (p) { - apply([&](auto&&... args) { - s = Smart(static_cast(p), std::forward(args)...); }, std::move(a)); -} -\end{codeblock} -if \tcode{is_constructible_v} is \tcode{true}; -\item -otherwise, the program is ill-formed. -\end{itemize} -\end{itemdescr} - -\begin{itemdecl} -operator Pointer*() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{operator void**()} has not been called on \tcode{*this}. - -\pnum -\returns -\tcode{addressof(const_cast(p))}. -\end{itemdescr} - -\begin{itemdecl} -operator void**() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{is_same_v} is \tcode{false}. - -\pnum -\mandates -\tcode{is_pointer_v} is \tcode{true}. - -\pnum -\expects -\tcode{operator Pointer*()} has not been called on \tcode{*this}. - -\pnum -\returns -A pointer value \tcode{v} such that: -\begin{itemize} -\item -the initial value \tcode{*v} is equivalent to \tcode{static_cast(p)} and -\item -any modification of \tcode{*v} -that is not followed by a subsequent modification of \tcode{*this} -affects the value of \tcode{p} during the destruction of \tcode{*this}, -such that \tcode{static_cast(p) == *v}. -\end{itemize} - -\pnum -\remarks -Accessing \tcode{*v} outside the lifetime of \tcode{*this} -has undefined behavior. - -\pnum -\begin{note} -\tcode{reinterpret_cast(static_cast(*this))} -can be a viable implementation strategy for some implementations. -\end{note} -\end{itemdescr} - -\rSec3[out.ptr]{Function template \tcode{out_ptr}} - -\indexlibraryglobal{out_ptr}% -\begin{itemdecl} -template - auto out_ptr(Smart& s, Args&&... args); -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{P} be \tcode{Pointer} -if \tcode{is_void_v} is \tcode{false}, -otherwise \tcode{\exposid{POINTER_OF}(Smart)}. - -\pnum -\returns -\tcode{out_ptr_t(s, std::forward(args)...)} -\end{itemdescr} - -\rSec3[inout.ptr.t]{Class template \tcode{inout_ptr_t}} - -\pnum -\tcode{inout_ptr_t} is a class template used to adapt types -such as smart pointers\iref{smartptr} -for functions that use output pointer parameters -whose dereferenced values may first be deleted -before being set to another allocated value. - -\pnum -\begin{example} -\begin{codeblock} -#include - -struct star_fish* star_fish_alloc(); -int star_fish_populate(struct star_fish** ps, const char* description); - -struct star_fish_deleter { - void operator() (struct star_fish* c) const noexcept; -}; - -using star_fish_ptr = std::unique_ptr; - -int main(int, char*[]) { - star_fish_ptr peach(star_fish_alloc()); - // ... - // used, need to re-make - int err = star_fish_populate(std::inout_ptr(peach), "caring clown-fish liker"); - return err; -} -\end{codeblock} -A \tcode{unique_ptr} can be used with \tcode{inout_ptr} -to be passed into an output pointer-style function. -The original value will be properly deleted -according to the function it is used with and -a new value reset in its place. -\end{example} - -\indexlibraryglobal{inout_ptr_t}% -\begin{codeblock} -namespace std { - template - class inout_ptr_t { - public: - explicit inout_ptr_t(Smart&, Args...); - inout_ptr_t(const inout_ptr_t&) = delete; - - ~inout_ptr_t(); - - operator Pointer*() const noexcept; - operator void**() const noexcept; - - private: - Smart& s; // \expos - tuple a; // \expos - Pointer p; // \expos - }; -} -\end{codeblock} - -\pnum -\tcode{Pointer} shall meet the \oldconcept{NullablePointer} requirements. -If \tcode{Smart} is a specialization of \tcode{shared_ptr}, -the program is ill-formed. -\begin{note} -It is impossible to properly acquire unique ownership of the managed resource -from a \tcode{shared_ptr} given its shared ownership model. -\end{note} - -\pnum -Program-defined specializations of \tcode{inout_ptr_t} -that depend on at least one program-defined type -need not meet the requirements for the primary template. - -\pnum -Evaluations of the conversion functions on the same object -may conflict\iref{intro.races}. - -\indexlibraryctor{inout_ptr_t}% -\begin{itemdecl} -explicit inout_ptr_t(Smart& smart, Args... args); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \tcode{s} with \tcode{smart}, -\tcode{a} with \tcode{std::forward(args)...}, and -\tcode{p} to either -\begin{itemize} -\item \tcode{smart} if \tcode{is_pointer_v} is \tcode{true}, -\item otherwise, \tcode{smart.get()}. -\end{itemize} - -\pnum -\remarks -An implementation can call \tcode{s.release()}. - -\pnum -\begin{note} -The constructor is not \tcode{noexcept} -to allow for a variety of non-terminating and safe implementation strategies. -For example, an intrusive pointer implementation with a control block -can allocate in the constructor and safely fail with an exception. -\end{note} -\end{itemdescr} - -\indexlibrarydtor{inout_ptr_t}% -\begin{itemdecl} -~inout_ptr_t(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{SP} be -\tcode{\exposid{POINTER_OF_OR}(Smart, Pointer)}\iref{memory.general}. - -\pnum -Let \exposid{release-statement} be \tcode{s.release();} -if an implementation does not call \tcode{s.release()} in the constructor. -Otherwise, it is empty. - -\pnum -\effects -Equivalent to: -\begin{itemize} -\item -% pretend to \item that there is real text here, but undo the vertical spacing -\mbox{}\vspace{-\baselineskip}\vspace{-\parskip} -\begin{codeblock} -if (p) { - apply([&](auto&&... args) { - s = Smart( static_cast(p), std::forward(args)...); }, std::move(a)); -} -\end{codeblock} -if \tcode{is_pointer_v} is \tcode{true}; -\item -otherwise, -\begin{codeblock} -if (p) { - apply([&](auto&&... args) { - @\exposid{release-statement}@; - s.reset(static_cast(p), std::forward(args)...); }, std::move(a)); -} -\end{codeblock} -if the expression -\tcode{s.reset(static_cast(p), std::forward(args)...)} -is well-\newline formed; -\item -otherwise, -\begin{codeblock} -if (p) { - apply([&](auto&&... args) { - @\exposid{release-statement}@; - s = Smart(static_cast(p), std::forward(args)...); }, std::move(a)); -} -\end{codeblock} -if \tcode{is_constructible_v} is \tcode{true}; -\item -otherwise, the program is ill-formed. -\end{itemize} -\end{itemdescr} - -\begin{itemdecl} -operator Pointer*() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{operator void**()} has not been called on \tcode{*this}. - -\pnum -\returns -\tcode{addressof(const_cast(p))}. -\end{itemdescr} - -\begin{itemdecl} -operator void**() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{is_same_v} is \tcode{false}. - -\pnum -\mandates -\tcode{is_pointer_v} is \tcode{true}. - -\pnum -\expects -\tcode{operator Pointer*()} has not been called on \tcode{*this}. - -\pnum -\returns -A pointer value \tcode{v} such that: -\begin{itemize} -\item -the initial value \tcode{*v} is equivalent to \tcode{static_cast(p)} and -\item -any modification of \tcode{*v} -that is not followed by subsequent modification of \tcode{*this} -affects the value of \tcode{p} during the destruction of \tcode{*this}, -such that \tcode{static_cast(p) == *v}. -\end{itemize} - -\pnum -\remarks -Accessing \tcode{*v} outside the lifetime of \tcode{*this} -has undefined behavior. - -\pnum -\begin{note} -\tcode{reinterpret_cast(static_cast(*this))} -can be a viable implementation strategy for some implementations. -\end{note} -\end{itemdescr} - -\rSec3[inout.ptr]{Function template \tcode{inout_ptr}} - -\indexlibraryglobal{inout_ptr}% -\begin{itemdecl} -template - auto inout_ptr(Smart& s, Args&&... args); -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{P} be \tcode{Pointer} if \tcode{is_void_v} is \tcode{false}, -otherwise \tcode{\exposid{POINTER_OF}(Smart)}. - -\pnum -\returns -\tcode{inout_ptr_t(s, std::forward(args)...)}. -\end{itemdescr} - -\rSec1[mem.res]{Memory resources} - -\rSec2[mem.res.syn]{Header \tcode{} synopsis} - -\indexheader{memory_resource}% -\begin{codeblock} -namespace std::pmr { - // \ref{mem.res.class}, class \tcode{memory_resource} - class memory_resource; - - bool operator==(const memory_resource& a, const memory_resource& b) noexcept; - - // \ref{mem.poly.allocator.class}, class template \tcode{polymorphic_allocator} - template class polymorphic_allocator; - - template - bool operator==(const polymorphic_allocator& a, - const polymorphic_allocator& b) noexcept; - - // \ref{mem.res.global}, global memory resources - memory_resource* new_delete_resource() noexcept; - memory_resource* null_memory_resource() noexcept; - memory_resource* set_default_resource(memory_resource* r) noexcept; - memory_resource* get_default_resource() noexcept; - - // \ref{mem.res.pool}, pool resource classes - struct pool_options; - class synchronized_pool_resource; - class unsynchronized_pool_resource; - class monotonic_buffer_resource; -} -\end{codeblock} - -\rSec2[mem.res.class]{Class \tcode{memory_resource}} - -\rSec3[mem.res.class.general]{General} - -\pnum -The \tcode{memory_resource} class is an abstract interface to an unbounded set of classes encapsulating memory resources. - -\indexlibraryglobal{memory_resource}% -\indexlibrarymember{operator=}{memory_resource}% -\begin{codeblock} -namespace std::pmr { - class memory_resource { - static constexpr size_t max_align = alignof(max_align_t); // \expos - - public: - memory_resource() = default; - memory_resource(const memory_resource&) = default; - virtual ~memory_resource(); - - memory_resource& operator=(const memory_resource&) = default; - - [[nodiscard]] void* allocate(size_t bytes, size_t alignment = max_align); - void deallocate(void* p, size_t bytes, size_t alignment = max_align); - - bool is_equal(const memory_resource& other) const noexcept; - - private: - virtual void* do_allocate(size_t bytes, size_t alignment) = 0; - virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0; - - virtual bool do_is_equal(const memory_resource& other) const noexcept = 0; - }; -} -\end{codeblock} - - -\rSec3[mem.res.public]{Public member functions} - -\indexlibrarydtor{memory_resource}% -\begin{itemdecl} -~memory_resource(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Destroys this \tcode{memory_resource}. -\end{itemdescr} - -\indexlibrarymember{allocate}{memory_resource}% -\begin{itemdecl} -[[nodiscard]] void* allocate(size_t bytes, size_t alignment = max_align); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Allocates storage by calling \tcode{do_allocate(bytes, alignment)} and -implicitly creates objects within the allocated region of storage. - -\pnum -\returns -A pointer to a suitable created object\iref{intro.object} -in the allocated region of storage. - -\pnum -\throws -What and when the call to \tcode{do_allocate} throws. -\end{itemdescr} - -\indexlibrarymember{deallocate}{memory_resource}% -\begin{itemdecl} -void deallocate(void* p, size_t bytes, size_t alignment = max_align); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to \tcode{do_deallocate(p, bytes, alignment)}. -\end{itemdescr} - -\indexlibrarymember{is_equal}{memory_resource}% -\begin{itemdecl} -bool is_equal(const memory_resource& other) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return do_is_equal(other);} -\end{itemdescr} - - -\rSec3[mem.res.private]{Private virtual member functions} - -\indexlibrarymember{do_allocate}{memory_resource}% -\begin{itemdecl} -virtual void* do_allocate(size_t bytes, size_t alignment) = 0; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{alignment} is a power of two. - -\pnum -\returns -A derived class shall implement this function to -return a pointer to allocated storage\iref{basic.stc.dynamic.allocation} -with a size of at least \tcode{bytes}, -aligned to the specified \tcode{alignment}. - -\pnum -\throws -A derived class implementation shall throw an appropriate exception if it is unable to allocate memory with the requested size and alignment. -\end{itemdescr} - -\indexlibrarymember{do_deallocate}{memory_resource}% -\begin{itemdecl} -virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{p} was returned from a prior call to \tcode{allocate(bytes, alignment)} -on a memory resource equal to \tcode{*this}, -and the storage at \tcode{p} has not yet been deallocated. - -\pnum -\effects -A derived class shall implement this function to dispose of allocated storage. - -\pnum -\throws -Nothing. -\end{itemdescr} - -\indexlibrarymember{do_is_equal}{memory_resource}% -\begin{itemdecl} -virtual bool do_is_equal(const memory_resource& other) const noexcept = 0; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A derived class shall implement this function to return \tcode{true} if memory allocated from \keyword{this} can be deallocated from \tcode{other} and vice-versa, -otherwise \tcode{false}. -\begin{note} -It is possible that the most-derived type of \tcode{other} does not match the type of \keyword{this}. -For a derived class \tcode{D}, an implementation of this function -can immediately return \tcode{false} -if \tcode{dynamic_cast(\&other) == nullptr}. -\end{note} -\end{itemdescr} - -\rSec3[mem.res.eq]{Equality} - -\indexlibrarymember{operator==}{memory_resource}% -\begin{itemdecl} -bool operator==(const memory_resource& a, const memory_resource& b) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{\&a == \&b || a.is_equal(b)}. -\end{itemdescr} - -\rSec2[mem.poly.allocator.class]{Class template \tcode{polymorphic_allocator}} - -\rSec3[mem.poly.allocator.class.general]{General} - -\pnum -A specialization of class template \tcode{pmr::polymorphic_allocator} -meets the \oldconcept{Allocator} requirements (\tref{cpp17.allocator}). -Constructed with different memory resources, -different instances of the same specialization of \tcode{pmr::polymorphic_allocator} -can exhibit entirely different allocation behavior. -This runtime polymorphism allows objects that use \tcode{polymorphic_allocator} -to behave as if they used different allocator types at run time -even though they use the same static allocator type. - -\pnum -All specializations of class template \tcode{pmr::polymorphic_allocator} -meet the allocator completeness requirements\iref{allocator.requirements.completeness}. - -\indexlibraryglobal{polymorphic_allocator}% -\indexlibrarymember{value_type}{polymorphic_allocator}% -\begin{codeblock} -namespace std::pmr { - template class polymorphic_allocator { - memory_resource* memory_rsrc; // \expos - - public: - using value_type = Tp; - - // \ref{mem.poly.allocator.ctor}, constructors - polymorphic_allocator() noexcept; - polymorphic_allocator(memory_resource* r); - - polymorphic_allocator(const polymorphic_allocator& other) = default; - - template - polymorphic_allocator(const polymorphic_allocator& other) noexcept; - - polymorphic_allocator& operator=(const polymorphic_allocator&) = delete; - - // \ref{mem.poly.allocator.mem}, member functions - [[nodiscard]] Tp* allocate(size_t n); - void deallocate(Tp* p, size_t n); - - [[nodiscard]] void* allocate_bytes(size_t nbytes, size_t alignment = alignof(max_align_t)); - void deallocate_bytes(void* p, size_t nbytes, size_t alignment = alignof(max_align_t)); - template [[nodiscard]] T* allocate_object(size_t n = 1); - template void deallocate_object(T* p, size_t n = 1); - template [[nodiscard]] T* new_object(CtorArgs&&... ctor_args); - template void delete_object(T* p); - - template - void construct(T* p, Args&&... args); - - polymorphic_allocator select_on_container_copy_construction() const; - - memory_resource* resource() const; - }; -} -\end{codeblock} - -\rSec3[mem.poly.allocator.ctor]{Constructors} - -\indexlibraryctor{polymorphic_allocator}% -\begin{itemdecl} -polymorphic_allocator() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Sets \tcode{memory_rsrc} to \tcode{get_default_resource()}. -\end{itemdescr} - -\indexlibraryctor{polymorphic_allocator}% -\begin{itemdecl} -polymorphic_allocator(memory_resource* r); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{r} is non-null. - -\pnum -\effects -Sets \tcode{memory_rsrc} to \tcode{r}. - -\pnum -\throws -Nothing. - -\pnum -\begin{note} -This constructor provides an implicit conversion from \tcode{memory_resource*}. -\end{note} -\end{itemdescr} - -\indexlibraryctor{polymorphic_allocator}% -\begin{itemdecl} -template polymorphic_allocator(const polymorphic_allocator& other) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Sets \tcode{memory_rsrc} to \tcode{other.resource()}. -\end{itemdescr} - - -\rSec3[mem.poly.allocator.mem]{Member functions} - -\indexlibrarymember{allocate}{polymorphic_allocator}% -\begin{itemdecl} -[[nodiscard]] Tp* allocate(size_t n); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If \tcode{numeric_limits::max() / sizeof(Tp) < n}, -throws \tcode{bad_array_new_length}. -Otherwise equivalent to: -\begin{codeblock} -return static_cast(memory_rsrc->allocate(n * sizeof(Tp), alignof(Tp))); -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{deallocate}{polymorphic_allocator}% -\begin{itemdecl} -void deallocate(Tp* p, size_t n); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{p} was allocated from a memory resource \tcode{x}, -equal to \tcode{*memory_rsrc}, -using \tcode{x.allocate(n * sizeof(Tp), alignof(Tp))}. - -\pnum -\effects -Equivalent to \tcode{memory_rsrc->deallocate(p, n * sizeof(Tp), alignof(Tp))}. - -\pnum -\throws -Nothing. -\end{itemdescr} - -\indexlibrarymember{allocate_bytes}{polymorphic_allocator}% -\begin{itemdecl} -[[nodiscard]] void* allocate_bytes(size_t nbytes, size_t alignment = alignof(max_align_t)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return memory_rsrc->allocate(nbytes, alignment);} - -\pnum -\begin{note} -The return type is \tcode{void*} (rather than, e.g., \tcode{byte*}) -to support conversion to an arbitrary pointer type \tcode{U*} -by \tcode{static_cast}, thus facilitating construction of a \tcode{U} -object in the allocated memory. -\end{note} -\end{itemdescr} - -\indexlibrarymember{deallocate_bytes}{polymorphic_allocator}% -\begin{itemdecl} -void deallocate_bytes(void* p, size_t nbytes, size_t alignment = alignof(max_align_t)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to \tcode{memory_rsrc->deallocate(p, nbytes, alignment)}. -\end{itemdescr} - -\indexlibrarymember{allocate_object}{polymorphic_allocator}% -\begin{itemdecl} -template - [[nodiscard]] T* allocate_object(size_t n = 1); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Allocates memory suitable for holding -an array of \tcode{n} objects of type \tcode{T}, as follows: -\begin{itemize} -\item - if \tcode{numeric_limits::max() / sizeof(T) < n}, - throws \tcode{bad_array_new_length}, -\item - otherwise equivalent to: -\begin{codeblock} -return static_cast(allocate_bytes(n*sizeof(T), alignof(T))); -\end{codeblock} -\end{itemize} - -\pnum -\begin{note} -\tcode{T} is not deduced and must therefore be provided as a template argument. -\end{note} -\end{itemdescr} - -\indexlibrarymember{deallocate_object}{polymorphic_allocator}% -\begin{itemdecl} -template - void deallocate_object(T* p, size_t n = 1); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to \tcode{deallocate_bytes(p, n*sizeof(T), alignof(T))}. -\end{itemdescr} - -\indexlibrarymember{new_object}{polymorphic_allocator}% -\begin{itemdecl} -template - [[nodiscard]] T* new_object(CtorArgs&&... ctor_args); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Allocates and constructs an object of type \tcode{T}, as follows.\newline -Equivalent to: -\begin{codeblock} -T* p = allocate_object(); -try { - construct(p, std::forward(ctor_args)...); -} catch (...) { - deallocate_object(p); - throw; -} -return p; -\end{codeblock} - -\pnum -\begin{note} -\tcode{T} is not deduced and must therefore be provided as a template argument. -\end{note} -\end{itemdescr} - -\indexlibrarymember{new_object}{polymorphic_allocator}% -\begin{itemdecl} -template - void delete_object(T* p); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -allocator_traits::destroy(*this, p); -deallocate_object(p); -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{construct}{polymorphic_allocator}% -\begin{itemdecl} -template - void construct(T* p, Args&&... args); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\mandates -Uses-allocator construction of \tcode{T} -with allocator \tcode{*this} (see~\ref{allocator.uses.construction}) -and constructor arguments \tcode{std::forward(args)...} is well-formed. - -\pnum -\effects -Construct a \tcode{T} object in the storage -whose address is represented by \tcode{p} -by uses-allocator construction with allocator \tcode{*this} -and constructor arguments \tcode{std::forward(args)...}. - -\pnum -\throws -Nothing unless the constructor for \tcode{T} throws. -\end{itemdescr} - -\indexlibrarymember{select_on_container_copy_construction}{polymorphic_allocator}% -\begin{itemdecl} -polymorphic_allocator select_on_container_copy_construction() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{polymorphic_allocator()}. - -\pnum -\begin{note} -The memory resource is not propagated. -\end{note} -\end{itemdescr} - -\indexlibrarymember{resource}{polymorphic_allocator}% -\begin{itemdecl} -memory_resource* resource() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{memory_rsrc}. -\end{itemdescr} - -\rSec3[mem.poly.allocator.eq]{Equality} - -\indexlibrarymember{operator==}{polymorphic_allocator}% -\begin{itemdecl} -template - bool operator==(const polymorphic_allocator& a, - const polymorphic_allocator& b) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{*a.resource() == *b.resource()}. -\end{itemdescr} - -\rSec2[mem.res.global]{Access to program-wide \tcode{memory_resource} objects} - -\indexlibraryglobal{new_delete_resource}% -\begin{itemdecl} -memory_resource* new_delete_resource() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A pointer to a static-duration object of a type derived from \tcode{memory_resource} -that can serve as a resource for allocating memory -using \tcode{::operator new} and \tcode{::operator delete}. -The same value is returned every time this function is called. -For a return value \tcode{p} and a memory resource \tcode{r}, -\tcode{p->is_equal(r)} returns \tcode{\&r == p}. -\end{itemdescr} - -\indexlibraryglobal{null_memory_resource}% -\begin{itemdecl} -memory_resource* null_memory_resource() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A pointer to a static-duration object of a type derived from \tcode{memory_resource} -for which \tcode{allocate()} always throws \tcode{bad_alloc} and -for which \tcode{deallocate()} has no effect. -The same value is returned every time this function is called. -For a return value \tcode{p} and a memory resource \tcode{r}, -\tcode{p->is_equal(r)} returns \tcode{\&r == p}. -\end{itemdescr} - -\pnum -The \defn{default memory resource pointer} is a pointer to a memory resource -that is used by certain facilities when an explicit memory resource -is not supplied through the interface. -Its initial value is the return value of \tcode{new_delete_resource()}. - -\indexlibraryglobal{set_default_resource}% -\begin{itemdecl} -memory_resource* set_default_resource(memory_resource* r) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If \tcode{r} is non-null, -sets the value of the default memory resource pointer to \tcode{r}, -otherwise sets the default memory resource pointer to \tcode{new_delete_resource()}. - -\pnum -\returns -The previous value of the default memory resource pointer. - -\pnum -\remarks -Calling the \tcode{set_default_resource} and -\tcode{get_default_resource} functions shall not incur a data race. -A call to the \tcode{set_default_resource} function -shall synchronize with subsequent calls to -the \tcode{set_default_resource} and \tcode{get_default_resource} functions. -\end{itemdescr} - -\indexlibraryglobal{get_default_resource}% -\begin{itemdecl} -memory_resource* get_default_resource() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The current value of the default memory resource pointer. -\end{itemdescr} - -\rSec2[mem.res.pool]{Pool resource classes} - -\rSec3[mem.res.pool.overview]{Classes \tcode{synchronized_pool_resource} and \tcode{unsynchronized_pool_resource}} - -\pnum -The \tcode{synchronized_pool_resource} and -\tcode{unsynchronized_pool_resource} classes -(collectively called \defn{pool resource classes}) -are general-purpose memory resources having the following qualities: -\begin{itemize} -\item -Each resource frees its allocated memory on destruction, -even if \tcode{deallocate} has not been called for some of the allocated blocks. -\item -A pool resource consists of a collection of \defn{pools}, -serving requests for different block sizes. -Each individual pool manages a collection of \defn{chunks} -that are in turn divided into blocks of uniform size, -returned via calls to \tcode{do_allocate}. -Each call to \tcode{do_allocate(size, alignment)} is dispatched -to the pool serving the smallest blocks accommodating at least \tcode{size} bytes. -\item -When a particular pool is exhausted, -allocating a block from that pool results in the allocation -of an additional chunk of memory from the \defn{upstream allocator} -(supplied at construction), thus replenishing the pool. -With each successive replenishment, -the chunk size obtained increases geometrically. -\begin{note} -By allocating memory in chunks, -the pooling strategy increases the chance that consecutive allocations -will be close together in memory. -\end{note} -\item -Allocation requests that exceed the largest block size of any pool -are fulfilled directly from the upstream allocator. -\item -A \tcode{pool_options} struct may be passed to the pool resource constructors -to tune the largest block size and the maximum chunk size. -\end{itemize} - -\pnum -A \tcode{synchronized_pool_resource} may be accessed from multiple threads -without external synchronization -and may have thread-specific pools to reduce synchronization costs. -An \tcode{unsynchronized_pool_resource} class may not be accessed -from multiple threads simultaneously -and thus avoids the cost of synchronization entirely -in single-threaded applications. - -\indexlibraryglobal{pool_options}% -\indexlibraryglobal{synchronized_pool_resource}% -\indexlibraryglobal{unsynchronized_pool_resource}% -\begin{codeblock} -namespace std::pmr { - struct pool_options { - size_t max_blocks_per_chunk = 0; - size_t largest_required_pool_block = 0; - }; - - class synchronized_pool_resource : public memory_resource { - public: - synchronized_pool_resource(const pool_options& opts, memory_resource* upstream); - - synchronized_pool_resource() - : synchronized_pool_resource(pool_options(), get_default_resource()) {} - explicit synchronized_pool_resource(memory_resource* upstream) - : synchronized_pool_resource(pool_options(), upstream) {} - explicit synchronized_pool_resource(const pool_options& opts) - : synchronized_pool_resource(opts, get_default_resource()) {} - - synchronized_pool_resource(const synchronized_pool_resource&) = delete; - virtual ~synchronized_pool_resource(); - - synchronized_pool_resource& operator=(const synchronized_pool_resource&) = delete; - - void release(); - memory_resource* upstream_resource() const; - pool_options options() const; - - protected: - void* do_allocate(size_t bytes, size_t alignment) override; - void do_deallocate(void* p, size_t bytes, size_t alignment) override; - - bool do_is_equal(const memory_resource& other) const noexcept override; - }; - - class unsynchronized_pool_resource : public memory_resource { - public: - unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream); - - unsynchronized_pool_resource() - : unsynchronized_pool_resource(pool_options(), get_default_resource()) {} - explicit unsynchronized_pool_resource(memory_resource* upstream) - : unsynchronized_pool_resource(pool_options(), upstream) {} - explicit unsynchronized_pool_resource(const pool_options& opts) - : unsynchronized_pool_resource(opts, get_default_resource()) {} - - unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete; - virtual ~unsynchronized_pool_resource(); - - unsynchronized_pool_resource& operator=(const unsynchronized_pool_resource&) = delete; - - void release(); - memory_resource* upstream_resource() const; - pool_options options() const; - - protected: - void* do_allocate(size_t bytes, size_t alignment) override; - void do_deallocate(void* p, size_t bytes, size_t alignment) override; - - bool do_is_equal(const memory_resource& other) const noexcept override; - }; -} -\end{codeblock} - -\rSec3[mem.res.pool.options]{\tcode{pool_options} data members} - -\pnum -The members of \tcode{pool_options} -comprise a set of constructor options for pool resources. -The effect of each option on the pool resource behavior is described below: - -\indexlibrarymember{pool_options}{max_blocks_per_chunk}% -\begin{itemdecl} -size_t max_blocks_per_chunk; -\end{itemdecl} - -\begin{itemdescr} -\pnum -The maximum number of blocks that will be allocated at once -from the upstream memory resource\iref{mem.res.monotonic.buffer} -to replenish a pool. -If the value of \tcode{max_blocks_per_chunk} is zero or -is greater than an \impldef{largest supported value to configure the maximum number of blocks to replenish a pool} -limit, that limit is used instead. -The implementation -may choose to use a smaller value than is specified in this field and -may use different values for different pools. -\end{itemdescr} - -\indexlibrarymember{pool_options}{largest_required_pool_block}% -\begin{itemdecl} -size_t largest_required_pool_block; -\end{itemdecl} - -\begin{itemdescr} -\pnum -The largest allocation size that is required to be fulfilled -using the pooling mechanism. -Attempts to allocate a single block larger than this threshold -will be allocated directly from the upstream memory resource. -If \tcode{largest_required_pool_block} is zero or -is greater than an \impldef{largest supported value to configure the largest allocation satisfied directly by a pool} -limit, that limit is used instead. -The implementation may choose a pass-through threshold -larger than specified in this field. -\end{itemdescr} - -\rSec3[mem.res.pool.ctor]{Constructors and destructors} - -\indexlibraryctor{synchronized_pool_resource}% -\indexlibraryctor{unsynchronized_pool_resource}% -\begin{itemdecl} -synchronized_pool_resource(const pool_options& opts, memory_resource* upstream); -unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{upstream} is the address of a valid memory resource. - -\pnum -\effects -Constructs a pool resource object that will obtain memory from \tcode{upstream} -whenever the pool resource is unable to satisfy a memory request -from its own internal data structures. -The resulting object will hold a copy of \tcode{upstream}, -but will not own the resource to which \tcode{upstream} points. -\begin{note} -The intention is that calls to \tcode{upstream->allocate()} -will be substantially fewer than calls to \tcode{this->allocate()} -in most cases. -\end{note} -The behavior of the pooling mechanism is tuned -according to the value of the \tcode{opts} argument. - -\pnum -\throws -Nothing unless \tcode{upstream->allocate()} throws. -It is unspecified if, or under what conditions, -this constructor calls \tcode{upstream->allocate()}. -\end{itemdescr} - -\indexlibrarydtor{synchronized_pool_resource}% -\indexlibrarydtor{unsynchronized_pool_resource}% -\begin{itemdecl} -virtual ~synchronized_pool_resource(); -virtual ~unsynchronized_pool_resource(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Calls \tcode{release()}. -\end{itemdescr} - -\rSec3[mem.res.pool.mem]{Members} - -\indexlibrarymember{release}{synchronized_pool_resource}% -\indexlibrarymember{release}{unsynchronized_pool_resource}% -\begin{itemdecl} -void release(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Calls \tcode{upstream_resource()->deallocate()} as necessary -to release all allocated memory. -\begin{note} -The memory is released back to \tcode{upstream_resource()} -even if \tcode{deallocate} has not been called -for some of the allocated blocks. -\end{note} -\end{itemdescr} - -\indexlibrarymember{upstream_resource}{synchronized_pool_resource}% -\indexlibrarymember{upstream_resource}{unsynchronized_pool_resource}% -\begin{itemdecl} -memory_resource* upstream_resource() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The value of the \tcode{upstream} argument -provided to the constructor of this object. -\end{itemdescr} - -\indexlibrarymember{options}{synchronized_pool_resource}% -\indexlibrarymember{options}{unsynchronized_pool_resource}% -\begin{itemdecl} -pool_options options() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The options that control the pooling behavior of this resource. -The values in the returned struct may differ -from those supplied to the pool resource constructor in that -values of zero will be replaced with \impldef{default configuration of a pool} -defaults, and sizes may be rounded to unspecified granularity. -\end{itemdescr} - -\indexlibrarymember{do_allocate}{synchronized_pool_resource}% -\indexlibrarymember{do_allocate}{unsynchronized_pool_resource}% -\begin{itemdecl} -void* do_allocate(size_t bytes, size_t alignment) override; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If the pool selected for a block of size \tcode{bytes} -is unable to satisfy the memory request from its own internal data structures, -it will call \tcode{upstream_resource()->allocate()} to obtain more memory. -If \tcode{bytes} is larger than that which the largest pool can handle, -then memory will be allocated using \tcode{upstream_resource()->allocate()}. - -\pnum -\returns -A pointer to allocated storage\iref{basic.stc.dynamic.allocation} -with a size of at least \tcode{bytes}. -The size and alignment of the allocated memory shall meet the requirements -for a class derived from \tcode{memory_resource}\iref{mem.res.class}. - -\pnum -\throws -Nothing unless \tcode{upstream_resource()->allocate()} throws. -\end{itemdescr} - -\indexlibrarymember{do_deallocate}{synchronized_pool_resource}% -\indexlibrarymember{do_deallocate}{unsynchronized_pool_resource}% -\begin{itemdecl} -void do_deallocate(void* p, size_t bytes, size_t alignment) override; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Returns the memory at \tcode{p} to the pool. -It is unspecified if, or under what circumstances, -this operation will result in a call to \tcode{upstream_resource()->deallocate()}. - -\pnum -\throws -Nothing. -\end{itemdescr} - -\indexlibrarymember{do_is_equal}{synchronized_pool_resource}% -\indexlibrarymember{do_is_equal}{unsynchronized_pool_resource}% -\begin{itemdecl} -bool do_is_equal(const memory_resource& other) const noexcept override; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{this == \&other}. -\end{itemdescr} - -\rSec2[mem.res.monotonic.buffer]{Class \tcode{monotonic_buffer_resource}} - -\rSec3[mem.res.monotonic.buffer.general]{General} - -\pnum -A \tcode{monotonic_buffer_resource} is a special-purpose memory resource -intended for very fast memory allocations in situations -where memory is used to build up a few objects -and then is released all at once when the memory resource object is destroyed. - -\indexlibraryglobal{monotonic_buffer_resource}% -\begin{codeblock} -namespace std::pmr { - class monotonic_buffer_resource : public memory_resource { - memory_resource* upstream_rsrc; // \expos - void* current_buffer; // \expos - size_t next_buffer_size; // \expos - - public: - explicit monotonic_buffer_resource(memory_resource* upstream); - monotonic_buffer_resource(size_t initial_size, memory_resource* upstream); - monotonic_buffer_resource(void* buffer, size_t buffer_size, memory_resource* upstream); - - monotonic_buffer_resource() - : monotonic_buffer_resource(get_default_resource()) {} - explicit monotonic_buffer_resource(size_t initial_size) - : monotonic_buffer_resource(initial_size, get_default_resource()) {} - monotonic_buffer_resource(void* buffer, size_t buffer_size) - : monotonic_buffer_resource(buffer, buffer_size, get_default_resource()) {} - - monotonic_buffer_resource(const monotonic_buffer_resource&) = delete; - - virtual ~monotonic_buffer_resource(); - - monotonic_buffer_resource& operator=(const monotonic_buffer_resource&) = delete; - - void release(); - memory_resource* upstream_resource() const; - - protected: - void* do_allocate(size_t bytes, size_t alignment) override; - void do_deallocate(void* p, size_t bytes, size_t alignment) override; - - bool do_is_equal(const memory_resource& other) const noexcept override; - }; -} -\end{codeblock} - -\rSec3[mem.res.monotonic.buffer.ctor]{Constructors and destructor} - -\indexlibraryctor{monotonic_buffer_resource}% -\begin{itemdecl} -explicit monotonic_buffer_resource(memory_resource* upstream); -monotonic_buffer_resource(size_t initial_size, memory_resource* upstream); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{upstream} is the address of a valid memory resource. -\tcode{initial_size}, if specified, is greater than zero. - -\pnum -\effects -Sets \tcode{upstream_rsrc} to \tcode{upstream} and -\tcode{current_buffer} to \keyword{nullptr}. -If \tcode{initial_size} is specified, -sets \tcode{next_buffer_size} to at least \tcode{initial_size}; -otherwise sets \tcode{next_buffer_size} to an -\impldef{default \tcode{next_buffer_size} for a \tcode{monotonic_buffer_resource}} size. -\end{itemdescr} - -\indexlibraryctor{monotonic_buffer_resource}% -\begin{itemdecl} -monotonic_buffer_resource(void* buffer, size_t buffer_size, memory_resource* upstream); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{upstream} is the address of a valid memory resource. -\tcode{buffer_size} is no larger than the number of bytes in \tcode{buffer}. - -\pnum -\effects -Sets \tcode{upstream_rsrc} to \tcode{upstream}, -\tcode{current_buffer} to \tcode{buffer}, and -\tcode{next_buffer_size} to \tcode{buffer_size} (but not less than 1), -then increases \tcode{next_buffer_size} -by an \impldef{growth factor for \tcode{monotonic_buffer_resource}} growth factor (which need not be integral). -\end{itemdescr} - -\indexlibrarydtor{monotonic_buffer_resource}% -\begin{itemdecl} -~monotonic_buffer_resource(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Calls \tcode{release()}. -\end{itemdescr} - - -\rSec3[mem.res.monotonic.buffer.mem]{Members} - -\indexlibrarymember{release}{monotonic_buffer_resource}% -\begin{itemdecl} -void release(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Calls \tcode{upstream_rsrc->deallocate()} as necessary -to release all allocated memory. -Resets \tcode{current_buffer} and \tcode{next_buffer_size} -to their initial values at construction. - -\pnum -\begin{note} -The memory is released back to \tcode{upstream_rsrc} -even if some blocks that were allocated from \keyword{this} -have not been deallocated from \keyword{this}. -\end{note} -\end{itemdescr} - -\indexlibrarymember{upstream_resource}{monotonic_buffer_resource}% -\begin{itemdecl} -memory_resource* upstream_resource() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The value of \tcode{upstream_rsrc}. -\end{itemdescr} - -\indexlibrarymember{do_allocate}{monotonic_buffer_resource}% -\begin{itemdecl} -void* do_allocate(size_t bytes, size_t alignment) override; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If the unused space in \tcode{current_buffer} -can fit a block with the specified \tcode{bytes} and \tcode{alignment}, -then allocate the return block from \tcode{current_buffer}; -otherwise set \tcode{current_buffer} to \tcode{upstream_rsrc->allocate(n, m)}, -where \tcode{n} is not less than \tcode{max(bytes, next_buffer_size)} and -\tcode{m} is not less than \tcode{alignment}, -and increase \tcode{next_buffer_size} -by an \impldef{growth factor for \tcode{monotonic_buffer_resource}} growth factor (which need not be integral), -then allocate the return block from the newly-allocated \tcode{current_buffer}. - -\pnum -\returns -A pointer to allocated storage\iref{basic.stc.dynamic.allocation} -with a size of at least \tcode{bytes}. -The size and alignment of the allocated memory shall meet the requirements -for a class derived from \tcode{memory_resource}\iref{mem.res.class}. - -\pnum -\throws -Nothing unless \tcode{upstream_rsrc->allocate()} throws. -\end{itemdescr} - -\indexlibrarymember{do_deallocate}{monotonic_buffer_resource}% -\begin{itemdecl} -void do_deallocate(void* p, size_t bytes, size_t alignment) override; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -None. - -\pnum -\throws -Nothing. - -\pnum -\remarks -Memory used by this resource increases monotonically until its destruction. -\end{itemdescr} - -\indexlibrarymember{do_is_equal}{monotonic_buffer_resource}% -\begin{itemdecl} -bool do_is_equal(const memory_resource& other) const noexcept override; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{this == \&other}. -\end{itemdescr} - - -\rSec1[allocator.adaptor]{Class template \tcode{scoped_allocator_adaptor}} - -\rSec2[allocator.adaptor.syn]{Header \tcode{} synopsis} - -\indexheader{scoped_allocator}% -\begin{codeblock} -namespace std { - // class template \tcode{scoped allocator adaptor} - template - class scoped_allocator_adaptor; - - // \ref{scoped.adaptor.operators}, scoped allocator operators - template - bool operator==(const scoped_allocator_adaptor& a, - const scoped_allocator_adaptor& b) noexcept; -} -\end{codeblock} - -\pnum -The class template \tcode{scoped_allocator_adaptor} is an allocator template that -specifies an allocator resource (the outer allocator) to be used by a container (as any -other allocator does) and also specifies an inner allocator resource to be passed to the -constructor of every element within the container. This adaptor is instantiated with one -outer and zero or more inner allocator types. If instantiated with only one allocator -type, the inner allocator becomes the \tcode{scoped_allocator_adaptor} itself, thus -using the same allocator resource for the container and every element within the -container and, if the elements themselves are containers, each of their elements -recursively. If instantiated with more than one allocator, the first allocator is the -outer allocator for use by the container, the second allocator is passed to the -constructors of the container's elements, and, if the elements themselves are -containers, the third allocator is passed to the elements' elements, and so on. If -containers are nested to a depth greater than the number of allocators, the last -allocator is used repeatedly, as in the single-allocator case, for any remaining -recursions. -\begin{note} -The \tcode{scoped_allocator_adaptor} is derived from the outer -allocator type so it can be substituted for the outer allocator type in most -expressions. -\end{note} - -\indexlibraryglobal{scoped_allocator_adaptor}% -\indexlibrarymember{outer_allocator_type}{scoped_allocator_adaptor}% -\indexlibrarymember{value_type}{scoped_allocator_adaptor}% -\indexlibrarymember{size_type}{scoped_allocator_adaptor}% -\indexlibrarymember{difference_type}{scoped_allocator_adaptor}% -\indexlibrarymember{pointer}{scoped_allocator_adaptor}% -\indexlibrarymember{const_pointer}{scoped_allocator_adaptor}% -\indexlibrarymember{void_pointer}{scoped_allocator_adaptor}% -\indexlibrarymember{const_void_pointer}{scoped_allocator_adaptor}% -\begin{codeblock} -namespace std { - template - class scoped_allocator_adaptor : public OuterAlloc { - private: - using OuterTraits = allocator_traits; // \expos - scoped_allocator_adaptor inner; // \expos - - public: - using outer_allocator_type = OuterAlloc; - using inner_allocator_type = @\seebelow@; - - using value_type = typename OuterTraits::value_type; - using size_type = typename OuterTraits::size_type; - using difference_type = typename OuterTraits::difference_type; - using pointer = typename OuterTraits::pointer; - using const_pointer = typename OuterTraits::const_pointer; - using void_pointer = typename OuterTraits::void_pointer; - using const_void_pointer = typename OuterTraits::const_void_pointer; - - using propagate_on_container_copy_assignment = @\seebelow@; - using propagate_on_container_move_assignment = @\seebelow@; - using propagate_on_container_swap = @\seebelow@; - using is_always_equal = @\seebelow@; - - template struct rebind { - using other = scoped_allocator_adaptor< - OuterTraits::template rebind_alloc, InnerAllocs...>; - }; - - scoped_allocator_adaptor(); - template - scoped_allocator_adaptor(OuterA2&& outerAlloc, - const InnerAllocs&... innerAllocs) noexcept; - - scoped_allocator_adaptor(const scoped_allocator_adaptor& other) noexcept; - scoped_allocator_adaptor(scoped_allocator_adaptor&& other) noexcept; - - template - scoped_allocator_adaptor( - const scoped_allocator_adaptor& other) noexcept; - template - scoped_allocator_adaptor( - scoped_allocator_adaptor&& other) noexcept; - - scoped_allocator_adaptor& operator=(const scoped_allocator_adaptor&) = default; - scoped_allocator_adaptor& operator=(scoped_allocator_adaptor&&) = default; - - ~scoped_allocator_adaptor(); - - inner_allocator_type& inner_allocator() noexcept; - const inner_allocator_type& inner_allocator() const noexcept; - outer_allocator_type& outer_allocator() noexcept; - const outer_allocator_type& outer_allocator() const noexcept; - - [[nodiscard]] pointer allocate(size_type n); - [[nodiscard]] pointer allocate(size_type n, const_void_pointer hint); - void deallocate(pointer p, size_type n); - size_type max_size() const; - - template - void construct(T* p, Args&&... args); - - template - void destroy(T* p); - - scoped_allocator_adaptor select_on_container_copy_construction() const; - }; - - template - scoped_allocator_adaptor(OuterAlloc, InnerAllocs...) - -> scoped_allocator_adaptor; -} -\end{codeblock} - -\rSec2[allocator.adaptor.types]{Member types} - -\indexlibrarymember{inner_allocator_type}{scoped_allocator_adaptor}% -\begin{itemdecl} -using inner_allocator_type = @\seebelow@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ctype \tcode{scoped_allocator_adaptor} if \tcode{sizeof...(InnerAllocs)} is -zero; otherwise,\\ \tcode{scoped_allocator_adaptor}. -\end{itemdescr} - -\indexlibrarymember{propagate_on_container_copy_assignment}{scoped_allocator_adaptor}% -\begin{itemdecl} -using propagate_on_container_copy_assignment = @\seebelow@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ctype \tcode{true_type} if -\tcode{allocator_traits::propagate_on_container_copy_assignment::value} is -\tcode{true} for any \tcode{A} in the set of \tcode{OuterAlloc} and -\tcode{InnerAllocs...}; otherwise, \tcode{false_type}. -\end{itemdescr} - -\indexlibrarymember{propagate_on_container_move_assignment}{scoped_allocator_adaptor}% -\begin{itemdecl} -using propagate_on_container_move_assignment = @\seebelow@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ctype \tcode{true_type} if -\tcode{allocator_traits::propagate_on_container_move_assignment::value} is -\tcode{true} for any \tcode{A} in the set of \tcode{OuterAlloc} and -\tcode{InnerAllocs...}; otherwise, \tcode{false_type}. -\end{itemdescr} - -\indexlibrarymember{propagate_on_container_swap}{scoped_allocator_adaptor}% -\begin{itemdecl} -using propagate_on_container_swap = @\seebelow@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ctype \tcode{true_type} if -\tcode{allocator_traits::propagate_on_container_swap::value} is -\tcode{true} for any \tcode{A} in the set of \tcode{OuterAlloc} and -\tcode{InnerAllocs...}; otherwise, \tcode{false_type}. -\end{itemdescr} - -\indexlibrarymember{is_always_equal}{scoped_allocator_adaptor}% -\begin{itemdecl} -using is_always_equal = @\seebelow@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ctype \tcode{true_type} if -\tcode{allocator_traits::is_always_equal::value} is -\tcode{true} for every \tcode{A} in the set of \tcode{OuterAlloc} and -\tcode{InnerAllocs...}; otherwise, \tcode{false_type}. -\end{itemdescr} - -\rSec2[allocator.adaptor.cnstr]{Constructors} - -\indexlibraryctor{scoped_allocator_adaptor}% -\begin{itemdecl} -scoped_allocator_adaptor(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Value-initializes the \tcode{OuterAlloc} base class and the \tcode{inner} allocator -object. -\end{itemdescr} - -\indexlibraryctor{scoped_allocator_adaptor}% -\begin{itemdecl} -template - scoped_allocator_adaptor(OuterA2&& outerAlloc, const InnerAllocs&... innerAllocs) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{is_constructible_v} is \tcode{true}. - -\pnum -\effects -Initializes the \tcode{OuterAlloc} base class with -\tcode{std::forward(outerAlloc)} and \tcode{inner} with \tcode{innerAllocs...} -(hence recursively initializing each allocator within the adaptor with the corresponding -allocator from the argument list). -\end{itemdescr} - -\indexlibraryctor{scoped_allocator_adaptor}% -\begin{itemdecl} -scoped_allocator_adaptor(const scoped_allocator_adaptor& other) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes each allocator within the adaptor with the corresponding allocator -from \tcode{other}. -\end{itemdescr} - -\indexlibraryctor{scoped_allocator_adaptor}% -\begin{itemdecl} -scoped_allocator_adaptor(scoped_allocator_adaptor&& other) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Move constructs each allocator within the adaptor with the corresponding allocator -from \tcode{other}. -\end{itemdescr} - -\indexlibraryctor{scoped_allocator_adaptor}% -\begin{itemdecl} -template - scoped_allocator_adaptor( - const scoped_allocator_adaptor& other) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{is_constructible_v} is \tcode{true}. - -\pnum -\effects -Initializes each allocator within the adaptor with the corresponding allocator -from \tcode{other}. -\end{itemdescr} - -\indexlibraryctor{scoped_allocator_adaptor}% -\begin{itemdecl} -template - scoped_allocator_adaptor(scoped_allocator_adaptor&& other) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{is_constructible_v} is \tcode{true}. - -\pnum -\effects -Initializes each allocator within the adaptor with the corresponding allocator rvalue -from \tcode{other}. -\end{itemdescr} - -\rSec2[allocator.adaptor.members]{Members} - -\pnum -In the \tcode{construct} member functions, -\tcode{\placeholdernc{OUTERMOST}(x)} is -\tcode{\placeholdernc{OUTERMOST}(x.outer_allocator())} if -the expression \tcode{x.outer_allocator()} is -valid~\iref{temp.deduct} and -\tcode{x} otherwise; -\tcode{\placeholdernc{OUTERMOST_ALLOC_TRAITS}(x)} is -\tcode{allocator_traits>}. -\begin{note} -\tcode{\placeholdernc{OUTERMOST}(x)} and -\tcode{\placeholdernc{OUTERMOST_ALL\-OC_TRAITS}(x)} are recursive operations. It -is incumbent upon the definition of \tcode{outer_allocator()} to ensure that the -recursion terminates. It will terminate for all instantiations of -\tcode{scoped_allocator_adaptor}. -\end{note} - -\indexlibrarymember{inner_allocator}{scoped_allocator_adaptor}% -\begin{itemdecl} -inner_allocator_type& inner_allocator() noexcept; -const inner_allocator_type& inner_allocator() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{*this} if \tcode{sizeof...(InnerAllocs)} is zero; otherwise, -\tcode{inner}. -\end{itemdescr} - -\indexlibrarymember{outer_allocator}{scoped_allocator_adaptor}% -\begin{itemdecl} -outer_allocator_type& outer_allocator() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{static_cast(*this)}. -\end{itemdescr} - -\indexlibrarymember{outer_allocator}{scoped_allocator_adaptor}% -\begin{itemdecl} -const outer_allocator_type& outer_allocator() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{static_cast(*this)}. -\end{itemdescr} - -\indexlibrarymember{allocate}{scoped_allocator_adaptor}% -\begin{itemdecl} -[[nodiscard]] pointer allocate(size_type n); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{allocator_traits::allocate(outer_allocator(), n)}. -\end{itemdescr} - -\indexlibrarymember{allocate}{scoped_allocator_adaptor}% -\begin{itemdecl} -[[nodiscard]] pointer allocate(size_type n, const_void_pointer hint); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{allocator_traits::allocate(outer_allocator(), n, hint)}. -\end{itemdescr} - -\indexlibrarymember{deallocate}{scoped_allocator_adaptor}% -\begin{itemdecl} -void deallocate(pointer p, size_type n) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -As if by: -\tcode{allocator_traits::deallocate(outer_allocator(), p, n);} -\end{itemdescr} - -\indexlibrarymember{max_size}{scoped_allocator_adaptor}% -\begin{itemdecl} -size_type max_size() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{allocator_traits::max_size(outer_allocator())}. -\end{itemdescr} - -\indexlibrarymember{construct}{scoped_allocator_adaptor}% -\begin{itemdecl} -template - void construct(T* p, Args&&... args); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -apply([p, this](auto&&... newargs) { - @\placeholdernc{OUTERMOST_ALLOC_TRAITS}@(*this)::construct( - @\placeholdernc{OUTERMOST}@(*this), p, - std::forward(newargs)...); - }, - uses_allocator_construction_args(inner_allocator(), - std::forward(args)...)); -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{destroy}{scoped_allocator_adaptor}% -\begin{itemdecl} -template - void destroy(T* p); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Calls \tcode{\placeholdernc{OUTERMOST_ALLOC_TRAITS}(*this)::destroy(\placeholdernc{OUTERMOST}(*this), p)}. -\end{itemdescr} - -\indexlibrarymember{select_on_container_copy_construction}{scoped_allocator_adaptor}% -\begin{itemdecl} -scoped_allocator_adaptor select_on_container_copy_construction() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A new \tcode{scoped_allocator_adaptor} object -where each allocator \tcode{a1} within the adaptor -is initialized with -\tcode{allocator_traits::select_on_container_copy_construction(a2)}, -where \tcode{A1} is the type of \tcode{a1} and -\tcode{a2} is the corresponding allocator in \tcode{*this}. -\end{itemdescr} - -\rSec2[scoped.adaptor.operators]{Operators} - -\indexlibrarymember{operator==}{scoped_allocator_adaptor}% -\begin{itemdecl} -template - bool operator==(const scoped_allocator_adaptor& a, - const scoped_allocator_adaptor& b) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -If \tcode{sizeof...(InnerAllocs)} is zero, -\begin{codeblock} -a.outer_allocator() == b.outer_allocator() -\end{codeblock} -otherwise -\begin{codeblock} -a.outer_allocator() == b.outer_allocator() && a.inner_allocator() == b.inner_allocator() -\end{codeblock} -\end{itemdescr} - -\rSec1[function.objects]{Function objects} - -\rSec2[function.objects.general]{General} - -\pnum -A \defnx{function object type}{function object!type} is an object -type\iref{term.object.type} that can be the type of the -\grammarterm{postfix-expression} -in a function call\iref{expr.call,over.match.call}. -\begin{footnote} -Such a type is a function -pointer or a class type which has a member \tcode{operator()} or a class type -which has a conversion to a pointer to function. -\end{footnote} -A \defn{function object} is an -object of a function object type. In the places where one would expect to pass a -pointer to a function to an algorithmic template\iref{algorithms}, the -interface is specified to accept a function object. This not only makes -algorithmic templates work with pointers to functions, but also enables them to -work with arbitrary function objects. - -\rSec2[functional.syn]{Header \tcode{} synopsis} - -\indexheader{functional}% -\indexlibraryglobal{unwrap_ref_decay}% -\indexlibraryglobal{unwrap_ref_decay_t}% -\begin{codeblock} -namespace std { - // \ref{func.invoke}, invoke - template - constexpr invoke_result_t invoke(F&& f, Args&&... args) - noexcept(is_nothrow_invocable_v); - - template - constexpr R invoke_r(F&& f, Args&&... args) - noexcept(is_nothrow_invocable_r_v); - - // \ref{refwrap}, \tcode{reference_wrapper} - template class reference_wrapper; - - template constexpr reference_wrapper ref(T&) noexcept; - template constexpr reference_wrapper cref(const T&) noexcept; - template void ref(const T&&) = delete; - template void cref(const T&&) = delete; - - template constexpr reference_wrapper ref(reference_wrapper) noexcept; - template constexpr reference_wrapper cref(reference_wrapper) noexcept; - - // \ref{arithmetic.operations}, arithmetic operations - template struct plus; - template struct minus; - template struct multiplies; - template struct divides; - template struct modulus; - template struct negate; - template<> struct plus; - template<> struct minus; - template<> struct multiplies; - template<> struct divides; - template<> struct modulus; - template<> struct negate; - - // \ref{comparisons}, comparisons - template struct equal_to; - template struct not_equal_to; - template struct greater; - template struct less; - template struct greater_equal; - template struct less_equal; - template<> struct equal_to; - template<> struct not_equal_to; - template<> struct greater; - template<> struct less; - template<> struct greater_equal; - template<> struct less_equal; - - // \ref{comparisons.three.way}, class \tcode{compare_three_way} - struct compare_three_way; - - // \ref{logical.operations}, logical operations - template struct logical_and; - template struct logical_or; - template struct logical_not; - template<> struct logical_and; - template<> struct logical_or; - template<> struct logical_not; - - // \ref{bitwise.operations}, bitwise operations - template struct bit_and; - template struct bit_or; - template struct bit_xor; - template struct bit_not; - template<> struct bit_and; - template<> struct bit_or; - template<> struct bit_xor; - template<> struct bit_not; - - // \ref{func.identity}, identity - struct identity; - - // \ref{func.not.fn}, function template \tcode{not_fn} - template constexpr @\unspec@ not_fn(F&& f); - - // \ref{func.bind.partial}, function templates \tcode{bind_front} and \tcode{bind_back} - template constexpr @\unspec@ bind_front(F&&, Args&&...); - template constexpr @\unspec@ bind_back(F&&, Args&&...); - - // \ref{func.bind}, bind - template struct is_bind_expression; - template - inline constexpr bool @\libglobal{is_bind_expression_v}@ = is_bind_expression::value; - template struct is_placeholder; - template - inline constexpr int @\libglobal{is_placeholder_v}@ = is_placeholder::value; - - template - constexpr @\unspec@ bind(F&&, BoundArgs&&...); - template - constexpr @\unspec@ bind(F&&, BoundArgs&&...); - - namespace placeholders { - // \tcode{\placeholder{M}} is the \impldef{number of placeholders for bind expressions} number of placeholders - @\seebelownc@ _1; - @\seebelownc@ _2; - . - . - . - @\seebelownc@ _@\placeholdernc{M}@; - } - - // \ref{func.memfn}, member function adaptors - template - constexpr @\unspec@ mem_fn(R T::*) noexcept; - - // \ref{func.wrap}, polymorphic function wrappers - class bad_function_call; - - template class function; // \notdef - template class function; - - // \ref{func.wrap.func.alg}, specialized algorithms - template - void swap(function&, function&) noexcept; - - // \ref{func.wrap.func.nullptr}, null pointer comparison operator functions - template - bool operator==(const function&, nullptr_t) noexcept; - - // \ref{func.wrap.move}, move only wrapper - template class move_only_function; // \notdef - template - class move_only_function; // \seebelow - - // \ref{func.search}, searchers - template> - class default_searcher; - - template::value_type>, - class BinaryPredicate = equal_to<>> - class boyer_moore_searcher; - - template::value_type>, - class BinaryPredicate = equal_to<>> - class boyer_moore_horspool_searcher; - - // \ref{unord.hash}, class template hash - template - struct hash; - - namespace ranges { - // \ref{range.cmp}, concept-constrained comparisons - struct equal_to; - struct not_equal_to; - struct greater; - struct less; - struct greater_equal; - struct less_equal; - } -} -\end{codeblock} - -\pnum -\begin{example} -If a \Cpp{} program wants to have a by-element addition of two vectors \tcode{a} -and \tcode{b} containing \tcode{double} and put the result into \tcode{a}, -it can do: - -\begin{codeblock} -transform(a.begin(), a.end(), b.begin(), a.begin(), plus()); -\end{codeblock} -\end{example} - -\pnum -\begin{example} -To negate every element of \tcode{a}: - -\begin{codeblock} -transform(a.begin(), a.end(), a.begin(), negate()); -\end{codeblock} - -\end{example} - -\rSec2[func.def]{Definitions} - -\pnum -The following definitions apply to this Clause: - -\pnum -A \defn{call signature} is the name of a return type followed by a -parenthesized comma-separated list of zero or more argument types. - -\pnum -A \defnadj{callable}{type} is a function object type\iref{function.objects} or a pointer to member. - -\pnum -A \defnadj{callable}{object} is an object of a callable type. - -\pnum -A \defnx{call wrapper type}{call wrapper!type} is a type that holds a callable object -and supports a call operation that forwards to that object. - -\pnum -A \defn{call wrapper} is an object of a call wrapper type. - -\pnum -A \defn{target object} is the callable object held by a call wrapper. - -\pnum -A call wrapper type may additionally hold -a sequence of objects and references -that may be passed as arguments to the target object. -These entities are collectively referred to -as \defnx{bound argument entities}{bound argument entity}. - -\pnum -The target object and bound argument entities of the call wrapper are -collectively referred to as \defnx{state entities}{state entity}. - -\rSec2[func.require]{Requirements} - -\pnum -\indexlibrary{invoke@\tcode{\placeholder{INVOKE}}}% -Define \tcode{\placeholdernc{INVOKE}(f, t$_1$, t$_2$, $\dotsc$, t$_N$)} as follows: -\begin{itemize} -\item \tcode{(t$_1$.*f)(t$_2$, $\dotsc$, t$_N$)} when \tcode{f} is a pointer to a -member function of a class \tcode{T} -and \tcode{is_base_of_v>} is \tcode{true}; - -\item \tcode{(t$_1$.get().*f)(t$_2$, $\dotsc$, t$_N$)} when \tcode{f} is a pointer to a -member function of a class \tcode{T} -and \tcode{remove_cvref_t} is a specialization of \tcode{reference_wrapper}; - -\item \tcode{((*t$_1$).*f)(t$_2$, $\dotsc$, t$_N$)} when \tcode{f} is a pointer to a -member function of a class \tcode{T} -and \tcode{t$_1$} does not satisfy the previous two items; - -\item \tcode{t$_1$.*f} when \tcode{N == 1} and \tcode{f} is a pointer to -data member of a class \tcode{T} -and \tcode{is_base_of_v>} is \tcode{true}; - -\item \tcode{t$_1$.get().*f} when \tcode{N == 1} and \tcode{f} is a pointer to -data member of a class \tcode{T} -and \tcode{remove_cvref_t} is a specialization of \tcode{reference_wrapper}; - -\item \tcode{(*t$_1$).*f} when \tcode{N == 1} and \tcode{f} is a pointer to -data member of a class \tcode{T} -and \tcode{t$_1$} does not satisfy the previous two items; - -\item \tcode{f(t$_1$, t$_2$, $\dotsc$, t$_N$)} in all other cases. -\end{itemize} - -\pnum -\indexlibrary{invoke@\tcode{\placeholder{INVOKE}}}% -Define \tcode{\placeholdernc{INVOKE}(f, t$_1$, t$_2$, $\dotsc$, t$_N$)} as -\tcode{static_cast(\placeholdernc{INVOKE}(f, t$_1$, t$_2$, $\dotsc$, t$_N$))} -if \tcode{R} is \cv{}~\keyword{void}, otherwise -\tcode{\placeholdernc{INVOKE}(f, t$_1$, t$_2$, $\dotsc$, t$_N$)} implicitly converted -to \tcode{R}. -If -\tcode{reference_converts_from_temporary_v} -is \tcode{true}, -\tcode{\placeholdernc{INVOKE}(f, t$_1$, t$_2$, $\dotsc$, t$_N$)} -is ill-formed. - -\pnum -\indextext{call wrapper}% -\indextext{call wrapper!simple}% -\indextext{call wrapper!forwarding}% -Every call wrapper\iref{func.def} meets the \oldconcept{MoveConstructible} -and \oldconcept{Destructible} requirements. -An \defn{argument forwarding call wrapper} is a -call wrapper that can be called with an arbitrary argument list -and delivers the arguments to the target object as references. -This forwarding step delivers rvalue arguments as rvalue references -and lvalue arguments as lvalue references. -\begin{note} -In a typical implementation, argument forwarding call wrappers have -an overloaded function call operator of the form -\begin{codeblock} -template - constexpr R operator()(UnBoundArgs&&... unbound_args) @\textit{cv-qual}@; -\end{codeblock} -\end{note} - -\pnum -\label{term.perfect.forwarding.call.wrapper}% -A \defnadj{perfect forwarding}{call wrapper} is -an argument forwarding call wrapper -that forwards its state entities to the underlying call expression. -This forwarding step delivers a state entity of type \tcode{T} -as \cv{} \tcode{T\&} -when the call is performed on an lvalue of the call wrapper type and -as \cv{} \tcode{T\&\&} otherwise, -where \cv{} represents the cv-qualifiers of the call wrapper and -where \cv{} shall be neither \tcode{volatile} nor \tcode{const volatile}. - -\pnum -A \defn{call pattern} defines the semantics of invoking -a perfect forwarding call wrapper. -A postfix call performed on a perfect forwarding call wrapper is -expression-equivalent\iref{defns.expression.equivalent} to -an expression \tcode{e} determined from its call pattern \tcode{cp} -by replacing all occurrences -of the arguments of the call wrapper and its state entities -with references as described in the corresponding forwarding steps. - -\pnum -\label{term.simple.call.wrapper}% -A \defn{simple call wrapper} is a perfect forwarding call wrapper that meets -the \oldconcept{CopyConstructible} and \oldconcept{CopyAssignable} requirements -and whose copy constructor, move constructor, and assignment operators -are constexpr functions that do not throw exceptions. - -\pnum -The copy/move constructor of an argument forwarding call wrapper has -the same apparent semantics -as if memberwise copy/move of its state entities -were performed\iref{class.copy.ctor}. -\begin{note} -This implies that each of the copy/move constructors has -the same exception-specification as -the corresponding implicit definition and is declared as \keyword{constexpr} -if the corresponding implicit definition would be considered to be constexpr. -\end{note} - -\pnum -Argument forwarding call wrappers returned by -a given standard library function template have the same type -if the types of their corresponding state entities are the same. - -\rSec2[func.invoke]{\tcode{invoke} functions} -\indexlibraryglobal{invoke}% -\indexlibrary{invoke@\tcode{\placeholder{INVOKE}}}% -\begin{itemdecl} -template - constexpr invoke_result_t invoke(F&& f, Args&&... args) - noexcept(is_nothrow_invocable_v); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{is_invocable_v} is \tcode{true}. - -\pnum -\returns -\tcode{\placeholdernc{INVOKE}(std::forward(f), std::forward(args)...)}\iref{func.require}. -\end{itemdescr} - -\indexlibraryglobal{invoke_r}% -\begin{itemdecl} -template - constexpr R invoke_r(F&& f, Args&&... args) - noexcept(is_nothrow_invocable_r_v); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{is_invocable_r_v} is \tcode{true}. - -\pnum -\returns -\tcode{\placeholdernc{INVOKE}(std::forward(f), std::forward(args)...)}\iref{func.require}. -\end{itemdescr} - -\rSec2[refwrap]{Class template \tcode{reference_wrapper}} - -\rSec3[refwrap.general]{General} - -\indexlibraryglobal{reference_wrapper}% -\indextext{function object!\idxcode{reference_wrapper}}% -\begin{codeblock} -namespace std { - template class reference_wrapper { - public: - // types - using type = T; - - // \ref{refwrap.const}, constructors - template - constexpr reference_wrapper(U&&) noexcept(@\seebelow@); - constexpr reference_wrapper(const reference_wrapper& x) noexcept; - - // \ref{refwrap.assign}, assignment - constexpr reference_wrapper& operator=(const reference_wrapper& x) noexcept; - - // \ref{refwrap.access}, access - constexpr operator T& () const noexcept; - constexpr T& get() const noexcept; - - // \ref{refwrap.invoke}, invocation - template - constexpr invoke_result_t operator()(ArgTypes&&...) const; - }; - - template - reference_wrapper(T&) -> reference_wrapper; -} -\end{codeblock} - -\pnum -\tcode{reference_wrapper} is a \oldconcept{CopyConstructible} and \oldconcept{CopyAssignable} wrapper -around a reference to an object or function of type \tcode{T}. - -\pnum -\tcode{reference_wrapper} is -a trivially copyable type\iref{term.trivially.copyable.type}. - -\pnum -The template parameter \tcode{T} of \tcode{reference_wrapper} -may be an incomplete type. - -\rSec3[refwrap.const]{Constructors} - -\indexlibraryctor{reference_wrapper}% -\begin{itemdecl} -template - constexpr reference_wrapper(U&& u) noexcept(@\seebelow@); -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{\placeholdernc{FUN}} denote the exposition-only functions -\begin{codeblock} -void @\placeholdernc{FUN}@(T&) noexcept; -void @\placeholdernc{FUN}@(T&&) = delete; -\end{codeblock} - -\pnum -\constraints -The expression \tcode{\placeholdernc{FUN}(declval())} is well-formed and -\tcode{is_same_v, reference_wrapper>} is \tcode{false}. - -\pnum -\effects -Creates a variable \tcode{r} -as if by \tcode{T\& r = std::forward(u)}, -then constructs a \tcode{reference_wrapper} object -that stores a reference to \tcode{r}. - -\pnum -\remarks -The exception specification is equivalent to -\tcode{noexcept(\placeholdernc{FUN}(declval()))}. -\end{itemdescr} - -\indexlibraryctor{reference_wrapper}% -\begin{itemdecl} -constexpr reference_wrapper(const reference_wrapper& x) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Constructs a \tcode{reference_wrapper} object that -stores a reference to \tcode{x.get()}. -\end{itemdescr} - -\rSec3[refwrap.assign]{Assignment} - -\indexlibrarymember{operator=}{reference_wrapper}% -\begin{itemdecl} -constexpr reference_wrapper& operator=(const reference_wrapper& x) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -\tcode{*this} stores a reference to \tcode{x.get()}. -\end{itemdescr} - -\rSec3[refwrap.access]{Access} - -\indexlibrarymember{operator T\&}{reference_wrapper}% -\begin{itemdecl} -constexpr operator T& () const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The stored reference. -\end{itemdescr} - -\indexlibrarymember{get}{reference_wrapper}% -\begin{itemdecl} -constexpr T& get() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The stored reference. -\end{itemdescr} - -\rSec3[refwrap.invoke]{Invocation} - -\indexlibrarymember{operator()}{reference_wrapper}% -\begin{itemdecl} -template - constexpr invoke_result_t - operator()(ArgTypes&&... args) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\mandates -\tcode{T} is a complete type. - -\pnum -\returns -\tcode{\placeholdernc{INVOKE}(get(), std::forward(args)...)}.\iref{func.require} -\end{itemdescr} - - -\rSec3[refwrap.helpers]{Helper functions} - -\pnum -The template parameter \tcode{T} of -the following \tcode{ref} and \tcode{cref} function templates -may be an incomplete type. - -\indexlibrarymember{ref}{reference_wrapper}% -\begin{itemdecl} -template constexpr reference_wrapper ref(T& t) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{reference_wrapper(t)}. -\end{itemdescr} - -\indexlibrarymember{ref}{reference_wrapper}% -\begin{itemdecl} -template constexpr reference_wrapper ref(reference_wrapper t) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{t}. -\end{itemdescr} - -\indexlibrarymember{cref}{reference_wrapper}% -\begin{itemdecl} -template constexpr reference_wrapper cref(const T& t) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{reference_wrapper (t)}. -\end{itemdescr} - -\indexlibrarymember{cref}{reference_wrapper}% -\begin{itemdecl} -template constexpr reference_wrapper cref(reference_wrapper t) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{t}. -\end{itemdescr} - -\rSec2[arithmetic.operations]{Arithmetic operations} - -\rSec3[arithmetic.operations.general]{General} - -\pnum -The library provides basic function object classes for all of the arithmetic -operators in the language\iref{expr.mul,expr.add}. - -\rSec3[arithmetic.operations.plus]{Class template \tcode{plus}} - -\indexlibraryglobal{plus}% -\begin{itemdecl} -template struct plus { - constexpr T operator()(const T& x, const T& y) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{plus}% -\begin{itemdecl} -constexpr T operator()(const T& x, const T& y) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x + y}. -\end{itemdescr} - -\indexlibraryglobal{plus<>}% -\begin{itemdecl} -template<> struct plus { - template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) + std::forward(u)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{plus<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) + std::forward(u)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{std::forward(t) + std::forward(u)}. -\end{itemdescr} - -\rSec3[arithmetic.operations.minus]{Class template \tcode{minus}} - -\indexlibraryglobal{minus}% -\begin{itemdecl} -template struct minus { - constexpr T operator()(const T& x, const T& y) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{minus}% -\begin{itemdecl} -constexpr T operator()(const T& x, const T& y) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x - y}. -\end{itemdescr} - -\indexlibraryglobal{minus<>}% -\begin{itemdecl} -template<> struct minus { - template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) - std::forward(u)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{minus<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) - std::forward(u)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{std::forward(t) - std::forward(u)}. -\end{itemdescr} - -\rSec3[arithmetic.operations.multiplies]{Class template \tcode{multiplies}} - -\indexlibraryglobal{multiplies}% -\begin{itemdecl} -template struct multiplies { - constexpr T operator()(const T& x, const T& y) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{multiplies}% -\begin{itemdecl} -constexpr T operator()(const T& x, const T& y) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x * y}. -\end{itemdescr} - -\indexlibraryglobal{multiplies<>}% -\begin{itemdecl} -template<> struct multiplies { - template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) * std::forward(u)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{multiplies<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) * std::forward(u)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{std::forward(t) * std::forward(u)}. -\end{itemdescr} - -\rSec3[arithmetic.operations.divides]{Class template \tcode{divides}} - -\indexlibraryglobal{divides}% -\begin{itemdecl} -template struct divides { - constexpr T operator()(const T& x, const T& y) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{divides}% -\begin{itemdecl} -constexpr T operator()(const T& x, const T& y) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x / y}. -\end{itemdescr} - -\indexlibraryglobal{divides<>}% -\begin{itemdecl} -template<> struct divides { - template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) / std::forward(u)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{divides<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) / std::forward(u)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{std::forward(t) / std::forward(u)}. -\end{itemdescr} - -\rSec3[arithmetic.operations.modulus]{Class template \tcode{modulus}} - -\indexlibraryglobal{modulus}% -\begin{itemdecl} -template struct modulus { - constexpr T operator()(const T& x, const T& y) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{modulus}% -\begin{itemdecl} -constexpr T operator()(const T& x, const T& y) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x \% y}. -\end{itemdescr} - -\indexlibraryglobal{modulus<>}% -\begin{itemdecl} -template<> struct modulus { - template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) % std::forward(u)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{modulus<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) % std::forward(u)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{std::forward(t) \% std::forward(u)}. -\end{itemdescr} - -\rSec3[arithmetic.operations.negate]{Class template \tcode{negate}} - -\indexlibraryglobal{negate}% -\begin{itemdecl} -template struct negate { - constexpr T operator()(const T& x) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{negate}% -\begin{itemdecl} -constexpr T operator()(const T& x) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{-x}. -\end{itemdescr} - -\indexlibraryglobal{negate<>}% -\begin{itemdecl} -template<> struct negate { - template constexpr auto operator()(T&& t) const - -> decltype(-std::forward(t)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{negate<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t) const - -> decltype(-std::forward(t)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{-std::forward(t)}. -\end{itemdescr} - - -\rSec2[comparisons]{Comparisons} - -\rSec3[comparisons.general]{General} - -\pnum -The library provides basic function object classes for all of the comparison -operators in the language\iref{expr.rel,expr.eq}. - -\pnum -For templates \tcode{less}, \tcode{greater}, \tcode{less_equal}, and -\tcode{greater_equal}, the specializations for any pointer type -yield a result consistent with the -implementation-defined strict total order over pointers\iref{defns.order.ptr}. -\begin{note} -If \tcode{a < b} is well-defined -for pointers \tcode{a} and \tcode{b} of type \tcode{P}, -then \tcode{(a < b) == less

()(a, b)}, -\tcode{(a > b) == greater

()(a, b)}, and so forth. -\end{note} -For template specializations \tcode{less}, \tcode{greater}, -\tcode{less_equal}, and \tcode{greater_equal}, -if the call operator calls a built-in operator comparing pointers, -the call operator yields a result consistent -with the implementation-defined strict total order over pointers. - -\rSec3[comparisons.equal.to]{Class template \tcode{equal_to}} - -\indexlibraryglobal{equal_to}% -\begin{itemdecl} -template struct equal_to { - constexpr bool operator()(const T& x, const T& y) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{equal_to}% -\begin{itemdecl} -constexpr bool operator()(const T& x, const T& y) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x == y}. -\end{itemdescr} - -\indexlibraryglobal{equal_to<>}% -\begin{itemdecl} -template<> struct equal_to { - template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) == std::forward(u)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{equal_to<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) == std::forward(u)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{std::forward(t) == std::forward(u)}. -\end{itemdescr} - -\rSec3[comparisons.not.equal.to]{Class template \tcode{not_equal_to}} - -\indexlibraryglobal{not_equal_to}% -\begin{itemdecl} -template struct not_equal_to { - constexpr bool operator()(const T& x, const T& y) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{not_equal_to}% -\begin{itemdecl} -constexpr bool operator()(const T& x, const T& y) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x != y}. -\end{itemdescr} - -\indexlibraryglobal{not_equal_to<>}% -\begin{itemdecl} -template<> struct not_equal_to { - template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) != std::forward(u)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{not_equal_to<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) != std::forward(u)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{std::forward(t) != std::forward(u)}. -\end{itemdescr} - -\rSec3[comparisons.greater]{Class template \tcode{greater}} - -\indexlibraryglobal{greater}% -\begin{itemdecl} -template struct greater { - constexpr bool operator()(const T& x, const T& y) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{greater}% -\begin{itemdecl} -constexpr bool operator()(const T& x, const T& y) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x > y}. -\end{itemdescr} - -\indexlibraryglobal{greater<>}% -\begin{itemdecl} -template<> struct greater { - template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) > std::forward(u)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{greater<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) > std::forward(u)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{std::forward(t) > std::forward(u)}. -\end{itemdescr} - -\rSec3[comparisons.less]{Class template \tcode{less}} - -\indexlibraryglobal{less}% -\begin{itemdecl} -template struct less { - constexpr bool operator()(const T& x, const T& y) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{less}% -\begin{itemdecl} -constexpr bool operator()(const T& x, const T& y) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x < y}. -\end{itemdescr} - -\indexlibraryglobal{less<>}% -\begin{itemdecl} -template<> struct less { - template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) < std::forward(u)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{less<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) < std::forward(u)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{std::forward(t) < std::forward(u)}. -\end{itemdescr} - -\rSec3[comparisons.greater.equal]{Class template \tcode{greater_equal}} - -\indexlibraryglobal{greater_equal}% -\begin{itemdecl} -template struct greater_equal { - constexpr bool operator()(const T& x, const T& y) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{greater_equal}% -\begin{itemdecl} -constexpr bool operator()(const T& x, const T& y) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x >= y}. -\end{itemdescr} - -\indexlibraryglobal{greater_equal<>}% -\begin{itemdecl} -template<> struct greater_equal { - template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) >= std::forward(u)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{greater_equal<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) >= std::forward(u)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{std::forward(t) >= std::forward(u)}. -\end{itemdescr} - -\rSec3[comparisons.less.equal]{Class template \tcode{less_equal}} - -\indexlibraryglobal{less_equal}% -\begin{itemdecl} -template struct less_equal { - constexpr bool operator()(const T& x, const T& y) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{less_equal}% -\begin{itemdecl} -constexpr bool operator()(const T& x, const T& y) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x <= y}. -\end{itemdescr} - -\indexlibraryglobal{less_equal<>}% -\begin{itemdecl} -template<> struct less_equal { - template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) <= std::forward(u)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{less_equal<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) <= std::forward(u)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{std::forward(t) <= std::forward(u)}. -\end{itemdescr} - -\rSec3[comparisons.three.way]{Class \tcode{compare_three_way}} - -\indexlibraryglobal{compare_three_way}% -\begin{codeblock} -struct compare_three_way { - template - constexpr auto operator()(T&& t, U&& u) const; - - using is_transparent = @\unspec@; -}; -\end{codeblock} - -\begin{itemdecl} -template - constexpr auto operator()(T&& t, U&& u) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{T} and \tcode{U} satisfy \libconcept{three_way_comparable_with}. - -\pnum -\expects -If the expression \tcode{std::forward(t) <=> std::forward(u)} results in -a call to a built-in operator \tcode{<=>} comparing pointers of type \tcode{P}, -the conversion sequences from both \tcode{T} and \tcode{U} to \tcode{P} -are equality-preserving\iref{concepts.equality}; -otherwise, \tcode{T} and \tcode{U} model \libconcept{three_way_comparable_with}. - -\pnum -\effects -\begin{itemize} -\item - If the expression \tcode{std::forward(t) <=> std::forward(u)} results in - a call to a built-in operator \tcode{<=>} comparing pointers of type \tcode{P}, - returns \tcode{strong_ordering::less} - if (the converted value of) \tcode{t} precedes \tcode{u} - in the implementation-defined strict total order - over pointers\iref{defns.order.ptr}, - \tcode{strong_ordering::greater} - if \tcode{u} precedes \tcode{t}, and - otherwise \tcode{strong_ordering::equal}. -\item - Otherwise, equivalent to: \tcode{return std::forward(t) <=> std::forward(u);} -\end{itemize} -\end{itemdescr} - -\rSec2[range.cmp]{Concept-constrained comparisons} - -\indexlibraryglobal{equal_to}% -\begin{codeblock} -struct ranges::equal_to { - template - constexpr bool operator()(T&& t, U&& u) const; - - using is_transparent = @\unspecnc@; -}; -\end{codeblock} - -\begin{itemdecl} -template - constexpr bool operator()(T&& t, U&& u) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{T} and \tcode{U} satisfy \libconcept{equality_comparable_with}. - -\pnum -\expects -If the expression \tcode{std::forward(t) == std::forward(u)} -results in a call to a built-in operator \tcode{==} comparing pointers of type -\tcode{P}, the conversion sequences from both \tcode{T} and \tcode{U} to \tcode{P} -are equality-preserving\iref{concepts.equality}; -otherwise, \tcode{T} and \tcode{U} model \libconcept{equality_comparable_with}. - -\pnum -\effects -\begin{itemize} -\item - If the expression \tcode{std::forward(t) == std::forward(u)} results in - a call to a built-in operator \tcode{==} comparing pointers: - returns \tcode{false} if either (the converted value of) \tcode{t} precedes - \tcode{u} or \tcode{u} precedes \tcode{t} in the implementation-defined strict - total order over pointers\iref{defns.order.ptr} and otherwise \tcode{true}. - -\item - Otherwise, equivalent to: - \tcode{return std::forward(t) == std::forward(u);} -\end{itemize} -\end{itemdescr} - -\indexlibraryglobal{not_equal_to}% -\begin{codeblock} -struct ranges::not_equal_to { - template - constexpr bool operator()(T&& t, U&& u) const; - - using is_transparent = @\unspecnc@; -}; -\end{codeblock} - -\begin{itemdecl} -template - constexpr bool operator()(T&& t, U&& u) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{T} and \tcode{U} satisfy \libconcept{equality_comparable_with}. - -\pnum -\effects -Equivalent to: -\begin{codeblock} -return !ranges::equal_to{}(std::forward(t), std::forward(u)); -\end{codeblock} -\end{itemdescr} - -\indexlibraryglobal{greater}% -\begin{codeblock} -struct ranges::greater { - template - constexpr bool operator()(T&& t, U&& u) const; - - using is_transparent = @\unspecnc@; -}; -\end{codeblock} - -\begin{itemdecl} -template - constexpr bool operator()(T&& t, U&& u) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{T} and \tcode{U} satisfy \libconcept{totally_ordered_with}. - -\pnum -\effects -Equivalent to: -\begin{codeblock} -return ranges::less{}(std::forward(u), std::forward(t)); -\end{codeblock} -\end{itemdescr} - -\indexlibraryglobal{less}% -\begin{codeblock} -struct ranges::less { - template - constexpr bool operator()(T&& t, U&& u) const; - - using is_transparent = @\unspecnc@; -}; -\end{codeblock} - -\begin{itemdecl} -template - constexpr bool operator()(T&& t, U&& u) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{T} and \tcode{U} satisfy \libconcept{totally_ordered_with}. - -\pnum -\expects -If the expression \tcode{std::forward(t) < std::forward(u)} results in a -call to a built-in operator \tcode{<} comparing pointers of type \tcode{P}, the -conversion sequences from both \tcode{T} and \tcode{U} to \tcode{P} are -equality-preserving\iref{concepts.equality}; -otherwise, \tcode{T} and \tcode{U} model \libconcept{totally_ordered_with}. -For any expressions -\tcode{ET} and \tcode{EU} such that \tcode{decltype((ET))} is \tcode{T} and -\tcode{decltype((EU))} is \tcode{U}, exactly one of -\tcode{ranges::less\{\}(ET, EU)}, -\tcode{ranges::less\{\}(EU, ET)}, or -\tcode{ranges::equal_to\{\}(ET, EU)} -is \tcode{true}. - -\pnum -\effects -\begin{itemize} -\item -If the expression \tcode{std::forward(t) < std::forward(u)} results in a -call to a built-in operator \tcode{<} comparing pointers: -returns \tcode{true} if (the converted value of) \tcode{t} precedes \tcode{u} in -the implementation-defined strict total order over pointers\iref{defns.order.ptr} -and otherwise \tcode{false}. - -\item -Otherwise, equivalent to: -\tcode{return std::forward(t) < std::forward(u);} -\end{itemize} -\end{itemdescr} - -\indexlibraryglobal{greater_equal}% -\begin{codeblock} -struct ranges::greater_equal { - template - constexpr bool operator()(T&& t, U&& u) const; - - using is_transparent = @\unspecnc@; -}; -\end{codeblock} - -\begin{itemdecl} -template - constexpr bool operator()(T&& t, U&& u) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{T} and \tcode{U} satisfy \libconcept{totally_ordered_with}. - -\pnum -\effects -Equivalent to: -\begin{codeblock} -return !ranges::less{}(std::forward(t), std::forward(u)); -\end{codeblock} -\end{itemdescr} - -\indexlibraryglobal{less_equal}% -\begin{itemdecl} -struct ranges::less_equal { - template - constexpr bool operator()(T&& t, U&& u) const; - - using is_transparent = @\unspecnc@; -}; -\end{itemdecl} - -\begin{itemdecl} -template - constexpr bool operator()(T&& t, U&& u) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{T} and \tcode{U} satisfy \libconcept{totally_ordered_with}. - -\pnum -\effects -Equivalent to: -\begin{codeblock} -return !ranges::less{}(std::forward(u), std::forward(t)); -\end{codeblock} -\end{itemdescr} - -\rSec2[logical.operations]{Logical operations} - -\rSec3[logical.operations.general]{General} - -\pnum -The library provides basic function object classes for all of the logical -operators in the language\iref{expr.log.and,expr.log.or,expr.unary.op}. - -\rSec3[logical.operations.and]{Class template \tcode{logical_and}} - -\indexlibraryglobal{logical_and}% -\begin{itemdecl} -template struct logical_and { - constexpr bool operator()(const T& x, const T& y) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{logical_and}% -\begin{itemdecl} -constexpr bool operator()(const T& x, const T& y) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x \&\& y}. -\end{itemdescr} - -\indexlibraryglobal{logical_and<>}% -\begin{itemdecl} -template<> struct logical_and { - template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) && std::forward(u)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{logical_and<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) && std::forward(u)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{std::forward(t) \&\& std::forward(u)}. -\end{itemdescr} - -\rSec3[logical.operations.or]{Class template \tcode{logical_or}} - -\indexlibraryglobal{logical_or}% -\begin{itemdecl} -template struct logical_or { - constexpr bool operator()(const T& x, const T& y) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{logical_or}% -\begin{itemdecl} -constexpr bool operator()(const T& x, const T& y) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x || y}. -\end{itemdescr} - -\indexlibraryglobal{logical_or<>}% -\begin{itemdecl} -template<> struct logical_or { - template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) || std::forward(u)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{logical_or<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) || std::forward(u)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{std::forward(t) || std::forward(u)}. -\end{itemdescr} - -\rSec3[logical.operations.not]{Class template \tcode{logical_not}} - -\indexlibraryglobal{logical_not}% -\begin{itemdecl} -template struct logical_not { - constexpr bool operator()(const T& x) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{logical_not}% -\begin{itemdecl} -constexpr bool operator()(const T& x) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{!x}. -\end{itemdescr} - -\indexlibraryglobal{logical_not<>}% -\begin{itemdecl} -template<> struct logical_not { - template constexpr auto operator()(T&& t) const - -> decltype(!std::forward(t)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{logical_not<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t) const - -> decltype(!std::forward(t)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{!std::forward(t)}. -\end{itemdescr} - - -\rSec2[bitwise.operations]{Bitwise operations} - -\rSec3[bitwise.operations.general]{General} - -\pnum -The library provides basic function object classes for all of the bitwise -operators in the language\iref{expr.bit.and,expr.or,expr.xor,expr.unary.op}. - -\rSec3[bitwise.operations.and]{Class template \tcode{bit_and}} - -\indexlibraryglobal{bit_and}% -\begin{itemdecl} -template struct bit_and { - constexpr T operator()(const T& x, const T& y) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{bit_and}% -\begin{itemdecl} -constexpr T operator()(const T& x, const T& y) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x \& y}. -\end{itemdescr} - -\indexlibraryglobal{bit_and<>}% -\begin{itemdecl} -template<> struct bit_and { - template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) & std::forward(u)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{bit_and<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) & std::forward(u)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{std::forward(t) \& std::forward(u)}. -\end{itemdescr} - -\rSec3[bitwise.operations.or]{Class template \tcode{bit_or}} - -\indexlibraryglobal{bit_or}% -\begin{itemdecl} -template struct bit_or { - constexpr T operator()(const T& x, const T& y) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{bit_or}% -\begin{itemdecl} -constexpr T operator()(const T& x, const T& y) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x | y}. -\end{itemdescr} - -\indexlibraryglobal{bit_or<>}% -\begin{itemdecl} -template<> struct bit_or { - template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) | std::forward(u)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{bit_or<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) | std::forward(u)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{std::forward(t) | std::forward(u)}. -\end{itemdescr} - -\rSec3[bitwise.operations.xor]{Class template \tcode{bit_xor}} - -\indexlibraryglobal{bit_xor}% -\begin{itemdecl} -template struct bit_xor { - constexpr T operator()(const T& x, const T& y) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{bit_xor}% -\begin{itemdecl} -constexpr T operator()(const T& x, const T& y) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x \caret{} y}. -\end{itemdescr} - -\indexlibraryglobal{bit_xor<>}% -\begin{itemdecl} -template<> struct bit_xor { - template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) ^ std::forward(u)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{bit_xor<>}% -\begin{itemdecl} -template constexpr auto operator()(T&& t, U&& u) const - -> decltype(std::forward(t) ^ std::forward(u)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{std::forward(t) \caret{} std::forward(u)}. -\end{itemdescr} - -\rSec3[bitwise.operations.not]{Class template \tcode{bit_not}} - -\begin{itemdecl} -template struct bit_not { - constexpr T operator()(const T& x) const; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{bit_not}% -\begin{itemdecl} -constexpr T operator()(const T& x) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{\~{}x}. -\end{itemdescr} - -\indexlibraryglobal{bit_not<>}% -\begin{itemdecl} -template<> struct bit_not { - template constexpr auto operator()(T&& t) const - -> decltype(~std::forward(t)); - - using is_transparent = @\unspec@; -}; -\end{itemdecl} - -\indexlibrarymember{operator()}{bit_not<>}% -\begin{itemdecl} -template constexpr auto operator()(T&&) const - -> decltype(~std::forward(t)); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{\~{}std::forward(t)}. -\end{itemdescr} - - -\rSec2[func.identity]{Class \tcode{identity}} - -\indexlibraryglobal{identity}% -\begin{itemdecl} -struct identity { - template - constexpr T&& operator()(T&& t) const noexcept; - - using is_transparent = @\unspec@; -}; - -template - constexpr T&& operator()(T&& t) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return std::forward(t);} -\end{itemdescr} - - -\rSec2[func.not.fn]{Function template \tcode{not_fn}} - -\indexlibraryglobal{not_fn}% -\begin{itemdecl} -template constexpr @\unspec@ not_fn(F&& f); -\end{itemdecl} - -\begin{itemdescr} -\pnum -In the text that follows: -\begin{itemize} -\item \tcode{g} is a value of the result of a \tcode{not_fn} invocation, -\item \tcode{FD} is the type \tcode{decay_t}, -\item \tcode{fd} is the target object of \tcode{g}\iref{func.def} - of type \tcode{FD}, - direct-non-list-initialized with \tcode{std::forward(f)}, -\item \tcode{call_args} is an argument pack - used in a function call expression\iref{expr.call} of \tcode{g}. -\end{itemize} - -\pnum -\mandates -\tcode{is_constructible_v \&\& is_move_constructible_v} -is \tcode{true}. - -\pnum -\expects -\tcode{FD} meets the \oldconcept{MoveConstructible} requirements. - -\pnum -\returns -A perfect forwarding call wrapper\iref{term.perfect.forwarding.call.wrapper} \tcode{g} -with call pattern \tcode{!invoke(fd, call_args...)}. - -\pnum -\throws -Any exception thrown by the initialization of \tcode{fd}. -\end{itemdescr} - -\rSec2[func.bind.partial]{Function templates \tcode{bind_front} and \tcode{bind_back}} - -\indexlibraryglobal{bind_front}% -\indexlibraryglobal{bind_back}% -\begin{itemdecl} -template - constexpr @\unspec@ bind_front(F&& f, Args&&... args); -template - constexpr @\unspec@ bind_back(F&& f, Args&&... args); -\end{itemdecl} - -\begin{itemdescr} -\pnum -Within this subclause: -\begin{itemize} -\item \tcode{g} is a value of -the result of a \tcode{bind_front} or \tcode{bind_back} invocation, -\item \tcode{FD} is the type \tcode{decay_t}, -\item \tcode{fd} is the target object of \tcode{g}\iref{func.def} - of type \tcode{FD}, - direct-non-list-initialized with \tcode{std::forward(f)}, -\item \tcode{BoundArgs} is a pack - that denotes \tcode{decay_t...}, -\item \tcode{bound_args} is - a pack of bound argument entities of \tcode{g}\iref{func.def} - of types \tcode{BoundArgs...}, - direct-non-list-initialized with \tcode{std::forward(args)...}, - respectively, and -\item \tcode{call_args} is an argument pack used in - a function call expression\iref{expr.call} of \tcode{g}. -\end{itemize} - -\pnum -\mandates -\begin{codeblock} -is_constructible_v && -is_move_constructible_v && -(is_constructible_v && ...) && -(is_move_constructible_v && ...) -\end{codeblock} -is \tcode{true}. - -\pnum -\expects -\tcode{FD} meets the \oldconcept{MoveConstructible} requirements. -For each $\tcode{T}_i$ in \tcode{BoundArgs}, -if $\tcode{T}_i$ is an object type, -$\tcode{T}_i$ meets the \oldconcept{MoveConstructible} requirements. - -\pnum -\returns -A perfect forwarding call wrapper\iref{term.perfect.forwarding.call.wrapper} \tcode{g} -with call pattern: -\begin{itemize} -\item -\tcode{invoke(fd, bound_args..., call_args...)} -for a \tcode{bind_front} invocation, or -\item -\tcode{invoke(fd, call_args..., bound_args...)} -for a \tcode{bind_back} invocation. -\end{itemize} - -\pnum -\throws -Any exception thrown by -the initialization of the state entities of \tcode{g}\iref{func.def}. -\end{itemdescr} - -\rSec2[func.bind]{Function object binders}% - -\rSec3[func.bind.general]{General}% -\indextext{function object!binders|(} - -\pnum -Subclause \ref{func.bind} describes a uniform mechanism for binding -arguments of callable objects. - -\rSec3[func.bind.isbind]{Class template \tcode{is_bind_expression}} - -\indexlibraryglobal{is_bind_expression}% -\begin{codeblock} -namespace std { - template struct is_bind_expression; // see below -} -\end{codeblock} - -\pnum -The class template \tcode{is_bind_expression} can be used to detect function objects -generated by \tcode{bind}. The function template \tcode{bind} -uses \tcode{is_bind_expression} to detect subexpressions. - -\pnum -Specializations of the \tcode{is_bind_expression} template shall meet -the \oldconcept{UnaryTypeTrait} requirements\iref{meta.rqmts}. The implementation -provides a definition that has a base characteristic of -\tcode{true_type} if \tcode{T} is a type returned from \tcode{bind}, -otherwise it has a base characteristic of \tcode{false_type}. -A program may specialize this template for a program-defined type \tcode{T} -to have a base characteristic of \tcode{true_type} to indicate that -\tcode{T} should be treated as a subexpression in a \tcode{bind} call. - -\rSec3[func.bind.isplace]{Class template \tcode{is_placeholder}} - -\indexlibraryglobal{is_placeholder}% -\begin{codeblock} -namespace std { - template struct is_placeholder; // see below -} -\end{codeblock} - -\pnum -The class template \tcode{is_placeholder} can be used to detect the standard placeholders -\tcode{_1}, \tcode{_2}, and so on. The function template \tcode{bind} uses -\tcode{is_placeholder} to detect placeholders. - -\pnum -Specializations of the \tcode{is_placeholder} template shall meet -the \oldconcept{UnaryTypeTrait} requirements\iref{meta.rqmts}. The implementation -provides a definition that has the base characteristic of -\tcode{integral_constant} if \tcode{T} is the type of -\tcode{std::placeholders::_\placeholder{J}}, otherwise it has a -base characteristic of \tcode{integral_constant}. A program -may specialize this template for a program-defined type \tcode{T} to -have a base characteristic of \tcode{integral_constant} -with \tcode{N > 0} to indicate that \tcode{T} should be -treated as a placeholder type. - -\rSec3[func.bind.bind]{Function template \tcode{bind}} -\indexlibrary{\idxcode{bind}|(} - -\pnum -In the text that follows: -\begin{itemize} -\item \tcode{g} is a value of the result of a \tcode{bind} invocation, -\item \tcode{FD} is the type \tcode{decay_t}, -\item \tcode{fd} is an lvalue that - is a target object of \tcode{g}\iref{func.def} of type \tcode{FD} - direct-non-list-initialized with \tcode{std::forward(f)}, -\item $\tcode{T}_i$ is the $i^\text{th}$ type in the template parameter pack \tcode{BoundArgs}, -\item $\tcode{TD}_i$ is the type \tcode{decay_t<$\tcode{T}_i$>}, -\item $\tcode{t}_i$ is the $i^\text{th}$ argument in the function parameter pack \tcode{bound_args}, -\item $\tcode{td}_i$ is a bound argument entity - of \tcode{g}\iref{func.def} of type $\tcode{TD}_i$ - direct-non-list-initialized with - \tcode{std::forward<\brk{}$\tcode{T}_i$>($\tcode{t}_i$)}, -\item $\tcode{U}_j$ is the $j^\text{th}$ deduced type of the \tcode{UnBoundArgs\&\&...} parameter - of the argument forwarding call wrapper, and -\item $\tcode{u}_j$ is the $j^\text{th}$ argument associated with $\tcode{U}_j$. -\end{itemize} - -\indexlibraryglobal{bind}% -\begin{itemdecl} -template - constexpr @\unspec@ bind(F&& f, BoundArgs&&... bound_args); -template - constexpr @\unspec@ bind(F&& f, BoundArgs&&... bound_args); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\mandates -\tcode{is_constructible_v} is \tcode{true}. For each $\tcode{T}_i$ -in \tcode{BoundArgs}, \tcode{is_cons\-tructible_v<$\tcode{TD}_i$, $\tcode{T}_i$>} is \tcode{true}. - -\pnum -\expects -\tcode{FD} and each $\tcode{TD}_i$ meet -the \oldconcept{MoveConstructible} and \oldconcept{Destructible} requirements. -\tcode{\placeholdernc{INVOKE}(fd, $\tcode{w}_1$, $\tcode{w}_2$, $\dotsc$, -$\tcode{w}_N$)}\iref{func.require} is a valid expression for some -values $\tcode{w}_1$, $\tcode{w}_2$, $\dotsc{}$, $\tcode{w}_N$, where -$N$ has the value \tcode{sizeof...(bound_args)}. - -\pnum -\returns -An argument forwarding call wrapper \tcode{g}\iref{func.require}. -A program that attempts to invoke a volatile-qualified \tcode{g} -is ill-formed. -When \tcode{g} is not volatile-qualified, invocation of -\tcode{g($\tcode{u}_1$, $\tcode{u}_2$, $\dotsc$, $\tcode{u}_M$)} -is expression-equivalent\iref{defns.expression.equivalent} to -\begin{codeblock} -@\placeholdernc{INVOKE}@(static_cast<@$\tcode{V}_\tcode{fd}$@>(@$\tcode{v}_\tcode{fd}$@), - static_cast<@$\tcode{V}_1$@>(@$\tcode{v}_1$@), static_cast<@$\tcode{V}_2$@>(@$\tcode{v}_2$@), @$\dotsc$@, static_cast<@$\tcode{V}_N$@>(@$\tcode{v}_N$@)) -\end{codeblock} -for the first overload, and -\begin{codeblock} -@\placeholdernc{INVOKE}@(static_cast<@$\tcode{V}_\tcode{fd}$@>(@$\tcode{v}_\tcode{fd}$@), - static_cast<@$\tcode{V}_1$@>(@$\tcode{v}_1$@), static_cast<@$\tcode{V}_2$@>(@$\tcode{v}_2$@), @$\dotsc$@, static_cast<@$\tcode{V}_N$@>(@$\tcode{v}_N$@)) -\end{codeblock} -for the second overload, -where the values and types of the target argument $\tcode{v}_\tcode{fd}$ and -of the bound arguments -$\tcode{v}_1$, $\tcode{v}_2$, $\dotsc$, $\tcode{v}_N$ are determined as specified below. - -\pnum -\throws -Any exception thrown by the initialization of -the state entities of \tcode{g}. - -\pnum -\begin{note} -If all of \tcode{FD} and $\tcode{TD}_i$ meet -the requirements of \oldconcept{CopyConstructible}, then -the return type meets the requirements of \oldconcept{CopyConstructible}. -\end{note} -\end{itemdescr} - -\pnum -\indextext{bound arguments}% -The values of the \term{bound arguments} $\tcode{v}_1$, $\tcode{v}_2$, $\dotsc$, $\tcode{v}_N$ and their -corresponding types $\tcode{V}_1$, $\tcode{V}_2$, $\dotsc$, $\tcode{V}_N$ depend on the -types $\tcode{TD}_i$ derived from -the call to \tcode{bind} and the -cv-qualifiers \cv{} of the call wrapper \tcode{g} as follows: -\begin{itemize} -\item if $\tcode{TD}_i$ is \tcode{reference_wrapper}, the -argument is \tcode{$\tcode{td}_i$.get()} and its type $\tcode{V}_i$ is \tcode{T\&}; - -\item if the value of \tcode{is_bind_expression_v<$\tcode{TD}_i$>} -is \tcode{true}, the argument is -\begin{codeblock} -static_cast<@\cv{} $\tcode{TD}_i$@&>(@$\tcode{td}_i$@)(std::forward<@$\tcode{U}_j$@>(@$\tcode{u}_j$@)...) -\end{codeblock} -and its type $\tcode{V}_i$ is -\tcode{invoke_result_t<\cv{} $\tcode{TD}_i$\&, $\tcode{U}_j$...>\&\&}; - -\item if the value \tcode{j} of \tcode{is_placeholder_v<$\tcode{TD}_i$>} -is not zero, the argument is \tcode{std::forward<$\tcode{U}_j$>($\tcode{u}_j$)} -and its type $\tcode{V}_i$ -is \tcode{$\tcode{U}_j$\&\&}; - -\item otherwise, the value is $\tcode{td}_i$ and its type $\tcode{V}_i$ -is \tcode{\cv{} $\tcode{TD}_i$\&}. -\end{itemize} - -\pnum -The value of the target argument $\tcode{v}_\tcode{fd}$ is \tcode{fd} and -its corresponding type $\tcode{V}_\tcode{fd}$ is \tcode{\cv{} FD\&}. -\indexlibrary{\idxcode{bind}|)}% - -\rSec3[func.bind.place]{Placeholders} - -\indexlibraryglobal{placeholders}% -\indexlibrary{1@\tcode{_1}}% -\begin{codeblock} -namespace std::placeholders { - // M is the \impldef{number of placeholders for bind expressions} number of placeholders - @\seebelow@ _1; - @\seebelow@ _2; - . - . - . - @\seebelow@ _M; -} -\end{codeblock} - -\pnum -All placeholder types meet the \oldconcept{DefaultConstructible} and -\oldconcept{CopyConstructible} requirements, and -their default constructors and copy/move -constructors are constexpr functions that -do not throw exceptions. It is \impldef{assignability of placeholder -objects} whether -placeholder types meet the \oldconcept{CopyAssignable} requirements, -but if so, their copy assignment operators are -constexpr functions that do not throw exceptions. - -\pnum -Placeholders should be defined as: -\begin{codeblock} -inline constexpr @\unspec@ _1{}; -\end{codeblock} -If they are not, they are declared as: -\begin{codeblock} -extern @\unspec@ _1; -\end{codeblock}% -\indextext{function object!binders|)} - -\rSec2[func.memfn]{Function template \tcode{mem_fn}}% -\indextext{function object!\idxcode{mem_fn}|(} - -\indexlibraryglobal{mem_fn}% -\begin{itemdecl} -template constexpr @\unspec@ mem_fn(R T::* pm) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A simple call wrapper\iref{term.simple.call.wrapper} \tcode{fn} -with call pattern \tcode{invoke(pmd, call_args...)}, where -\tcode{pmd} is the target object of \tcode{fn} of type \tcode{R T::*} -direct-non-list-initialized with \tcode{pm}, and -\tcode{call_args} is an argument pack -used in a function call expression\iref{expr.call} of \tcode{fn}. -\end{itemdescr} -\indextext{function object!\idxcode{mem_fn}|)} - -\rSec2[func.wrap]{Polymorphic function wrappers}% - -\rSec3[func.wrap.general]{General}% -\indextext{function object!wrapper|(} - -\pnum -Subclause \ref{func.wrap} describes polymorphic wrapper classes that -encapsulate arbitrary callable objects. - -\rSec3[func.wrap.badcall]{Class \tcode{bad_function_call}}% -\indexlibraryglobal{bad_function_call}% - -\pnum -An exception of type \tcode{bad_function_call} is thrown by -\tcode{function::operator()}\iref{func.wrap.func.inv} -when the function wrapper object has no target. - -\begin{codeblock} -namespace std { - class bad_function_call : public exception { - public: - // see \ref{exception} for the specification of the special member functions - const char* what() const noexcept override; - }; -} -\end{codeblock} - -\indexlibrarymember{what}{bad_function_call}% -\begin{itemdecl} -const char* what() const noexcept override; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -An -\impldef{return value of \tcode{bad_function_call::what}} \ntbs{}. -\end{itemdescr} - -\rSec3[func.wrap.func]{Class template \tcode{function}} - -\rSec4[func.wrap.func.general]{General} -\indexlibraryglobal{function}% - -\indexlibrarymember{result_type}{function}% -\begin{codeblock} -namespace std { - template class function; // \notdef - - template - class function { - public: - using result_type = R; - - // \ref{func.wrap.func.con}, construct/copy/destroy - function() noexcept; - function(nullptr_t) noexcept; - function(const function&); - function(function&&) noexcept; - template function(F&&); - - function& operator=(const function&); - function& operator=(function&&); - function& operator=(nullptr_t) noexcept; - template function& operator=(F&&); - template function& operator=(reference_wrapper) noexcept; - - ~function(); - - // \ref{func.wrap.func.mod}, function modifiers - void swap(function&) noexcept; - - // \ref{func.wrap.func.cap}, function capacity - explicit operator bool() const noexcept; - - // \ref{func.wrap.func.inv}, function invocation - R operator()(ArgTypes...) const; - - // \ref{func.wrap.func.targ}, function target access - const type_info& target_type() const noexcept; - template T* target() noexcept; - template const T* target() const noexcept; - }; - - template - function(R(*)(ArgTypes...)) -> function; - - template function(F) -> function<@\seebelow@>; -} -\end{codeblock} - -\pnum -The \tcode{function} class template provides polymorphic wrappers that -generalize the notion of a function pointer. Wrappers can store, copy, -and call arbitrary callable objects\iref{func.def}, given a call -signature\iref{func.def}. - -\pnum -\indextext{callable type}% -A callable type\iref{func.def} \tcode{F} -is \defn{Lvalue-Callable} for argument -types \tcode{ArgTypes} -and return type \tcode{R} -if the expression -\tcode{\placeholdernc{INVOKE}(declval(), declval()...)}, -considered as an unevaluated operand\iref{term.unevaluated.operand}, is -well-formed\iref{func.require}. - -\pnum -The \tcode{function} class template is a call -wrapper\iref{func.def} whose call signature\iref{func.def} -is \tcode{R(ArgTypes...)}. - -\pnum -\begin{note} -The types deduced by the deduction guides for \tcode{function} -might change in future revisions of \Cpp{}. -\end{note} - -\rSec4[func.wrap.func.con]{Constructors and destructor} - -\indexlibraryctor{function}% -\begin{itemdecl} -function() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -\tcode{!*this}. -\end{itemdescr} - -\indexlibraryctor{function}% -\begin{itemdecl} -function(nullptr_t) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -\tcode{!*this}. -\end{itemdescr} - -\indexlibraryctor{function}% -\begin{itemdecl} -function(const function& f); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -\tcode{!*this} if \tcode{!f}; otherwise, -the target object of \tcode{*this} is a copy of \tcode{f.target()}. - -\pnum -\throws -Nothing if \tcode{f}'s target is -a specialization of \tcode{reference_wrapper} or -a function pointer. Otherwise, may throw \tcode{bad_alloc} -or any exception thrown by the copy constructor of the stored callable object. - -\pnum -\recommended -Implementations should avoid the use of -dynamically allocated memory for small callable objects, for example, where -\tcode{f}'s target is an object holding only a pointer or reference -to an object and a member function pointer. -\end{itemdescr} - -\indexlibraryctor{function}% -\begin{itemdecl} -function(function&& f) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -If \tcode{!f}, \tcode{*this} has no target; -otherwise, the target of \tcode{*this} is equivalent to -the target of \tcode{f} before the construction, and -\tcode{f} is in a valid state with an unspecified value. - -\pnum -\recommended -Implementations should avoid the use of -dynamically allocated memory for small callable objects, for example, -where \tcode{f}'s target is an object holding only a pointer or reference -to an object and a member function pointer. -\end{itemdescr} - -\indexlibraryctor{function}% -\begin{itemdecl} -template function(F&& f); -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{FD} be \tcode{decay_t}. - -\pnum -\constraints -\begin{itemize} -\item -\tcode{is_same_v, function>} is \tcode{false}, and -\item -\tcode{FD} is Lvalue-Callable\iref{func.wrap.func} for argument types -\tcode{ArgTypes...} and return type \tcode{R}. -\end{itemize} - -\pnum -\mandates -\begin{itemize} -\item -\tcode{is_copy_constructible_v} is \tcode{true}, and -\item -\tcode{is_constructible_v} is \tcode{true}. -\end{itemize} - -\pnum -\expects -\tcode{FD} meets the \oldconcept{CopyConstructible} requirements. - -\pnum -\ensures -\tcode{!*this} is \tcode{true} if any of the following hold: -\begin{itemize} -\item \tcode{f} is a null function pointer value. -\item \tcode{f} is a null member pointer value. -\item \tcode{remove_cvref_t} is -a specialization of the \tcode{function} class template, and -\tcode{!f} is \tcode{true}. -\end{itemize} - -\pnum -Otherwise, \tcode{*this} has a target object of type \tcode{FD} -direct-non-list-initialized with \tcode{std::forward(f)}. - -\pnum -\throws -Nothing if \tcode{FD} is -a specialization of \tcode{reference_wrapper} or -a function pointer type. -Otherwise, may throw \tcode{bad_alloc} or -any exception thrown by the initialization of the target object. - -\pnum -\recommended -Implementations should avoid the use of -dynamically allocated memory for small callable objects, for example, -where \tcode{f} refers to an object holding only a pointer or -reference to an object and a member function pointer. -\end{itemdescr} - - -\begin{itemdecl} -template function(F) -> function<@\seebelow@>; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{\&F::operator()} is well-formed when treated as an unevaluated operand and -\tcode{decltype(\brk{}\&F::operator())} is of the form -\tcode{R(G::*)(A...)}~\cv{}~\tcode{\opt{\&}~\opt{noexcept}} -for a class type \tcode{G}. - -\pnum -\remarks -The deduced type is \tcode{function}. - -\pnum -\begin{example} -\begin{codeblock} -void f() { - int i{5}; - function g = [&](double) { return i; }; // deduces \tcode{function} -} -\end{codeblock} -\end{example} -\end{itemdescr} - -\indexlibrarymember{operator=}{function}% -\begin{itemdecl} -function& operator=(const function& f); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -As if by \tcode{function(f).swap(*this);} - -\pnum -\returns -\tcode{*this}. -\end{itemdescr} - -\indexlibrarymember{operator=}{function}% -\begin{itemdecl} -function& operator=(function&& f); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Replaces the target of \tcode{*this} -with the target of \tcode{f}. - -\pnum -\returns -\tcode{*this}. -\end{itemdescr} - -\indexlibrarymember{operator=}{function}% -\begin{itemdecl} -function& operator=(nullptr_t) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If \tcode{*this != nullptr}, destroys the target of \keyword{this}. - -\pnum -\ensures -\tcode{!(*this)}. - -\pnum -\returns -\tcode{*this}. -\end{itemdescr} - -\indexlibrarymember{operator=}{function}% -\begin{itemdecl} -template function& operator=(F&& f); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{decay_t} is Lvalue-Callable\iref{func.wrap.func} -for argument types \tcode{ArgTypes...} and return type \tcode{R}. - -\pnum -\effects -As if by: \tcode{function(std::forward(f)).swap(*this);} - -\pnum -\returns -\tcode{*this}. -\end{itemdescr} - -\indexlibrarymember{operator=}{function}% -\begin{itemdecl} -template function& operator=(reference_wrapper f) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -As if by: \tcode{function(f).swap(*this);} - -\pnum -\returns -\tcode{*this}. -\end{itemdescr} - -\indexlibrarydtor{function}% -\begin{itemdecl} -~function(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If \tcode{*this != nullptr}, destroys the target of \keyword{this}. -\end{itemdescr} - -\rSec4[func.wrap.func.mod]{Modifiers} - -\indexlibrarymember{swap}{function}% -\begin{itemdecl} -void swap(function& other) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Interchanges the target objects of \tcode{*this} and \tcode{other}. -\end{itemdescr} - -\rSec4[func.wrap.func.cap]{Capacity} - -\indexlibrarymember{operator bool}{function}% -\begin{itemdecl} -explicit operator bool() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true} if \tcode{*this} has a target, otherwise \tcode{false}. -\end{itemdescr} - -\rSec4[func.wrap.func.inv]{Invocation} - -\indexlibrary{\idxcode{function}!invocation}% -\indexlibrarymember{operator()}{function}% -\begin{itemdecl} -R operator()(ArgTypes... args) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{\placeholdernc{INVOKE}(f, std::forward(args)...)}\iref{func.require}, -where \tcode{f} is the target object\iref{func.def} of \tcode{*this}. - -\pnum -\throws -\tcode{bad_function_call} if \tcode{!*this}; otherwise, any -exception thrown by the target object. -\end{itemdescr} - -\rSec4[func.wrap.func.targ]{Target access} - -\indexlibrarymember{target_type}{function}% -\begin{itemdecl} -const type_info& target_type() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -If \tcode{*this} has a target of type \tcode{T}, - \tcode{typeid(T)}; otherwise, \tcode{typeid(void)}. -\end{itemdescr} - -\indexlibrarymember{target}{function}% -\begin{itemdecl} -template T* target() noexcept; -template const T* target() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -If \tcode{target_type() == typeid(T)} -a pointer to the stored function target; otherwise a null pointer. -\end{itemdescr} - -\rSec4[func.wrap.func.nullptr]{Null pointer comparison operator functions} - -\indexlibrarymember{operator==}{function}% -\begin{itemdecl} -template - bool operator==(const function& f, nullptr_t) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{!f}. -\end{itemdescr} - -\rSec4[func.wrap.func.alg]{Specialized algorithms} - -\indexlibrarymember{swap}{function}% -\begin{itemdecl} -template - void swap(function& f1, function& f2) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -As if by: \tcode{f1.swap(f2);} -\end{itemdescr}% - -\rSec3[func.wrap.move]{Move only wrapper} - -\rSec4[func.wrap.move.general]{General} - -\pnum -The header provides partial specializations of \tcode{move_only_function} -for each combination of the possible replacements -of the placeholders \cv{}, \placeholder{ref}, and \placeholder{noex} where -\begin{itemize} -\item -\cv{} is either const or empty, -\item -\placeholder{ref} is either \tcode{\&}, \tcode{\&\&}, or empty, and -\item -\placeholder{noex} is either \tcode{true} or \tcode{false}. -\end{itemize} - -\pnum -For each of the possible combinations of the placeholders mentioned above, -there is a placeholder \placeholder{inv-quals} defined as follows: -\begin{itemize} -\item -If \placeholder{ref} is empty, let \placeholder{inv-quals} be \tcode{\cv{}\&}, -\item -otherwise, let \placeholder{inv-quals} be \cv{} \placeholder{ref}. -\end{itemize} - -\rSec4[func.wrap.move.class]{Class template \tcode{move_only_function}} - -\indexlibraryglobal{move_only_function}% -\begin{codeblock} -namespace std { - template class move_only_function; // \notdef - - template - class move_only_function { - public: - using result_type = R; - - // \ref{func.wrap.move.ctor}, constructors, assignment, and destructor - move_only_function() noexcept; - move_only_function(nullptr_t) noexcept; - move_only_function(move_only_function&&) noexcept; - template move_only_function(F&&); - template - explicit move_only_function(in_place_type_t, Args&&...); - template - explicit move_only_function(in_place_type_t, initializer_list, Args&&...); - - move_only_function& operator=(move_only_function&&); - move_only_function& operator=(nullptr_t) noexcept; - template move_only_function& operator=(F&&); - - ~move_only_function(); - - // \ref{func.wrap.move.inv}, invocation - explicit operator bool() const noexcept; - R operator()(ArgTypes...) @\cv{}@ @\placeholder{ref}@ noexcept(@\placeholder{noex}@); - - // \ref{func.wrap.move.util}, utility - void swap(move_only_function&) noexcept; - friend void swap(move_only_function&, move_only_function&) noexcept; - friend bool operator==(const move_only_function&, nullptr_t) noexcept; - - private: - template - static constexpr bool @\exposid{is-callable-from}@ = @\seebelow@; // \expos - }; -} -\end{codeblock} - -\pnum -The \tcode{move_only_function} class template provides polymorphic wrappers -that generalize the notion of a callable object\iref{func.def}. -These wrappers can store, move, and call arbitrary callable objects, -given a call signature. - -\pnum -\recommended -Implementations should avoid the use of dynamically allocated memory -for a small contained value. -\begin{note} -Such small-object optimization can only be applied to a type \tcode{T} -for which \tcode{is_nothrow_move_constructible_v} is \tcode{true}. -\end{note} - -\rSec4[func.wrap.move.ctor]{Constructors, assignment, and destructor} - -\indexlibrarymember{\exposid{is-callable-from}}{move_only_function}% -\begin{itemdecl} -template - static constexpr bool @\exposid{is-callable-from}@ = @\seebelow@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -If \placeholder{noex} is \tcode{true}, -\tcode{\exposid{is-callable-from}} is equal to: -\begin{codeblock} -is_nothrow_invocable_r_v && -is_nothrow_invocable_r_v -\end{codeblock} -Otherwise, \tcode{\exposid{is-callable-from}} is equal to: -\begin{codeblock} -is_invocable_r_v && -is_invocable_r_v -\end{codeblock} -\end{itemdescr} - -\indexlibraryctor{move_only_function}% -\begin{itemdecl} -move_only_function() noexcept; -move_only_function(nullptr_t) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -\tcode{*this} has no target object. -\end{itemdescr} - -\indexlibraryctor{move_only_function}% -\begin{itemdecl} -move_only_function(move_only_function&& f) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -The target object of \tcode{*this} is -the target object \tcode{f} had before construction, and -\tcode{f} is in a valid state with an unspecified value. -\end{itemdescr} - -\indexlibraryctor{move_only_function}% -\begin{itemdecl} -template move_only_function(F&& f); -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{VT} be \tcode{decay_t}. - -\pnum -\constraints -\begin{itemize} -\item -\tcode{remove_cvref_t} is not the same type as \tcode{move_only_function}, and -\item -\tcode{remove_cvref_t} is not a specialization of \tcode{in_place_type_t}, and -\item -\tcode{\exposid{is-callable-from}} is \tcode{true}. -\end{itemize} - -\pnum -\mandates -\tcode{is_constructible_v} is \tcode{true}. - -\pnum -\expects -\tcode{VT} meets the \oldconcept{Destructible} requirements, and -if \tcode{is_move_constructible_v} is \tcode{true}, -\tcode{VT} meets the \oldconcept{MoveConstructible} requirements. - -\pnum -\ensures -\tcode{*this} has no target object if any of the following hold: -\begin{itemize} -\item -\tcode{f} is a null function pointer value, or -\item -\tcode{f} is a null member pointer value, or -\item -\tcode{remove_cvref_t} is a specialization of -the \tcode{move_only_function} class template, -and \tcode{f} has no target object. -\end{itemize} -Otherwise, \tcode{*this} has a target object of type \tcode{VT} -direct-non-list-initialized with \tcode{std::forward(f)}. - -\pnum -\throws -Any exception thrown by the initialization of the target object. -May throw \tcode{bad_alloc} unless \tcode{VT} is -a function pointer or a specialization of \tcode{reference_wrapper}. -\end{itemdescr} - -\indexlibraryctor{move_only_function}% -\begin{itemdecl} -template - explicit move_only_function(in_place_type_t, Args&&... args); -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{VT} be \tcode{decay_t}. - -\pnum -\constraints -\begin{itemize} -\item -\tcode{is_constructible_v} is \tcode{true}, and -\item -\tcode{\exposid{is-callable-from}} is \tcode{true}. -\end{itemize} - -\pnum -\mandates -\tcode{VT} is the same type as \tcode{T}. - -\pnum -\expects -\tcode{VT} meets the \oldconcept{Destructible} requirements, and -if \tcode{is_move_constructible_v} is \tcode{true}, -\tcode{VT} meets the \oldconcept{MoveConstructible} requirements. - -\pnum -\ensures -\tcode{*this} has a target object of type \tcode{VT} -direct-non-list-initialized with \tcode{std::forward\brk{}(args)...}. - -\pnum -\throws -Any exception thrown by the initialization of the target object. -May throw \tcode{bad_alloc} unless \tcode{VT} is -a function pointer or a specialization of \tcode{reference_wrapper}. -\end{itemdescr} - -\indexlibraryctor{move_only_function}% -\begin{itemdecl} -template - explicit move_only_function(in_place_type_t, initializer_list ilist, Args&&... args); -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{VT} be \tcode{decay_t}. - -\pnum -\constraints -\begin{itemize} -\item -\tcode{is_constructible_v\&, ArgTypes...>} is -\tcode{true}, and -\item -\tcode{\exposid{is-callable-from}} is \tcode{true}. -\end{itemize} - -\pnum -\mandates -\tcode{VT} is the same type as \tcode{T}. - -\pnum -\expects -\tcode{VT} meets the \oldconcept{Destructible} requirements, and -if \tcode{is_move_constructible_v} is \tcode{true}, -\tcode{VT} meets the \oldconcept{MoveConstructible} requirements. - -\pnum -\ensures -\tcode{*this} has a target object of type \tcode{VT} -direct-non-list-initialized with -\tcode{ilist, std::for\-ward(args)...}. - -\pnum -\throws -Any exception thrown by the initialization of the target object. -May throw \tcode{bad_alloc} unless \tcode{VT} is -a function pointer or a specialization of \tcode{reference_wrapper}. -\end{itemdescr} - -\indexlibrarymember{operator=}{move_only_function}% -\begin{itemdecl} -move_only_function& operator=(move_only_function&& f); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{move_only_function(std::move(f)).swap(*this);} - -\pnum -\returns -\tcode{*this}. -\end{itemdescr} - -\indexlibrarymember{operator=}{move_only_function}% -\begin{itemdecl} -move_only_function& operator=(nullptr_t) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Destroys the target object of \tcode{*this}, if any. - -\pnum -\returns -\tcode{*this}. -\end{itemdescr} - -\indexlibrarymember{operator=}{move_only_function}% -\begin{itemdecl} -template move_only_function& operator=(F&& f); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{move_only_function(std::forward(f)).swap(*this);} - -\pnum -\returns -\tcode{*this}. -\end{itemdescr} - -\indexlibrarydtor{move_only_function}% -\begin{itemdecl} -~move_only_function(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Destroys the target object of \tcode{*this}, if any. -\end{itemdescr} - -\rSec4[func.wrap.move.inv]{Invocation} - -\indexlibrarymember{operator bool}{move_only_function}% -\begin{itemdecl} -explicit operator bool() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true} if \tcode{*this} has a target object, otherwise \tcode{false}. -\end{itemdescr} - -\indexlibrarymember{operator()}{move_only_function}% -\begin{itemdecl} -R operator()(ArgTypes... args) @\cv{}@ @\placeholder{ref}@ noexcept(@\placeholder{noex}@); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{*this} has a target object. - -\pnum -\effects -Equivalent to: -\begin{codeblock} -return @\placeholder{INVOKE}@(static_cast(f), std::forward(args)...); -\end{codeblock} -where \tcode{f} is an lvalue designating the target object of \tcode{*this} and -\tcode{F} is the type of \tcode{f}. -\end{itemdescr} - -\rSec4[func.wrap.move.util]{Utility} - -\indexlibrarymember{swap}{move_only_function}% -\begin{itemdecl} -void swap(move_only_function& other) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Exchanges the target objects of \tcode{*this} and \tcode{other}. -\end{itemdescr} - -\indexlibrarymember{swap}{move_only_function}% -\begin{itemdecl} -friend void swap(move_only_function& f1, move_only_function& f2) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to \tcode{f1.swap(f2)}. -\end{itemdescr} - -\indexlibrarymember{operator==}{move_only_function}% -\begin{itemdecl} -friend bool operator==(const move_only_function& f, nullptr_t) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true} if \tcode{f} has no target object, otherwise \tcode{false}. -\end{itemdescr} -\indextext{function object!wrapper|)} - -\rSec2[func.search]{Searchers} - -\rSec3[func.search.general]{General} - -\pnum -Subclause \ref{func.search} provides function object types\iref{function.objects} for -operations that search for a sequence \range{pat\textunderscore\nobreak first}{pat_last} in another -sequence \range{first}{last} that is provided to the object's function call -operator. The first sequence (the pattern to be searched for) is provided to -the object's constructor, and the second (the sequence to be searched) is -provided to the function call operator. - -\pnum -Each specialization of a class template specified in \ref{func.search} -shall meet the \oldconcept{CopyConst\-ruct\-ible} and \oldconcept{CopyAssignable} requirements. -Template parameters named -\begin{itemize} -\item \tcode{ForwardIterator}, -\item \tcode{ForwardIterator1}, -\item \tcode{ForwardIterator2}, -\item \tcode{RandomAccessIterator}, -\item \tcode{RandomAccessIterator1}, -\item \tcode{RandomAccessIterator2}, and -\item \tcode{BinaryPredicate} -\end{itemize} -of templates specified in -\ref{func.search} shall meet the same requirements and semantics as -specified in \ref{algorithms.general}. -Template parameters named \tcode{Hash} shall meet the \oldconcept{Hash} -requirements (\tref{cpp17.hash}). - -\pnum -The Boyer-Moore searcher implements the Boyer-Moore search algorithm. -The Boyer-Moore-Horspool searcher implements the Boyer-Moore-Horspool search algorithm. -In general, the Boyer-Moore searcher will use more memory and give better runtime performance than Boyer-Moore-Horspool. - -\rSec3[func.search.default]{Class template \tcode{default_searcher}} - -\indexlibraryglobal{default_searcher}% -\begin{codeblock} -template> - class default_searcher { - public: - constexpr default_searcher(ForwardIterator1 pat_first, ForwardIterator1 pat_last, - BinaryPredicate pred = BinaryPredicate()); - - template - constexpr pair - operator()(ForwardIterator2 first, ForwardIterator2 last) const; - - private: - ForwardIterator1 pat_first_; // \expos - ForwardIterator1 pat_last_; // \expos - BinaryPredicate pred_; // \expos - }; -\end{codeblock} - -\indexlibraryctor{default_searcher}% -\begin{itemdecl} -constexpr default_searcher(ForwardIterator pat_first, ForwardIterator pat_last, - BinaryPredicate pred = BinaryPredicate()); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -% FIXME: The mbox prevents TeX from adding a bizarre hyphen after pat_last_. -Constructs a \tcode{default_searcher} object, initializing \tcode{pat_first_} -with \tcode{pat_first}, \mbox{\tcode{pat_last_}} with \tcode{pat_last}, and -\tcode{pred_} with \tcode{pred}. - -\pnum -\throws -Any exception thrown by the copy constructor of \tcode{BinaryPredicate} or -\tcode{ForwardIterator1}. -\end{itemdescr} - -\indexlibrarymember{operator()}{default_searcher}% -\begin{itemdecl} -template - constexpr pair - operator()(ForwardIterator2 first, ForwardIterator2 last) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Returns a pair of iterators \tcode{i} and \tcode{j} such that -\begin{itemize} -\item \tcode{i == search(first, last, pat_first_, pat_last_, pred_)}, and -\item if \tcode{i == last}, then \tcode{j == last}, -otherwise \tcode{j == next(i, distance(pat_first_, pat_last_))}. -\end{itemize} -\end{itemdescr} - -\rSec3[func.search.bm]{Class template \tcode{boyer_moore_searcher}} - -\indexlibraryglobal{boyer_moore_searcher}% -\begin{codeblock} -template::value_type>, - class BinaryPredicate = equal_to<>> - class boyer_moore_searcher { - public: - boyer_moore_searcher(RandomAccessIterator1 pat_first, - RandomAccessIterator1 pat_last, - Hash hf = Hash(), - BinaryPredicate pred = BinaryPredicate()); - - template - pair - operator()(RandomAccessIterator2 first, RandomAccessIterator2 last) const; - - private: - RandomAccessIterator1 pat_first_; // \expos - RandomAccessIterator1 pat_last_; // \expos - Hash hash_; // \expos - BinaryPredicate pred_; // \expos - }; -\end{codeblock} - -\indexlibraryctor{boyer_moore_searcher}% -\begin{itemdecl} -boyer_moore_searcher(RandomAccessIterator1 pat_first, - RandomAccessIterator1 pat_last, - Hash hf = Hash(), - BinaryPredicate pred = BinaryPredicate()); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -The value type of \tcode{RandomAccessIterator1} meets -the \oldconcept{DefaultConstructible}, -the \oldconcept{Copy\-Constructible}, and -the \oldconcept{CopyAssignable} requirements. - -\pnum -Let \tcode{V} be \tcode{iterator_traits::val\-ue_type}. -For any two values \tcode{A} and \tcode{B} of type \tcode{V}, -if \tcode{pred(A, B) == true}, then \tcode{hf(A) == hf(B)} is \tcode{true}. - -\pnum -\effects -Initializes -\tcode{pat_first_} with \tcode{pat_first}, -\tcode{pat_last_} with \tcode{pat_last}, -\tcode{hash_} with \tcode{hf}, and -\tcode{pred_} with \tcode{pred}. - -\pnum -\throws -Any exception thrown by the copy constructor of \tcode{RandomAccessIterator1}, -or by the default constructor, copy constructor, or the copy assignment operator of the value type of \tcode{RandomAccess\-Iterator1}, -or the copy constructor or \tcode{operator()} of \tcode{BinaryPredicate} or \tcode{Hash}. -May throw \tcode{bad_alloc} if additional memory needed for internal data structures cannot be allocated. -\end{itemdescr} - -\indexlibrarymember{operator()}{boyer_moore_searcher}% -\begin{itemdecl} -template - pair - operator()(RandomAccessIterator2 first, RandomAccessIterator2 last) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\mandates -\tcode{RandomAccessIterator1} and \tcode{RandomAccessIterator2} -have the same value type. - -\pnum -\effects -Finds a subsequence of equal values in a sequence. - -\pnum -\returns -A pair of iterators \tcode{i} and \tcode{j} such that -\begin{itemize} -\item \tcode{i} is the first iterator -in the range \range{first}{last - (pat_last_ - pat_first_)} such that -for every non-negative integer \tcode{n} less than \tcode{pat_last_ - pat_first_} -the following condition holds: -\tcode{pred(*(i + n), *(pat_first_ + n)) != false}, and -\item \tcode{j == next(i, distance(pat_first_, pat_last_))}. -\end{itemize} -Returns \tcode{make_pair(first, first)} if \range{pat_first_}{pat_last_} is empty, -otherwise returns \tcode{make_pair(last, last)} if no such iterator is found. - -\pnum -\complexity -At most \tcode{(last - first) * (pat_last_ - pat_first_)} applications of the predicate. -\end{itemdescr} - -\rSec3[func.search.bmh]{Class template \tcode{boyer_moore_horspool_searcher}} - -\indexlibraryglobal{boyer_moore_horspool_searcher}% -\begin{codeblock} -template::value_type>, - class BinaryPredicate = equal_to<>> - class boyer_moore_horspool_searcher { - public: - boyer_moore_horspool_searcher(RandomAccessIterator1 pat_first, - RandomAccessIterator1 pat_last, - Hash hf = Hash(), - BinaryPredicate pred = BinaryPredicate()); - - template - pair - operator()(RandomAccessIterator2 first, RandomAccessIterator2 last) const; - - private: - RandomAccessIterator1 pat_first_; // \expos - RandomAccessIterator1 pat_last_; // \expos - Hash hash_; // \expos - BinaryPredicate pred_; // \expos - }; -\end{codeblock} - -\indexlibraryctor{boyer_moore_horspool_searcher}% -\begin{itemdecl} -boyer_moore_horspool_searcher(RandomAccessIterator1 pat_first, - RandomAccessIterator1 pat_last, - Hash hf = Hash(), - BinaryPredicate pred = BinaryPredicate()); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -The value type of \tcode{RandomAccessIterator1} meets the \oldconcept{DefaultConstructible}, -\oldconcept{Copy\-Constructible}, and \oldconcept{CopyAssignable} requirements. - -\pnum -Let \tcode{V} be \tcode{iterator_traits::val\-ue_type}. -For any two values \tcode{A} and \tcode{B} of type \tcode{V}, -if \tcode{pred(A, B) == true}, then \tcode{hf(A) == hf(B)} is \tcode{true}. - -\pnum -\effects -Initializes -\tcode{pat_first_} with \tcode{pat_first}, -\tcode{pat_last_} with \tcode{pat_last}, -\tcode{hash_} with \tcode{hf}, and -\tcode{pred_} with \tcode{pred}. - -\pnum -\throws -Any exception thrown by the copy constructor of \tcode{RandomAccessIterator1}, -or by the default constructor, copy constructor, or the copy assignment operator of the value type of \tcode{RandomAccess\-Iterator1}, -or the copy constructor or \tcode{operator()} of \tcode{BinaryPredicate} or \tcode{Hash}. -May throw \tcode{bad_alloc} if additional memory needed for internal data structures cannot be allocated. -\end{itemdescr} - -\indexlibrarymember{operator()}{boyer_moore_horspool_searcher}% -\begin{itemdecl} -template - pair - operator()(RandomAccessIterator2 first, RandomAccessIterator2 last) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\mandates -\tcode{RandomAccessIterator1} and \tcode{RandomAccessIterator2} -have the same value type. - -\pnum -\effects -Finds a subsequence of equal values in a sequence. - -\pnum -\returns -A pair of iterators \tcode{i} and \tcode{j} such that -\begin{itemize} -\item \tcode{i} is the first iterator in the range -\range{first}{last - (pat_last_ - pat_first_)} such that -for every non-negative integer \tcode{n} less than \tcode{pat_last_ - pat_first_} -the following condition holds: -\tcode{pred(*(i + n), *(pat_first_ + n)) != false}, and -\item \tcode{j == next(i, distance(pat_first_, pat_last_))}. -\end{itemize} -Returns \tcode{make_pair(first, first)} if \range{pat_first_}{pat_last_} is empty, -otherwise returns \tcode{make_pair(last, last)} if no such iterator is found. - -\pnum -\complexity -At most \tcode{(last - first) * (pat_last_ - pat_first_)} applications of the predicate. -\end{itemdescr} - -\rSec2[unord.hash]{Class template \tcode{hash}} - -\pnum -\indexlibraryglobal{hash}% -\indextext{\idxcode{hash}!instantiation restrictions}% -The unordered associative containers defined in \ref{unord} use -specializations of the class template \tcode{hash}\iref{functional.syn} -as the default hash function. - -\pnum -Each specialization of \tcode{hash} is either enabled or disabled, -as described below. -\begin{note} -Enabled specializations meet the \oldconcept{Hash} requirements, and -disabled specializations do not. -\end{note} -Each header that declares the template \tcode{hash} -provides enabled specializations of \tcode{hash} for \tcode{nullptr_t} and -all cv-unqualified arithmetic, enumeration, and pointer types. -For any type \tcode{Key} for which neither the library nor the user provides -an explicit or partial specialization of the class template \tcode{hash}, -\tcode{hash} is disabled. - -\pnum -If the library provides an explicit or partial specialization of \tcode{hash}, -that specialization is enabled except as noted otherwise, -and its member functions are \keyword{noexcept} except as noted otherwise. - -\pnum -If \tcode{H} is a disabled specialization of \tcode{hash}, -these values are \tcode{false}: -\tcode{is_default_constructible_v}, -\tcode{is_copy_constructible_v}, -\tcode{is_move_constructible_v}, -\tcode{is_copy_assignable_v}, and -\tcode{is_move_assignable_v}. -Disabled specializations of \tcode{hash} -are not function object types\iref{function.objects}. -\begin{note} -This means that the specialization of \tcode{hash} exists, but -any attempts to use it as a \oldconcept{Hash} will be ill-formed. -\end{note} - -\pnum -An enabled specialization \tcode{hash} will: -\begin{itemize} -\item meet the \oldconcept{Hash} requirements (\tref{cpp17.hash}), -with \tcode{Key} as the function -call argument type, the \oldconcept{Default\-Constructible} requirements (\tref{cpp17.defaultconstructible}), -the \oldconcept{CopyAssignable} requirements (\tref{cpp17.copyassignable}), -\item be swappable\iref{swappable.requirements} for lvalues, -\item meet the requirement that if \tcode{k1 == k2} is \tcode{true}, \tcode{h(k1) == h(k2)} is -also \tcode{true}, where \tcode{h} is an object of type \tcode{hash} and \tcode{k1} and \tcode{k2} -are objects of type \tcode{Key}; -\item meet the requirement that the expression \tcode{h(k)}, where \tcode{h} -is an object of type \tcode{hash} and \tcode{k} is an object of type -\tcode{Key}, shall not throw an exception unless \tcode{hash} is a -program-defined specialization. -\end{itemize} - -\rSec1[meta]{Metaprogramming and type traits} - -\rSec2[meta.general]{General} - -\pnum -Subclause \ref{meta} describes components used by \Cpp{} programs, particularly in -templates, to support the widest possible range of types, optimise -template code usage, detect type related user errors, and perform -type inference and transformation at compile time. It includes type -classification traits, type property inspection traits, and type -transformations. The type classification traits describe a complete taxonomy -of all possible \Cpp{} types, and state where in that taxonomy a given -type belongs. The type property inspection traits allow important -characteristics of types or of combinations of types to be inspected. The -type transformations allow certain properties of types to be manipulated. - -\pnum -\indextext{signal-safe!type traits}% -All functions specified in \ref{meta} are signal-safe\iref{support.signal}. - -\rSec2[meta.rqmts]{Requirements} - -\pnum -A \defnoldconcept{UnaryTypeTrait} describes a property -of a type. It shall be a class template that takes one template type -argument and, optionally, additional arguments that help define the -property being described. It shall be \oldconcept{DefaultConstructible}, -\oldconcept{CopyConstructible}, -and publicly and unambiguously derived, directly or indirectly, from -its \defn{base characteristic}, which is -a specialization of the template -\tcode{integral_constant}\iref{meta.help}, with -the arguments to the template \tcode{integral_constant} determined by the -requirements for the particular property being described. -The member names of the base characteristic shall not be hidden and shall be -unambiguously available in the \oldconcept{UnaryTypeTrait}. - -\pnum -A \defnoldconcept{BinaryTypeTrait} describes a -relationship between two types. It shall be a class template that -takes two template type arguments and, optionally, additional -arguments that help define the relationship being described. It shall -be \oldconcept{DefaultConstructible}, \oldconcept{CopyConstructible}, -and publicly and unambiguously derived, directly or -indirectly, from -its \term{base characteristic}, which is a specialization -of the template -\tcode{integral_constant}\iref{meta.help}, with -the arguments to the template \tcode{integral_constant} determined by the -requirements for the particular relationship being described. -The member names of the base characteristic shall not be hidden and shall be -unambiguously available in the \oldconcept{BinaryTypeTrait}. - -\pnum -A \defnoldconcept{TransformationTrait} -modifies a property -of a type. It shall be a class template that takes one -template type argument and, optionally, additional arguments that help -define the modification. It shall define a publicly accessible nested type -named \tcode{type}, which shall be a synonym for the modified type. - -\pnum -Unless otherwise specified, -the behavior of a program that adds specializations -for any of the templates specified in \ref{meta} -is undefined. - -\pnum -Unless otherwise specified, an incomplete type may be used -to instantiate a template specified in \ref{meta}. -The behavior of a program is undefined if: -\begin{itemize} -\item - an instantiation of a template specified in \ref{meta} - directly or indirectly depends on - an incompletely-defined object type \tcode{T}, and -\item - that instantiation could yield a different result - were \tcode{T} hypothetically completed. -\end{itemize} - -\rSec2[meta.type.synop]{Header \tcode{} synopsis} - -\indexheader{type_traits}% -% FIXME: Many index entries missing. -\begin{codeblock} -namespace std { - // \ref{meta.help}, helper class - template struct integral_constant; - - template - using bool_constant = integral_constant; - using true_type = bool_constant; - using false_type = bool_constant; - - // \ref{meta.unary.cat}, primary type categories - template struct is_void; - template struct is_null_pointer; - template struct is_integral; - template struct is_floating_point; - template struct is_array; - template struct is_pointer; - template struct is_lvalue_reference; - template struct is_rvalue_reference; - template struct is_member_object_pointer; - template struct is_member_function_pointer; - template struct is_enum; - template struct is_union; - template struct is_class; - template struct is_function; - - // \ref{meta.unary.comp}, composite type categories - template struct is_reference; - template struct is_arithmetic; - template struct is_fundamental; - template struct is_object; - template struct is_scalar; - template struct is_compound; - template struct is_member_pointer; - - // \ref{meta.unary.prop}, type properties - template struct is_const; - template struct is_volatile; - template struct is_trivial; - template struct is_trivially_copyable; - template struct is_standard_layout; - template struct is_empty; - template struct is_polymorphic; - template struct is_abstract; - template struct is_final; - template struct is_aggregate; - - template struct is_signed; - template struct is_unsigned; - template struct is_bounded_array; - template struct is_unbounded_array; - template struct is_scoped_enum; - - template struct is_constructible; - template struct is_default_constructible; - template struct is_copy_constructible; - template struct is_move_constructible; - - template struct is_assignable; - template struct is_copy_assignable; - template struct is_move_assignable; - - template struct is_swappable_with; - template struct is_swappable; - - template struct is_destructible; - - template struct is_trivially_constructible; - template struct is_trivially_default_constructible; - template struct is_trivially_copy_constructible; - template struct is_trivially_move_constructible; - - template struct is_trivially_assignable; - template struct is_trivially_copy_assignable; - template struct is_trivially_move_assignable; - template struct is_trivially_destructible; - - template struct is_nothrow_constructible; - template struct is_nothrow_default_constructible; - template struct is_nothrow_copy_constructible; - template struct is_nothrow_move_constructible; - - template struct is_nothrow_assignable; - template struct is_nothrow_copy_assignable; - template struct is_nothrow_move_assignable; - - template struct is_nothrow_swappable_with; - template struct is_nothrow_swappable; - - template struct is_nothrow_destructible; - - template struct has_virtual_destructor; - - template struct has_unique_object_representations; - - template struct reference_constructs_from_temporary; - template struct reference_converts_from_temporary; - - // \ref{meta.unary.prop.query}, type property queries - template struct alignment_of; - template struct rank; - template struct extent; - - // \ref{meta.rel}, type relations - template struct is_same; - template struct is_base_of; - template struct is_convertible; - template struct is_nothrow_convertible; - template struct is_layout_compatible; - template struct is_pointer_interconvertible_base_of; - - template struct is_invocable; - template struct is_invocable_r; - - template struct is_nothrow_invocable; - template struct is_nothrow_invocable_r; - - // \ref{meta.trans.cv}, const-volatile modifications - template struct remove_const; - template struct remove_volatile; - template struct remove_cv; - template struct add_const; - template struct add_volatile; - template struct add_cv; - - template - using @\libglobal{remove_const_t}@ = typename remove_const::type; - template - using @\libglobal{remove_volatile_t}@ = typename remove_volatile::type; - template - using @\libglobal{remove_cv_t}@ = typename remove_cv::type; - template - using @\libglobal{add_const_t}@ = typename add_const::type; - template - using @\libglobal{add_volatile_t}@ = typename add_volatile::type; - template - using @\libglobal{add_cv_t}@ = typename add_cv::type; - - // \ref{meta.trans.ref}, reference modifications - template struct remove_reference; - template struct add_lvalue_reference; - template struct add_rvalue_reference; - - template - using @\libglobal{remove_reference_t}@ = typename remove_reference::type; - template - using @\libglobal{add_lvalue_reference_t}@ = typename add_lvalue_reference::type; - template - using @\libglobal{add_rvalue_reference_t}@ = typename add_rvalue_reference::type; - - // \ref{meta.trans.sign}, sign modifications - template struct make_signed; - template struct make_unsigned; - - template - using @\libglobal{make_signed_t}@ = typename make_signed::type; - template - using @\libglobal{make_unsigned_t}@ = typename make_unsigned::type; - - // \ref{meta.trans.arr}, array modifications - template struct remove_extent; - template struct remove_all_extents; - - template - using @\libglobal{remove_extent_t}@ = typename remove_extent::type; - template - using @\libglobal{remove_all_extents_t}@ = typename remove_all_extents::type; - - // \ref{meta.trans.ptr}, pointer modifications - template struct remove_pointer; - template struct add_pointer; - - template - using @\libglobal{remove_pointer_t}@ = typename remove_pointer::type; - template - using @\libglobal{add_pointer_t}@ = typename add_pointer::type; - - // \ref{meta.trans.other}, other transformations - template struct type_identity; - template struct remove_cvref; - template struct decay; - template struct enable_if; - template struct conditional; - template struct common_type; - template class TQual, template class UQual> - struct basic_common_reference { }; - template struct common_reference; - template struct underlying_type; - template struct invoke_result; - template struct unwrap_reference; - template struct unwrap_ref_decay; - - template - using @\libglobal{type_identity_t}@ = typename type_identity::type; - template - using @\libglobal{remove_cvref_t}@ = typename remove_cvref::type; - template - using @\libglobal{decay_t}@ = typename decay::type; - template - using @\libglobal{enable_if_t}@ = typename enable_if::type; - template - using @\libglobal{conditional_t}@ = typename conditional::type; - template - using @\libglobal{common_type_t}@ = typename common_type::type; - template - using @\libglobal{common_reference_t}@ = typename common_reference::type; - template - using @\libglobal{underlying_type_t}@ = typename underlying_type::type; - template - using @\libglobal{invoke_result_t}@ = typename invoke_result::type; - template - using unwrap_reference_t = typename unwrap_reference::type; - template - using unwrap_ref_decay_t = typename unwrap_ref_decay::type; - template - using @\libglobal{void_t}@ = void; - - // \ref{meta.logical}, logical operator traits - template struct conjunction; - template struct disjunction; - template struct negation; - - // \ref{meta.unary.cat}, primary type categories - template - inline constexpr bool @\libglobal{is_void_v}@ = is_void::value; - template - inline constexpr bool @\libglobal{is_null_pointer_v}@ = is_null_pointer::value; - template - inline constexpr bool @\libglobal{is_integral_v}@ = is_integral::value; - template - inline constexpr bool @\libglobal{is_floating_point_v}@ = is_floating_point::value; - template - inline constexpr bool @\libglobal{is_array_v}@ = is_array::value; - template - inline constexpr bool @\libglobal{is_pointer_v}@ = is_pointer::value; - template - inline constexpr bool @\libglobal{is_lvalue_reference_v}@ = is_lvalue_reference::value; - template - inline constexpr bool @\libglobal{is_rvalue_reference_v}@ = is_rvalue_reference::value; - template - inline constexpr bool @\libglobal{is_member_object_pointer_v}@ = is_member_object_pointer::value; - template - inline constexpr bool @\libglobal{is_member_function_pointer_v}@ = is_member_function_pointer::value; - template - inline constexpr bool @\libglobal{is_enum_v}@ = is_enum::value; - template - inline constexpr bool @\libglobal{is_union_v}@ = is_union::value; - template - inline constexpr bool @\libglobal{is_class_v}@ = is_class::value; - template - inline constexpr bool @\libglobal{is_function_v}@ = is_function::value; - - // \ref{meta.unary.comp}, composite type categories - template - inline constexpr bool @\libglobal{is_reference_v}@ = is_reference::value; - template - inline constexpr bool @\libglobal{is_arithmetic_v}@ = is_arithmetic::value; - template - inline constexpr bool @\libglobal{is_fundamental_v}@ = is_fundamental::value; - template - inline constexpr bool @\libglobal{is_object_v}@ = is_object::value; - template - inline constexpr bool @\libglobal{is_scalar_v}@ = is_scalar::value; - template - inline constexpr bool @\libglobal{is_compound_v}@ = is_compound::value; - template - inline constexpr bool @\libglobal{is_member_pointer_v}@ = is_member_pointer::value; - - // \ref{meta.unary.prop}, type properties - template - inline constexpr bool @\libglobal{is_const_v}@ = is_const::value; - template - inline constexpr bool @\libglobal{is_volatile_v}@ = is_volatile::value; - template - inline constexpr bool @\libglobal{is_trivial_v}@ = is_trivial::value; - template - inline constexpr bool @\libglobal{is_trivially_copyable_v}@ = is_trivially_copyable::value; - template - inline constexpr bool @\libglobal{is_standard_layout_v}@ = is_standard_layout::value; - template - inline constexpr bool @\libglobal{is_empty_v}@ = is_empty::value; - template - inline constexpr bool @\libglobal{is_polymorphic_v}@ = is_polymorphic::value; - template - inline constexpr bool @\libglobal{is_abstract_v}@ = is_abstract::value; - template - inline constexpr bool @\libglobal{is_final_v}@ = is_final::value; - template - inline constexpr bool @\libglobal{is_aggregate_v}@ = is_aggregate::value; - template - inline constexpr bool @\libglobal{is_signed_v}@ = is_signed::value; - template - inline constexpr bool @\libglobal{is_unsigned_v}@ = is_unsigned::value; - template - inline constexpr bool @\libglobal{is_bounded_array_v}@ = is_bounded_array::value; - template - inline constexpr bool @\libglobal{is_unbounded_array_v}@ = is_unbounded_array::value; - template - inline constexpr bool @\libglobal{is_scoped_enum_v}@ = is_scoped_enum::value; - template - inline constexpr bool @\libglobal{is_constructible_v}@ = is_constructible::value; - template - inline constexpr bool @\libglobal{is_default_constructible_v}@ = is_default_constructible::value; - template - inline constexpr bool @\libglobal{is_copy_constructible_v}@ = is_copy_constructible::value; - template - inline constexpr bool @\libglobal{is_move_constructible_v}@ = is_move_constructible::value; - template - inline constexpr bool @\libglobal{is_assignable_v}@ = is_assignable::value; - template - inline constexpr bool @\libglobal{is_copy_assignable_v}@ = is_copy_assignable::value; - template - inline constexpr bool @\libglobal{is_move_assignable_v}@ = is_move_assignable::value; - template - inline constexpr bool @\libglobal{is_swappable_with_v}@ = is_swappable_with::value; - template - inline constexpr bool @\libglobal{is_swappable_v}@ = is_swappable::value; - template - inline constexpr bool @\libglobal{is_destructible_v}@ = is_destructible::value; - template - inline constexpr bool is_trivially_constructible_v - = is_trivially_constructible::value; - template - inline constexpr bool is_trivially_default_constructible_v - = is_trivially_default_constructible::value; - template - inline constexpr bool is_trivially_copy_constructible_v - = is_trivially_copy_constructible::value; - template - inline constexpr bool is_trivially_move_constructible_v - = is_trivially_move_constructible::value; - template - inline constexpr bool @\libglobal{is_trivially_assignable_v}@ = is_trivially_assignable::value; - template - inline constexpr bool is_trivially_copy_assignable_v - = is_trivially_copy_assignable::value; - template - inline constexpr bool is_trivially_move_assignable_v - = is_trivially_move_assignable::value; - template - inline constexpr bool @\libglobal{is_trivially_destructible_v}@ = is_trivially_destructible::value; - template - inline constexpr bool is_nothrow_constructible_v - = is_nothrow_constructible::value; - template - inline constexpr bool is_nothrow_default_constructible_v - = is_nothrow_default_constructible::value; - template - inline constexpr bool is_nothrow_copy_constructible_v - = is_nothrow_copy_constructible::value; - template - inline constexpr bool is_nothrow_move_constructible_v - = is_nothrow_move_constructible::value; - template - inline constexpr bool @\libglobal{is_nothrow_assignable_v}@ = is_nothrow_assignable::value; - template - inline constexpr bool @\libglobal{is_nothrow_copy_assignable_v}@ = is_nothrow_copy_assignable::value; - template - inline constexpr bool @\libglobal{is_nothrow_move_assignable_v}@ = is_nothrow_move_assignable::value; - template - inline constexpr bool @\libglobal{is_nothrow_swappable_with_v}@ = is_nothrow_swappable_with::value; - template - inline constexpr bool @\libglobal{is_nothrow_swappable_v}@ = is_nothrow_swappable::value; - template - inline constexpr bool @\libglobal{is_nothrow_destructible_v}@ = is_nothrow_destructible::value; - template - inline constexpr bool @\libglobal{has_virtual_destructor_v}@ = has_virtual_destructor::value; - template - inline constexpr bool has_unique_object_representations_v - = has_unique_object_representations::value; - template - inline constexpr bool @\libglobal{reference_constructs_from_temporary_v}@ - = reference_constructs_from_temporary::value; - template - inline constexpr bool @\libglobal{reference_converts_from_temporary_v}@ - = reference_converts_from_temporary::value; - - // \ref{meta.unary.prop.query}, type property queries - template - inline constexpr size_t @\libglobal{alignment_of_v}@ = alignment_of::value; - template - inline constexpr size_t @\libglobal{rank_v}@ = rank::value; - template - inline constexpr size_t @\libglobal{extent_v}@ = extent::value; - - // \ref{meta.rel}, type relations - template - inline constexpr bool @\libglobal{is_same_v}@ = is_same::value; - template - inline constexpr bool @\libglobal{is_base_of_v}@ = is_base_of::value; - template - inline constexpr bool @\libglobal{is_convertible_v}@ = is_convertible::value; - template - inline constexpr bool @\libglobal{is_nothrow_convertible_v}@ = is_nothrow_convertible::value; - template - inline constexpr bool @\libglobal{is_layout_compatible_v}@ = is_layout_compatible::value; - template - inline constexpr bool is_pointer_interconvertible_base_of_v - = is_pointer_interconvertible_base_of::value; - template - inline constexpr bool @\libglobal{is_invocable_v}@ = is_invocable::value; - template - inline constexpr bool @\libglobal{is_invocable_r_v}@ = is_invocable_r::value; - template - inline constexpr bool @\libglobal{is_nothrow_invocable_v}@ = is_nothrow_invocable::value; - template - inline constexpr bool is_nothrow_invocable_r_v - = is_nothrow_invocable_r::value; - - // \ref{meta.logical}, logical operator traits - template - inline constexpr bool @\libglobal{conjunction_v}@ = conjunction::value; - template - inline constexpr bool @\libglobal{disjunction_v}@ = disjunction::value; - template - inline constexpr bool @\libglobal{negation_v}@ = negation::value; - - // \ref{meta.member}, member relationships - template - constexpr bool is_pointer_interconvertible_with_class(M S::*m) noexcept; - template - constexpr bool is_corresponding_member(M1 S1::*m1, M2 S2::*m2) noexcept; - - // \ref{meta.const.eval}, constant evaluation context - constexpr bool is_constant_evaluated() noexcept; -} -\end{codeblock} - -\rSec2[meta.help]{Helper classes} - -\indexlibrarymember{value_type}{integral_constant}% -\begin{codeblock} -namespace std { - template struct integral_constant { - static constexpr T value = v; - - using value_type = T; - using type = integral_constant; - - constexpr operator value_type() const noexcept { return value; } - constexpr value_type operator()() const noexcept { return value; } - }; -} -\end{codeblock} - -\indexlibraryglobal{integral_constant}% -\indexlibraryglobal{bool_constant}% -\indexlibraryglobal{true_type}% -\indexlibraryglobal{false_type}% -\pnum -The class template \tcode{integral_constant}, -alias template \tcode{bool_constant}, and -its associated \grammarterm{typedef-name}{s} -\tcode{true_type} and \tcode{false_type} -are used as base classes to define -the interface for various type traits. - -\rSec2[meta.unary]{Unary type traits} - -\rSec3[meta.unary.general]{General} - -\pnum -Subclause \ref{meta.unary} contains templates that may be used to query the -properties of a type at compile time. - -\pnum -Each of these templates shall be a -\oldconcept{UnaryTypeTrait}\iref{meta.rqmts} -with a base characteristic of -\tcode{true_type} if the corresponding condition is \tcode{true}, otherwise -\tcode{false_type}. - -\rSec3[meta.unary.cat]{Primary type categories} - -\pnum -The primary type categories correspond to the descriptions given in -subclause~\ref{basic.types} of the \Cpp{} standard. - -\pnum -For any given type \tcode{T}, the result of applying one of these templates to -\tcode{T} and to \cv{}~\tcode{T} shall yield the same result. - -\pnum -\begin{note} -For any given type \tcode{T}, exactly one of the primary type categories -has a \tcode{value} member that evaluates to \tcode{true}. -\end{note} - -\begin{libreqtab3e}{Primary type category predicates}{meta.unary.cat} -\\ \topline -\lhdr{Template} & \chdr{Condition} & \rhdr{Comments} \\\capsep -\endfirsthead -\continuedcaption\\ -\topline -\lhdr{Template} & \chdr{Condition} & \rhdr{Comments} \\ \capsep -\endhead -\indexlibraryglobal{is_void}% -\tcode{template}\br - \tcode{struct is_void;} & -\tcode{T} is \keyword{void} & \\ \rowsep -\indexlibraryglobal{is_null_pointer}% -\tcode{template}\br - \tcode{struct is_null_pointer;} & -\tcode{T} is \tcode{nullptr_t}\iref{basic.fundamental} & \\ \rowsep -\indexlibraryglobal{is_integral}% -\tcode{template}\br - \tcode{struct is_integral;} & -\tcode{T} is an integral type\iref{basic.fundamental} & \\ \rowsep -\indexlibraryglobal{is_floating_point}% -\tcode{template}\br - \tcode{struct is_floating_point;} & -\tcode{T} is a floating-point type\iref{basic.fundamental} & \\ \rowsep -\indexlibraryglobal{is_array}% -\tcode{template}\br - \tcode{struct is_array;} & -\tcode{T} is an array type\iref{basic.compound} of known or unknown extent & -Class template \tcode{array}\iref{array} -is not an array type. \\ \rowsep -\indexlibraryglobal{is_pointer}% -\tcode{template}\br - \tcode{struct is_pointer;} & -\tcode{T} is a pointer type\iref{basic.compound} & -Includes pointers to functions -but not pointers to non-static members. \\ \rowsep -\indexlibraryglobal{is_lvalue_reference}% -\tcode{template}\br - \tcode{struct is_lvalue_reference;} & - \tcode{T} is an lvalue reference type\iref{dcl.ref} & \\ \rowsep -\indexlibraryglobal{is_rvalue_reference}% -\tcode{template}\br - \tcode{struct is_rvalue_reference;} & - \tcode{T} is an rvalue reference type\iref{dcl.ref} & \\ \rowsep -\indexlibraryglobal{is_member_object_pointer}% -\tcode{template}\br - \tcode{struct is_member_object_pointer;}& - \tcode{T} is a pointer to data member & \\ \rowsep -\indexlibraryglobal{is_member_function_pointer}% -\tcode{template}\br - \tcode{struct is_member_function_pointer;}& -\tcode{T} is a pointer to member function & \\ \rowsep -\indexlibraryglobal{is_enum}% -\tcode{template}\br - \tcode{struct is_enum;} & -\tcode{T} is an enumeration type\iref{basic.compound} & \\ \rowsep -\indexlibraryglobal{is_union}% -\tcode{template}\br - \tcode{struct is_union;} & -\tcode{T} is a union type\iref{basic.compound} & \\ \rowsep -\indexlibraryglobal{is_class}% -\tcode{template}\br - \tcode{struct is_class;} & -\tcode{T} is a non-union class type\iref{basic.compound} & \\ \rowsep -\indexlibraryglobal{is_function}% -\tcode{template}\br - \tcode{struct is_function;} & -\tcode{T} is a function type\iref{basic.compound} & \\ -\end{libreqtab3e} - -\rSec3[meta.unary.comp]{Composite type traits} - -\pnum -These templates provide convenient compositions of the primary type -categories, corresponding to the descriptions given in subclause~\ref{basic.types}. - -\pnum -For any given type \tcode{T}, the result of applying one of these templates to -\tcode{T} and to \cv{}~\tcode{T} shall yield the same result. - -\begin{libreqtab3b}{Composite type category predicates}{meta.unary.comp} -\\ \topline -\lhdr{Template} & \chdr{Condition} & \rhdr{Comments} \\ \capsep -\endfirsthead -\continuedcaption\\ -\topline -\lhdr{Template} & \chdr{Condition} & \rhdr{Comments} \\ \capsep -\endhead -\indexlibraryglobal{is_reference}% -\tcode{template}\br - \tcode{struct is_reference;} & - \tcode{T} is an lvalue reference or an rvalue reference & \\ \rowsep -\indexlibraryglobal{is_arithmetic}% -\tcode{template}\br - \tcode{struct is_arithmetic;} & - \tcode{T} is an arithmetic type\iref{basic.fundamental} & \\ \rowsep -\indexlibraryglobal{is_fundamental}% -\tcode{template}\br - \tcode{struct is_fundamental;} & - \tcode{T} is a fundamental type\iref{basic.fundamental} & \\ \rowsep -\indexlibraryglobal{is_object}% -\tcode{template}\br - \tcode{struct is_object;} & - \tcode{T} is an object type\iref{term.object.type} & \\ \rowsep -\indexlibraryglobal{is_scalar}% -\tcode{template}\br - \tcode{struct is_scalar;} & - \tcode{T} is a scalar type\iref{term.scalar.type} & \\ \rowsep -\indexlibraryglobal{is_compound}% -\tcode{template}\br - \tcode{struct is_compound;} & - \tcode{T} is a compound type\iref{basic.compound} & \\ \rowsep -\indexlibraryglobal{is_member_pointer}% -\tcode{template}\br - \tcode{struct is_member_pointer;} & - \tcode{T} is a pointer-to-member type\iref{basic.compound} & \\ -\end{libreqtab3b} - -\rSec3[meta.unary.prop]{Type properties} - -\pnum -These templates provide access to some of the more important -properties of types. - -\pnum -It is unspecified whether the library defines any full or partial -specializations of any of these templates. - -\pnum -For all of the class templates \tcode{X} declared in this subclause, -instantiating that template with a template-argument that is a class -template specialization may result in the implicit instantiation of -the template argument if and only if the semantics of \tcode{X} require that -the argument is a complete type. - -\pnum -For the purpose of defining the templates in this subclause, -a function call expression \tcode{declval()} for any type \tcode{T} -is considered to be a trivial\iref{term.trivial.type,special} function call -that is not an odr-use\iref{term.odr.use} of \tcode{declval} -in the context of the corresponding definition -notwithstanding the restrictions of~\ref{declval}. - -\pnum -For the purpose of defining the templates in this subclause, -let \tcode{\placeholdernc{VAL}} for some type \tcode{T} be -an expression defined as follows: -\begin{itemize} -\item -If \tcode{T} is a reference or function type, -\tcode{\placeholdernc{VAL}} is an expression -with the same type and value category as \tcode{declval()}. -\item -Otherwise, \tcode{\placeholdernc{VAL}} is a prvalue -that initially has type \tcode{T}. -\begin{note} -If \tcode{T} is cv-qualified, -the cv-qualification is subject to adjustment\iref{expr.type}. -\end{note} -\end{itemize} - -\begin{libreqtab3b}{Type property predicates}{meta.unary.prop} -\\ \topline -\lhdr{Template} & \chdr{Condition} & \rhdr{Preconditions} \\ \capsep -\endfirsthead -\continuedcaption\\ -\topline -\lhdr{Template} & \chdr{Condition} & \rhdr{Preconditions} \\ \capsep -\endhead - -\indexlibraryglobal{is_const}% -\tcode{template}\br - \tcode{struct is_const;} & - \tcode{T} is const-qualified\iref{basic.type.qualifier} & \\ \rowsep - -\indexlibraryglobal{is_volatile}% -\tcode{template}\br - \tcode{struct is_volatile;} & - \tcode{T} is volatile-qualified\iref{basic.type.qualifier} & \\ \rowsep - - -\indexlibraryglobal{is_trivial}% -\tcode{template}\br - \tcode{struct is_trivial;} & - \tcode{T} is a trivial type\iref{term.trivial.type} & - \tcode{remove_all_extents_t} shall be a complete - type or \cv{}~\keyword{void}. \\ \rowsep - -\indexlibraryglobal{is_trivially_copyable}% -\tcode{template}\br - \tcode{struct is_trivially_copyable;} & - \tcode{T} is a trivially copyable type\iref{term.trivially.copyable.type} & - \tcode{remove_all_extents_t} shall be a complete type or - \cv{}~\keyword{void}. \\ \rowsep - -\indexlibraryglobal{is_standard_layout}% -\tcode{template}\br - \tcode{struct is_standard_layout;} & - \tcode{T} is a standard-layout type\iref{term.standard.layout.type} & - \tcode{remove_all_extents_t} shall be a complete - type or \cv{}~\keyword{void}. \\ \rowsep - -\indexlibrary{\idxcode{is_empty}!class}% -\tcode{template}\br - \tcode{struct is_empty;} & - \tcode{T} is a class type, but not a union type, with no non-static data - members other than subobjects of zero size, no virtual member functions, - no virtual base classes, and no base class \tcode{B} for - which \tcode{is_empty_v} is \tcode{false}. & - If \tcode{T} is a non-union class type, \tcode{T} shall be a complete type. \\ \rowsep - -\indexlibraryglobal{is_polymorphic}% -\tcode{template}\br - \tcode{struct is_polymorphic;} & - \tcode{T} is a polymorphic class\iref{class.virtual} & - If \tcode{T} is a non-union class type, \tcode{T} shall be a complete type. \\ \rowsep - -\indexlibraryglobal{is_abstract}% -\tcode{template}\br - \tcode{struct is_abstract;} & - \tcode{T} is an abstract class\iref{class.abstract} & - If \tcode{T} is a non-union class type, \tcode{T} shall be a complete type. \\ \rowsep - -\indexlibraryglobal{is_final}% -\tcode{template}\br - \tcode{struct is_final;} & - \tcode{T} is a class type marked with the \grammarterm{class-virt-specifier} - \tcode{final}\iref{class.pre}. -\begin{tailnote} -A union is a class type that - can be marked with \tcode{final}. -\end{tailnote} -& - If \tcode{T} is a class type, \tcode{T} shall be a complete type. \\ \rowsep - -\indexlibraryglobal{is_aggregate}% -\tcode{template}\br - \tcode{struct is_aggregate;} & - \tcode{T} is an aggregate type\iref{dcl.init.aggr} & - \tcode{remove_all_extents_t} shall be a complete type or \cv~\keyword{void}. \\ \rowsep - -\indexlibrary{\idxcode{is_signed}!class}% -\tcode{template}\br - \tcode{struct is_signed;} & - If \tcode{is_arithmetic_v} is \tcode{true}, the same result as - \tcode{T(-1) < T(0)}; - otherwise, \tcode{false} & \\ \rowsep - -\indexlibraryglobal{is_unsigned}% -\tcode{template}\br - \tcode{struct is_unsigned;} & - If \tcode{is_arithmetic_v} is \tcode{true}, the same result as - \tcode{T(0) < T(-1)}; - otherwise, \tcode{false} & \\ \rowsep - -\indexlibraryglobal{is_bounded_array}% -\tcode{template}\br - \tcode{struct is_bounded_array;} & - \tcode{T} is an array type of known bound\iref{dcl.array} - & \\ \rowsep - -\indexlibraryglobal{is_unbounded_array}% -\tcode{template}\br - \tcode{struct is_unbounded_array;} & - \tcode{T} is an array type of unknown bound\iref{dcl.array} - & \\ \rowsep - -\indexlibraryglobal{is_scoped_enum}% -\tcode{template}\br - \tcode{struct is_scoped_enum;} & - \tcode{T} is a scoped enumeration\iref{dcl.enum} - & \\ \rowsep - -\indexlibraryglobal{is_constructible}% -\tcode{template}\br - \tcode{struct is_constructible;} & - For a function type \tcode{T} or - for a \cv{}~\keyword{void} type \tcode{T}, - \tcode{is_constructible_v} is \tcode{false}, - otherwise \seebelow & - \tcode{T} and all types in the template parameter pack \tcode{Args} - shall be complete types, \cv{}~\keyword{void}, - or arrays of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_default_constructible}% -\tcode{template}\br - \tcode{struct is_default_constructible;} & - \tcode{is_constructible_v} is \tcode{true}. & - \tcode{T} shall be a complete type, \cv{}~\keyword{void}, - or an array of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_copy_constructible}% -\tcode{template}\br - \tcode{struct is_copy_constructible;} & - For a referenceable type \tcode{T}\iref{defns.referenceable}, the same result as - \tcode{is_constructible_v}, otherwise \tcode{false}. & - \tcode{T} shall be a complete type, \cv{}~\keyword{void}, - or an array of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_move_constructible}% -\tcode{template}\br - \tcode{struct is_move_constructible;} & - For a referenceable type \tcode{T}, the same result as - \tcode{is_constructible_v}, otherwise \tcode{false}. & - \tcode{T} shall be a complete type, \cv{}~\keyword{void}, - or an array of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_assignable}% -\tcode{template}\br - \tcode{struct is_assignable;} & - The expression \tcode{declval() =} \tcode{declval()} is well-formed - when treated as an unevaluated - operand\iref{term.unevaluated.operand}. Access checking is performed as if in a context - unrelated to \tcode{T} and \tcode{U}. Only the validity of the immediate context - of the assignment expression is considered. -\begin{tailnote} -The compilation of the - expression can result in side effects such as the instantiation of class template - specializations and function template specializations, the generation of - implicitly-defined functions, and so on. Such side effects are not in the ``immediate - context'' and can result in the program being ill-formed. -\end{tailnote} -& - \tcode{T} and \tcode{U} shall be complete types, \cv{}~\keyword{void}, - or arrays of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_copy_assignable}% -\tcode{template}\br - \tcode{struct is_copy_assignable;} & - For a referenceable type \tcode{T}, the same result as - \tcode{is_assignable_v}, otherwise \tcode{false}. & - \tcode{T} shall be a complete type, \cv{}~\keyword{void}, - or an array of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_move_assignable}% -\tcode{template}\br - \tcode{struct is_move_assignable;} & - For a referenceable type \tcode{T}, the same result as - \tcode{is_assignable_v}, otherwise \tcode{false}. & - \tcode{T} shall be a complete type, \cv{}~\keyword{void}, - or an array of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_swappable_with}% -\tcode{template}\br - \tcode{struct is_swappable_with;} & - The expressions \tcode{swap(declval(), declval())} and - \tcode{swap(declval(), declval())} are each well-formed - when treated as an unevaluated operand\iref{term.unevaluated.operand} - in an overload-resolution context - for swappable values\iref{swappable.requirements}. - Access checking is performed as if in a context - unrelated to \tcode{T} and \tcode{U}. - Only the validity of the immediate context - of the \tcode{swap} expressions is considered. - \begin{tailnote} - The compilation of the expressions can result in side effects - such as the instantiation of class template specializations and - function template specializations, - the generation of implicitly-defined functions, and so on. - Such side effects are not in the ``immediate context'' and - can result in the program being ill-formed. - \end{tailnote} -& - \tcode{T} and \tcode{U} shall be complete types, - \cv{}~\keyword{void}, or - arrays of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_swappable}% -\tcode{template}\br - \tcode{struct is_swappable;} & - For a referenceable type \tcode{T}, - the same result as \tcode{is_swappable_with_v}, - otherwise \tcode{false}. & - \tcode{T} shall be a complete type, - \cv{}~\keyword{void}, or - an array of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_destructible}% -\tcode{template}\br - \tcode{struct is_destructible;} & - Either \tcode{T} is a reference type, - or \tcode{T} is a complete object type - for which the expression - \tcode{declval().\~U()} - is well-formed - when treated as an unevaluated operand\iref{term.unevaluated.operand}, - where \tcode{U} is - \tcode{remove_all_extents_t}. & - \tcode{T} shall be a complete type, \cv{}~\keyword{void}, - or an array of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_trivially_constructible}% -\tcode{template}\br - \keyword{struct}\br - \tcode{is_trivially_constructible;} & - \tcode{is_constructible_v} is \tcode{true} and the variable - definition for \tcode{is_constructible}, as defined below, is known to call - no operation that is not trivial\iref{term.trivial.type,special}. & - \tcode{T} and all types in the template parameter pack \tcode{Args} shall be complete types, - \cv{}~\keyword{void}, or arrays of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_trivially_default_constructible}% -\tcode{template}\br - \tcode{struct is_trivially_default_constructible;} & - \tcode{is_trivially_constructible_v} is \tcode{true}. & - \tcode{T} shall be a complete type, - \cv{}~\keyword{void}, or an array of unknown - bound. \\ \rowsep - -\indexlibraryglobal{is_trivially_copy_constructible}% -\tcode{template}\br - \tcode{struct is_trivially_copy_constructible;} & - For a referenceable type \tcode{T}, the same result as - \tcode{is_trivially_constructible_v}, otherwise \tcode{false}. & - \tcode{T} shall be a complete type, - \cv{}~\keyword{void}, or an array of unknown - bound. \\ \rowsep - -\indexlibraryglobal{is_trivially_move_constructible}% -\tcode{template}\br - \tcode{struct is_trivially_move_constructible;} & - For a referenceable type \tcode{T}, the same result as - \tcode{is_trivially_constructible_v}, otherwise \tcode{false}. & - \tcode{T} shall be a complete type, - \cv{}~\keyword{void}, or an array of unknown - bound. \\ \rowsep - -\indexlibraryglobal{is_trivially_assignable}% -\tcode{template}\br - \tcode{struct is_trivially_assignable;} & - \tcode{is_assignable_v} is \tcode{true} and the assignment, as defined by - \tcode{is_assignable}, is known to call no operation that is not - trivial\iref{term.trivial.type,special}. & - \tcode{T} and \tcode{U} shall be complete types, \cv{}~\keyword{void}, - or arrays of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_trivially_copy_assignable}% -\tcode{template}\br - \tcode{struct is_trivially_copy_assignable;} & - For a referenceable type \tcode{T}, the same result as - \tcode{is_trivially_assignable_v}, otherwise \tcode{false}. & - \tcode{T} shall be a complete type, - \cv{}~\keyword{void}, or an array of unknown - bound. \\ \rowsep - -\indexlibraryglobal{is_trivially_move_assignable}% -\tcode{template}\br - \tcode{struct is_trivially_move_assignable;} & - For a referenceable type \tcode{T}, the same result as - \tcode{is_trivially_assignable_v}, otherwise \tcode{false}. & - \tcode{T} shall be a complete type, - \cv{}~\keyword{void}, or an array of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_trivially_destructible}% -\tcode{template}\br - \tcode{struct is_trivially_destructible;} & - \tcode{is_destructible_v} is \tcode{true} and - \tcode{remove_all_extents_t} is either a non-class type or - a class type with a trivial destructor. & - \tcode{T} shall be a complete type, - \cv{}~\keyword{void}, or an array of unknown - bound. \\ \rowsep - -\indexlibraryglobal{is_nothrow_constructible}% -\tcode{template}\br - \tcode{struct is_nothrow_constructible;} & - \tcode{is_constructible_v} is \tcode{true} - and the - variable definition for \tcode{is_constructible}, as defined below, is known not to - throw any exceptions\iref{expr.unary.noexcept}. - & - \tcode{T} and all types in the template parameter pack \tcode{Args} - shall be complete types, \cv{}~\keyword{void}, - or arrays of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_nothrow_default_constructible}% -\tcode{template}\br - \tcode{struct is_nothrow_default_constructible;} & - \tcode{is_nothrow_constructible_v} is \tcode{true}. & - \tcode{T} shall be a complete type, - \cv{}~\keyword{void}, or an array of unknown - bound. \\ \rowsep - -\indexlibraryglobal{is_nothrow_copy_constructible}% -\tcode{template}\br - \tcode{struct is_nothrow_copy_constructible;} & - For a referenceable type \tcode{T}, the same result as - \tcode{is_nothrow_constructible_v}, otherwise \tcode{false}. & - \tcode{T} shall be a complete type, - \cv{}~\keyword{void}, or an array of unknown - bound. \\ \rowsep - -\indexlibraryglobal{is_nothrow_move_constructible}% -\tcode{template}\br - \tcode{struct is_nothrow_move_constructible;} & - For a referenceable type \tcode{T}, the same result as - \tcode{is_nothrow_constructible_v}, otherwise \tcode{false}. & - \tcode{T} shall be a complete type, - \cv{}~\keyword{void}, or an array of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_nothrow_assignable}% -\tcode{template}\br - \tcode{struct is_nothrow_assignable;} & - \tcode{is_assignable_v} is \tcode{true} and the assignment is known not to - throw any exceptions\iref{expr.unary.noexcept}. & - \tcode{T} and \tcode{U} shall be complete types, \cv{}~\keyword{void}, - or arrays of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_nothrow_copy_assignable}% -\tcode{template}\br - \tcode{struct is_nothrow_copy_assignable;} & - For a referenceable type \tcode{T}, the same result as - \tcode{is_nothrow_assignable_v}, otherwise \tcode{false}. & - \tcode{T} shall be a complete type, - \cv{}~\keyword{void}, or an array of unknown - bound. \\ \rowsep - -\indexlibraryglobal{is_nothrow_move_assignable}% -\tcode{template}\br - \tcode{struct is_nothrow_move_assignable;} & - For a referenceable type \tcode{T}, the same result as - \tcode{is_nothrow_assignable_v}, otherwise \tcode{false}. & - \tcode{T} shall be a complete type, - \cv{}~\keyword{void}, or an array of unknown - bound. \\ \rowsep - -\indexlibraryglobal{is_nothrow_swappable_with}% -\tcode{template}\br - \tcode{struct is_nothrow_swappable_with;} & - \tcode{is_swappable_with_v} is \tcode{true} and - each \tcode{swap} expression of the definition of - \tcode{is_swappable_with} is known not to throw - any exceptions\iref{expr.unary.noexcept}. & - \tcode{T} and \tcode{U} shall be complete types, - \cv{}~\keyword{void}, or - arrays of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_nothrow_swappable}% -\tcode{template}\br - \tcode{struct is_nothrow_swappable;} & - For a referenceable type \tcode{T}, - the same result as \tcode{is_nothrow_swappable_with_v}, - otherwise \tcode{false}. & - \tcode{T} shall be a complete type, - \cv{}~\keyword{void}, or - an array of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_nothrow_destructible}% -\tcode{template}\br - \tcode{struct is_nothrow_destructible;} & - \tcode{is_destructible_v} is \tcode{true} and the indicated destructor is known - not to throw any exceptions\iref{expr.unary.noexcept}. & - \tcode{T} shall be a complete type, - \cv{}~\keyword{void}, or an array of unknown - bound. \\ \rowsep - -\indexlibraryglobal{has_virtual_destructor}% -\tcode{template}\br - \tcode{struct has_virtual_destructor;} & - \tcode{T} has a virtual destructor\iref{class.dtor} & - If \tcode{T} is a non-union class type, \tcode{T} shall be a complete type. \\ \rowsep - -\indexlibraryglobal{has_unique_object_representations}% -\tcode{template}\br - \tcode{struct has_unique_object_representations;} & - For an array type \tcode{T}, the same result as - \tcode{has_unique_object_representations_v>}, - otherwise \seebelow. & - \tcode{T} shall be a complete type, \cv{}~\keyword{void}, or - an array of unknown bound. \\ \rowsep - -\indexlibraryglobal{reference_constructs_from_temporary}% -\tcode{template}\br - \tcode{struct reference_constructs_from_temporary;} & - \tcode{conjunction_v, is_constructible>} - is \tcode{true}, and - the initialization \tcode{T t(\exposidnc{VAL});} binds \tcode{t} to - a temporary object whose lifetime is extended\iref{class.temporary}. & - \tcode{T} and \tcode{U} shall be - complete types, \cv{}~\keyword{void}, or arrays of unknown bound. \\ \rowsep - -\indexlibraryglobal{reference_converts_from_temporary}% -\tcode{template}\br - \tcode{struct reference_converts_from_temporary;} & - \tcode{conjunction_v, is_convertible>} is \tcode{true}, - and the initialization \tcode{T t = \exposidnc{VAL};} binds \tcode{t} to - a temporary object whose lifetime is extended\iref{class.temporary}. & - \tcode{T} and \tcode{U} shall be - complete types, \cv{}~\keyword{void}, or arrays of unknown bound. \\ \rowsep - -\end{libreqtab3b} - -\pnum -\begin{example} -\begin{codeblock} -is_const_v // \tcode{true} -is_const_v // \tcode{false} -is_const_v // \tcode{false} -is_const_v // \tcode{false} -is_const_v // \tcode{true} -\end{codeblock} -\end{example} - -\pnum -\begin{example} -\begin{codeblock} -remove_const_t // \tcode{volatile int} -remove_const_t // \tcode{const int*} -remove_const_t // \tcode{const int\&} -remove_const_t // \tcode{int[3]} -\end{codeblock} -\end{example} - -\pnum -\begin{example} -\begin{codeblock} -// Given: -struct P final { }; -union U1 { }; -union U2 final { }; - -// the following assertions hold: -static_assert(!is_final_v); -static_assert(is_final_v

); -static_assert(!is_final_v); -static_assert(is_final_v); -\end{codeblock} -\end{example} - -\indexlibraryglobal{is_constructible}% -\pnum -The predicate condition for a template specialization -\tcode{is_constructible} shall be satisfied if and only if the -following variable definition would be well-formed for some invented variable \tcode{t}: - -\begin{codeblock} -T t(declval()...); -\end{codeblock} - -\begin{note} -These tokens are never interpreted as a function declaration. -\end{note} -Access checking is performed as if in a context unrelated to \tcode{T} -and any of the \tcode{Args}. Only the validity of the immediate context of the -variable initialization is considered. -\begin{note} -The evaluation of the -initialization can result in side effects such as the instantiation of class -template specializations and function template specializations, the generation -of implicitly-defined functions, and so on. Such side effects are not in the -``immediate context'' and can result in the program being ill-formed. -\end{note} - -\indexlibraryglobal{has_unique_object_representations}% -\pnum -The predicate condition for a template specialization -\tcode{has_unique_object_representations} -shall be satisfied if and only if: -\begin{itemize} -\item \tcode{T} is trivially copyable, and -\item any two objects of type \tcode{T} with the same value -have the same object representation, where -two objects of array or non-union class type are considered to have the same value -if their respective sequences of direct subobjects have the same values, and -two objects of union type are considered to have the same value -if they have the same active member and the corresponding members have the same value. -\end{itemize} -The set of scalar types for which this condition holds is -\impldef{which scalar types have unique object representations}. -\begin{note} -If a type has padding bits, the condition does not hold; -otherwise, the condition holds true for integral types. -\end{note} - -\rSec2[meta.unary.prop.query]{Type property queries} - -\pnum -This subclause contains templates that may be used to query -properties of types at compile time. - -\begin{libreqtab2a}{Type property queries}{meta.unary.prop.query} -\\ \topline -\lhdr{Template} & \rhdr{Value} \\ \capsep -\endfirsthead -\continuedcaption\\ -\topline -\lhdr{Template} & \rhdr{Value} \\ \capsep -\endhead - -\indexlibraryglobal{alignment_of}% -\tcode{template\br - struct alignment_of;} & - \tcode{alignof(T)}.\br - \mandates - \tcode{alignof(T)} is a valid expression\iref{expr.alignof} \\ \rowsep - -\indexlibraryglobal{rank}% -\tcode{template\br - struct rank;} & - If \tcode{T} names an array type, an integer value representing - the number of dimensions of \tcode{T}; otherwise, 0. \\ \rowsep - -\indexlibraryglobal{extent}% -\tcode{template\br - struct extent;} & - If \tcode{T} is not an array type, or if it has rank less - than or equal to \tcode{I}, or if \tcode{I} is 0 and \tcode{T} - has type ``array of unknown bound of \tcode{U}'', then - 0; otherwise, the bound\iref{dcl.array} of the $\tcode{I}^\text{th}$ dimension of -\tcode{T}, where indexing of \tcode{I} is zero-based \\ -\end{libreqtab2a} - -\pnum -Each of these templates shall be a \oldconcept{UnaryTypeTrait}\iref{meta.rqmts} with a -base characteristic of \tcode{integral_constant}. - -\pnum -\begin{example} -\begin{codeblock} -// the following assertions hold: -assert(rank_v == 0); -assert(rank_v == 1); -assert(rank_v == 2); -\end{codeblock} -\end{example} - -\pnum -\begin{example} -\begin{codeblock} -// the following assertions hold: -assert(extent_v == 0); -assert(extent_v == 2); -assert(extent_v == 2); -assert(extent_v == 0); -assert((extent_v) == 0); -assert((extent_v) == 0); -assert((extent_v) == 4); -assert((extent_v) == 4); -\end{codeblock} -\end{example} - -\rSec2[meta.rel]{Relationships between types} - -\pnum -This subclause contains templates that may be used to query -relationships between types at compile time. - -\pnum -Each of these templates shall be a -\oldconcept{BinaryTypeTrait}\iref{meta.rqmts} -with a base characteristic of -\tcode{true_type} if the corresponding condition is true, otherwise -\tcode{false_type}. - -\begin{libreqtab3f}{Type relationship predicates}{meta.rel} -\\ \topline -\lhdr{Template} & \chdr{Condition} & \rhdr{Comments} \\ \capsep -\endfirsthead -\continuedcaption\\ -\topline -\lhdr{Template} & \chdr{Condition} & \rhdr{Comments} \\ \capsep -\endhead -\tcode{template}\br - \tcode{struct is_same;} & - \tcode{T} and \tcode{U} name the same type with the same cv-qualifications & \\ \rowsep - -\indexlibraryglobal{is_base_of}% -\tcode{template}\br - \tcode{struct is_base_of;} & - \tcode{Base} is a base class of \tcode{Derived}\iref{class.derived} - without regard to cv-qualifiers - or \tcode{Base} and \tcode{Derived} are not unions and - name the same class type - without regard to cv-qualifiers & - If \tcode{Base} and - \tcode{Derived} are non-union class types and are -not possibly cv-qualified versions of the same type, - \tcode{Derived} shall be a complete - type. - \begin{tailnote} -Base classes that are private, protected, or ambiguous - are, nonetheless, base classes. -\end{tailnote} -\\ \rowsep - -\indexlibraryglobal{is_convertible}% -\tcode{template}\br - \tcode{struct is_convertible;} & - \seebelow & - \tcode{From} and \tcode{To} shall be complete types, - \cv{}~\keyword{void}, or arrays of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_nothrow_convertible}% -\tcode{template}\br - \tcode{struct is_nothrow_convertible;} & - \tcode{is_convertible_v} is \tcode{true} and - the conversion, as defined by \tcode{is_convertible}, - is known not to throw any exceptions\iref{expr.unary.noexcept} & - \tcode{From} and \tcode{To} shall be complete types, - \cv{}~\keyword{void}, or arrays of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_layout_compatible}% -\tcode{template}\br - \tcode{struct is_layout_compatible;} & - \tcode{T} and \tcode{U} are layout-compatible\iref{term.layout.compatible.type} & - \tcode{T} and \tcode{U} shall be complete types, - \cv{}~\keyword{void}, - or arrays of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_pointer_interconvertible_base_of}% -\tcode{template}\br - \tcode{struct is_pointer_interconvertible_base_of;} & - \tcode{Derived} is unambiguously derived from \tcode{Base} - without regard to cv-qualifiers, - and each object of type \tcode{Derived} - is pointer-interconvertible\iref{basic.compound} with - its \tcode{Base} subobject, - or \tcode{Base} and \tcode{Derived} are not unions - and name the same class type - without regard to cv-qualifiers. & - If \tcode{Base} and \tcode{Derived} are non-union class types - and are not (possibly cv-qualified versions of) the same type, - \tcode{Derived} shall be a complete type. \\ \rowsep - -\indexlibraryglobal{is_invocable}% -\tcode{template}\br - \tcode{struct is_invocable;} & - The expression \tcode{\placeholdernc{INVOKE}(declval(), declval()...)} - is well-formed when treated as an unevaluated operand\iref{term.unevaluated.operand} & - \tcode{Fn} and all types in the template parameter pack \tcode{ArgTypes} - shall be complete types, \cv{}~\keyword{void}, or - arrays of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_invocable_r}% -\tcode{template}\br - \tcode{struct is_invocable_r;} & - The expression \tcode{\placeholdernc{INVOKE}(declval(), declval()...)} - is well-formed when treated as an unevaluated operand & - \tcode{Fn}, \tcode{R}, and all types in the template parameter pack \tcode{ArgTypes} - shall be complete types, \cv{}~\keyword{void}, or - arrays of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_nothrow_invocable}% -\tcode{template}\br - \tcode{struct is_nothrow_invocable;} & - \tcode{is_invocable_v<}\br\tcode{Fn, ArgTypes...>} is \tcode{true} and - the expression \tcode{\placeholdernc{INVOKE}(declval(), declval()...)} - is known not to throw any exceptions\iref{expr.unary.noexcept} & - \tcode{Fn} and all types in the template parameter pack \tcode{ArgTypes} - shall be complete types, \cv{}~\keyword{void}, or - arrays of unknown bound. \\ \rowsep - -\indexlibraryglobal{is_nothrow_invocable_r}% -\tcode{template}\br - \tcode{struct is_nothrow_invocable_r;} & - \tcode{is_invocable_r_v<}\br\tcode{R, Fn, ArgTypes...>} is \tcode{true} and - the expression \tcode{\placeholdernc{INVOKE}(declval(), declval()...)} - is known not to throw any exceptions\iref{expr.unary.noexcept} & - \tcode{Fn}, \tcode{R}, and all types in the template parameter pack \tcode{ArgTypes} - shall be complete types, \cv{}~\keyword{void}, or - arrays of unknown bound. \\ -\end{libreqtab3f} - -\pnum -For the purpose of defining the templates in this subclause, -a function call expression \tcode{declval()} for any type \tcode{T} -is considered to be a trivial\iref{term.trivial.type,special} function call -that is not an odr-use\iref{term.odr.use} of \tcode{declval} -in the context of the corresponding definition -notwithstanding the restrictions of~\ref{declval}. - -\pnum -\begin{example} -\begin{codeblock} -struct B {}; -struct B1 : B {}; -struct B2 : B {}; -struct D : private B1, private B2 {}; - -is_base_of_v // \tcode{true} -is_base_of_v // \tcode{true} -is_base_of_v // \tcode{true} -is_base_of_v // \tcode{true} -is_base_of_v // \tcode{false} -is_base_of_v // \tcode{false} -is_base_of_v // \tcode{false} -is_base_of_v // \tcode{false} -\end{codeblock} -\end{example} - -\indexlibraryglobal{is_convertible}% -\pnum -The predicate condition for a template specialization \tcode{is_convertible} -shall be satisfied if and only if the return expression in the following code would be -well-formed, including any implicit conversions to the return type of the function: - -\begin{codeblock} -To test() { - return declval(); -} -\end{codeblock} - -\begin{note} -This requirement gives well-defined results for reference types, -array types, function types, and \cv{}~\keyword{void}. -\end{note} -Access checking is performed -in a context unrelated to \tcode{To} and \tcode{From}. Only the validity of -the immediate context of the \grammarterm{expression} of the \tcode{return} statement\iref{stmt.return} -(including initialization of the returned object or reference) is considered. -\begin{note} -The -initialization can result in side effects such as the -instantiation of class template specializations and function template -specializations, the generation of implicitly-defined functions, and so on. Such -side effects are not in the ``immediate context'' and can result in the program -being ill-formed. -\end{note} - -\rSec2[meta.trans]{Transformations between types} - -\rSec3[meta.trans.general]{General} -\pnum -Subclause \ref{meta.trans} contains templates that may be used to transform one -type to another following some predefined rule. - -\pnum -Each of the templates in \ref{meta.trans} shall be a -\oldconcept{TransformationTrait}\iref{meta.rqmts}. - -\rSec3[meta.trans.cv]{Const-volatile modifications} - -\begin{libreqtab2a}{Const-volatile modifications}{meta.trans.cv} -\\ \topline -\lhdr{Template} & \rhdr{Comments} \\ \capsep -\endfirsthead -\continuedcaption\\ -\topline -\lhdr{Template} & \rhdr{Comments} \\ \capsep -\endhead - -\indexlibraryglobal{remove_const}% -\tcode{template\br - struct remove_const;} & - The member typedef \tcode{type} names - the same type as \tcode{T} - except that any top-level const-qualifier has been removed. - \begin{tailexample} -\tcode{remove_const_t} evaluates - to \tcode{volatile int}, whereas \tcode{remove_const_t} evaluates to - \tcode{const int*}. -\end{tailexample} -\\ \rowsep - -\indexlibraryglobal{remove_volatile}% -\tcode{template\br - struct remove_volatile;} & - The member typedef \tcode{type} names - the same type as \tcode{T} - except that any top-level volatile-qualifier has been removed. - \begin{tailexample} -\tcode{remove_volatile_t} - evaluates to \tcode{const int}, - whereas \tcode{remove_volatile_t} evaluates to \tcode{volatile int*}. - \end{tailexample} -\\ \rowsep - -\indexlibraryglobal{remove_cv}% -\tcode{template\br - struct remove_cv;} & - The member typedef \tcode{type} shall be the same as \tcode{T} - except that any top-level cv-qualifier has been removed. - \begin{tailexample} -\tcode{remove_cv_t} - evaluates to \tcode{int}, whereas \tcode{remove_cv_t} - evaluates to \tcode{const volatile int*}. -\end{tailexample} -\\ \rowsep - -\indexlibraryglobal{add_const}% -\tcode{template\br - struct add_const;} & - If \tcode{T} is a reference, function, or top-level const-qualified - type, then \tcode{type} names - the same type as \tcode{T}, otherwise - \tcode{T const}. \\ \rowsep - -\indexlibraryglobal{add_volatile}% -\tcode{template\br - struct add_volatile;} & - If \tcode{T} is a reference, function, or top-level volatile-qualified - type, then \tcode{type} names - the same type as \tcode{T}, otherwise - \tcode{T volatile}. \\ \rowsep - -\indexlibraryglobal{add_cv}% -\tcode{template\br - struct add_cv;} & - The member typedef \tcode{type} names - the same type as - \tcode{add_const_t>}. \\ -\end{libreqtab2a} - -\rSec3[meta.trans.ref]{Reference modifications} - -\begin{libreqtab2a}{Reference modifications}{meta.trans.ref} -\\ \topline -\lhdr{Template} & \rhdr{Comments} \\ \capsep -\endfirsthead -\continuedcaption\\ -\topline -\lhdr{Template} & \rhdr{Comments} \\ \capsep -\endhead - -\indexlibraryglobal{remove_reference}% -\tcode{template\br - struct remove_reference;} & - If \tcode{T} has type ``reference to \tcode{T1}'' then the - member typedef \tcode{type} names \tcode{T1}; - otherwise, \tcode{type} names \tcode{T}.\\ \rowsep - -\indexlibraryglobal{add_lvalue_reference}% -\tcode{template\br - struct add_lvalue_reference;} & - If \tcode{T} names a referenceable type\iref{defns.referenceable} then - the member typedef \tcode{type} names \tcode{T\&}; - otherwise, \tcode{type} names \tcode{T}. - \begin{tailnote} - This rule reflects the semantics of reference collapsing\iref{dcl.ref}. - \end{tailnote} -\\ \rowsep - -\indexlibraryglobal{add_rvalue_reference}% -\tcode{template}\br - \tcode{struct add_rvalue_reference;} & - If \tcode{T} names a referenceable type then - the member typedef \tcode{type} names \tcode{T\&\&}; - otherwise, \tcode{type} names \tcode{T}. - \begin{tailnote} -This rule reflects the semantics of reference collapsing\iref{dcl.ref}. - For example, when a type \tcode{T} names a type \tcode{T1\&}, the type - \tcode{add_rvalue_reference_t} is not an rvalue reference. - \end{tailnote} -\\ -\end{libreqtab2a} - -\rSec3[meta.trans.sign]{Sign modifications} -\begin{libreqtab2a}{Sign modifications}{meta.trans.sign} -\\ \topline -\lhdr{Template} & \rhdr{Comments} \\ \capsep -\endfirsthead -\continuedcaption\\ -\topline -\lhdr{Template} & \rhdr{Comments} \\ \capsep -\endhead - -\indexlibraryglobal{make_signed}% -\tcode{template}\br - \tcode{struct make_signed;} & - If \tcode{T} names a (possibly cv-qualified) signed integer - type\iref{basic.fundamental} then the member typedef - \tcode{type} names the type \tcode{T}; otherwise, - if \tcode{T} names a (possibly cv-qualified) unsigned integer - type then \tcode{type} names the corresponding - signed integer type, with the same cv-qualifiers as \tcode{T}; - otherwise, \tcode{type} names the signed integer type with smallest - rank\iref{conv.rank} for which - \tcode{sizeof(T) == sizeof(type)}, with the same - cv-qualifiers as \tcode{T}.\br - \mandates \tcode{T} is an integral or enumeration type - other than \cv~\tcode{bool}.\\ \rowsep - -\indexlibraryglobal{make_unsigned}% -\tcode{template}\br - \tcode{struct make_unsigned;} & - If \tcode{T} names a (possibly cv-qualified) unsigned integer - type\iref{basic.fundamental} then the member typedef - \tcode{type} names the type \tcode{T}; otherwise, - if \tcode{T} names a (possibly cv-qualified) signed integer - type then \tcode{type} names the corresponding - unsigned integer type, with the same cv-qualifiers as \tcode{T}; - otherwise, \tcode{type} names the unsigned integer type with smallest - rank\iref{conv.rank} for which - \tcode{sizeof(T) == sizeof(type)}, with the same - cv-qualifiers as \tcode{T}.\br - \mandates \tcode{T} is an integral or enumeration type - other than \cv~\tcode{bool}.\\ -\end{libreqtab2a} - -\rSec3[meta.trans.arr]{Array modifications} -\begin{libreqtab2a}{Array modifications}{meta.trans.arr} -\\ \topline -\lhdr{Template} & \rhdr{Comments} \\ \capsep -\endfirsthead -\continuedcaption\\ -\topline -\lhdr{Template} & \rhdr{Comments} \\ \capsep -\endhead - -\indexlibraryglobal{remove_extent}% -\tcode{template\br - struct remove_extent;} & - If \tcode{T} names a type ``array of \tcode{U}'', - the member typedef \tcode{type} shall - be \tcode{U}, otherwise \tcode{T}. - \begin{tailnote} -For multidimensional arrays, only the first array dimension is - removed. For a type ``array of \tcode{const U}'', the resulting type is - \tcode{const U}. -\end{tailnote} -\\ \rowsep - -\indexlibraryglobal{remove_all_extents}% -\tcode{template\br - struct remove_all_extents;} & - If \tcode{T} is ``multi-dimensional array of \tcode{U}'', the resulting member - typedef \tcode{type} is \tcode{U}, otherwise \tcode{T}. \\ -\end{libreqtab2a} - -\pnum -\begin{example} -\begin{codeblock} -// the following assertions hold: -assert((is_same_v, int>)); -assert((is_same_v, int>)); -assert((is_same_v, int[3]>)); -assert((is_same_v, int[3]>)); -\end{codeblock} -\end{example} - -\pnum -\begin{example} -\begin{codeblock} -// the following assertions hold: -assert((is_same_v, int>)); -assert((is_same_v, int>)); -assert((is_same_v, int>)); -assert((is_same_v, int>)); -\end{codeblock} -\end{example} - -\rSec3[meta.trans.ptr]{Pointer modifications} -\begin{libreqtab2a}{Pointer modifications}{meta.trans.ptr} -\\ \topline -\lhdr{Template} & \rhdr{Comments} \\ \capsep -\endfirsthead -\continuedcaption\\ -\topline -\lhdr{Template} & \rhdr{Comments} \\ \capsep -\endhead - -\indexlibraryglobal{remove_pointer}% -\tcode{template\br - struct remove_pointer;} & - If \tcode{T} has type ``(possibly cv-qualified) pointer - to \tcode{T1}'' then the member typedef \tcode{type} - names \tcode{T1}; otherwise, it names \tcode{T}.\\ \rowsep - -\indexlibraryglobal{add_pointer}% -\tcode{template\br - struct add_pointer;} & - If \tcode{T} names a referenceable type\iref{defns.referenceable} or a - \cv{}~\keyword{void} type then - the member typedef \tcode{type} names the same type as - \tcode{remove_reference_t*}; - otherwise, \tcode{type} names \tcode{T}. \\ -\end{libreqtab2a} - -\rSec3[meta.trans.other]{Other transformations} - -\begin{libreqtab2a}{Other transformations}{meta.trans.other} -\\ \topline -\lhdr{Template} & \rhdr{Comments} \\ \capsep -\endfirsthead -\continuedcaption\\ -\topline -\lhdr{Template} & \rhdr{Comments} \\ \capsep -\endhead - -\indexlibraryglobal{type_identity}% -\tcode{template\br - struct type_identity;} - & - The member typedef \tcode{type} names the type \tcode{T}. \\ \rowsep - -\indexlibraryglobal{remove_cvref}% -\tcode{template\br struct remove_cvref;} - & - The member typedef \tcode{type} names the same type as - \tcode{remove_cv_t>}. - \\ \rowsep - -\indexlibraryglobal{decay}% -\tcode{template\br struct decay;} - & - Let \tcode{U} be \tcode{remove_reference_t}. If \tcode{is_array_v} is - \tcode{true}, the member typedef \tcode{type} equals - \tcode{remove_extent_t*}. If \tcode{is_function_v} is \tcode{true}, - the member typedef \tcode{type} equals \tcode{add_pointer_t}. Otherwise - the member typedef \tcode{type} equals \tcode{remove_cv_t}. -\begin{tailnote} -This behavior is similar to the lvalue-to-rvalue\iref{conv.lval}, -array-to-pointer\iref{conv.array}, and function-to-pointer\iref{conv.func} -conversions applied when an lvalue is used as an rvalue, but also -strips cv-qualifiers from class types in order to more closely model by-value -argument passing. -\end{tailnote} - \\ \rowsep - -\indexlibraryglobal{enable_if}% -\tcode{template} \tcode{struct enable_if;} - & - If \tcode{B} is \tcode{true}, the member typedef \tcode{type} - shall equal \tcode{T}; otherwise, there shall be no member - \tcode{type}. \\ \rowsep - -\tcode{template}\br - \tcode{struct conditional;} - & - If \tcode{B} is \tcode{true}, the member typedef \tcode{type} shall equal \tcode{T}. - If \tcode{B} is \tcode{false}, the member typedef \tcode{type} shall equal \tcode{F}. \\ \rowsep - - \tcode{template} \tcode{struct common_type;} - & - Unless this trait is specialized (as specified in Note B, below), - the member \tcode{type} is defined or omitted as specified in Note A, below. - If it is omitted, there shall be no member \tcode{type}. - Each type in the template parameter pack \tcode{T} shall be - complete, \cv{}~\keyword{void}, or an array of unknown bound. \\ \rowsep - -\indexlibraryglobal{basic_common_reference}% -\tcode{template class,} - \hspace*{2ex}\tcode{template class>} - \keyword{struct} - \hspace*{2ex}\tcode{basic_common_reference;} - & - Unless this trait is specialized (as specified in Note D, below), - there shall be no member \tcode{type}. \\ \rowsep - -\indexlibraryglobal{common_reference}% -\tcode{template} \tcode{struct common_reference;} - & - The member \grammarterm{typedef-name} \tcode{type} is defined or omitted - as specified in Note C, below. Each type in the parameter pack \tcode{T} shall - be complete or \cv{} \keyword{void}. \\ \rowsep - -\indexlibraryglobal{underlying_type}% -\tcode{template}\br - \tcode{struct underlying_type;} - & - If \tcode{T} is an enumeration type, the member typedef \tcode{type} names - the underlying type of \tcode{T}\iref{dcl.enum}; - otherwise, there is no member \tcode{type}.\br - \mandates \tcode{T} is not an incomplete enumeration type. \\ \rowsep - -\tcode{template}\br - \tcode{struct invoke_result;} - & - If the expression \tcode{\placeholdernc{INVOKE}(declval(), declval()...)} - is well-formed when treated as an unevaluated operand\iref{term.unevaluated.operand}, - the member typedef \tcode{type} names the type - \tcode{decltype(\placeholdernc{INVOKE}(declval(), declval()...))}; - otherwise, there shall be no member \tcode{type}. Access checking is - performed as if in a context unrelated to \tcode{Fn} and - \tcode{ArgTypes}. Only the validity of the immediate context of the - expression is considered. - \begin{note} - The compilation of the expression can result in side effects such as - the instantiation of class template specializations and function - template specializations, the generation of implicitly-defined - functions, and so on. Such side effects are not in the ``immediate - context'' and can result in the program being ill-formed. - \end{note} - \expects \tcode{Fn} and all types in the template parameter pack \tcode{ArgTypes} - are complete types, \cv{}~\keyword{void}, or arrays of - unknown bound.\\ \rowsep - -\indexlibraryglobal{unwrap_reference}% -\tcode{template} \tcode{struct unwrap_reference;} - & - If \tcode{T} is - a specialization \tcode{reference_wrapper} for some type \tcode{X}, - the member typedef \tcode{type} of \tcode{unwrap_reference} is \tcode{X\&}, - otherwise it is \tcode{T}. \\ \rowsep - -\indexlibraryglobal{unwrap_ref_decay}% -\tcode{template} \tcode{unwrap_ref_decay;} - & - The member typedef \tcode{type} of \tcode{unwrap_ref_decay} - denotes the type \tcode{unwrap_reference_t>}.\\ -\end{libreqtab2a} - -\pnum -In addition to being available via inclusion -of the \tcode{} header, the templates -\tcode{unwrap_reference}, -\tcode{unwrap_ref_decay}, -\tcode{unwrap_reference_t}, and -\tcode{unwrap_ref_decay_t} -are available -when the header \tcode{}\iref{functional.syn} is included. - -\indexlibraryglobal{common_type}% -\pnum -Let: -\begin{itemize} -\item \tcode{\placeholdernc{CREF}(A)} be - \tcode{add_lvalue_reference_t{}>}, -\item \tcode{\placeholdernc{XREF}(A)} denote a unary alias template \tcode{T} - such that \tcode{T} denotes the same type as \tcode{U} with the addition - of \tcode{A}'s cv and reference qualifiers, for a non-reference cv-unqualified - type \tcode{U}, -\item \tcode{\placeholdernc{COPYCV}(FROM, TO)} be an alias for type \tcode{TO} - with the addition of \tcode{FROM}'s top-level cv-qualifiers, - \begin{example} - \tcode{\placeholdernc{COPYCV}(const int, volatile short)} is an alias for - \tcode{const volatile short}. - \end{example} -\item \tcode{\placeholdernc{COND-RES}(X, Y)} be - \tcode{decltype(false ?\ declval()() :\ declval()())}. -\end{itemize} -Given types \tcode{A} and \tcode{B}, -let \tcode{X} be \tcode{remove_reference_t}, -let \tcode{Y} be \tcode{remove_reference_t}, and -let \tcode{\placeholdernc{COMMON-\brk{}REF}(A, B)} be: -\begin{itemize} -\item If \tcode{A} and \tcode{B} are both lvalue reference types, - \tcode{\placeholdernc{COMMON-REF}(A, B)} is - \tcode{\placeholdernc{COND-RES}(\placeholdernc{COPYCV}(X, Y) \&, - \placeholdernc{COPYCV}(\brk{}Y, X) \&)} if that type exists - and is a reference type. -\item Otherwise, let \tcode{C} be - \tcode{remove_reference_t<\placeholdernc{COMMON-REF}(X\&, Y\&)>\&\&}. - If \tcode{A} and \tcode{B} are both rvalue reference types, - \tcode{C} is well-formed, and - \tcode{is_convertible_v \&\& is_convertible_v} is \tcode{true}, - then \tcode{\placeholdernc{COMMON-REF}(A, B)} is \tcode{C}. -\item Otherwise, let \tcode{D} be - \tcode{\placeholdernc{COMMON-REF}(const X\&, Y\&)}. If \tcode{A} is an rvalue - reference and \tcode{B} is an lvalue reference and \tcode{D} is - well-formed and \tcode{is_convertible_v} is - \tcode{true}, then \tcode{\placeholdernc{COMMON-REF}(A, B)} is \tcode{D}. -\item Otherwise, if \tcode{A} is an lvalue reference and \tcode{B} - is an rvalue reference, then \tcode{\placeholdernc{COMMON-REF}(A, B)} is - \tcode{\placeholdernc{COMMON-REF}(B, A)}. -\item Otherwise, \tcode{\placeholdernc{COMMON-REF}(A, B)} is ill-formed. -\end{itemize} - -If any of the types computed above is ill-formed, then -\tcode{\placeholdernc{COMMON-REF}(A, B)} is ill-formed. - -\pnum -Note A: -For the \tcode{common_type} trait applied to a template parameter pack \tcode{T} of types, -the member \tcode{type} shall be either defined or not present as follows: - -\begin{itemize} -\item If \tcode{sizeof...(T)} is zero, there shall be no member \tcode{type}. - -\item If \tcode{sizeof...(T)} is one, let \tcode{T0} denote the sole type -constituting the pack \tcode{T}. -The member \grammarterm{typedef-name} \tcode{type} shall denote the same -type, if any, as \tcode{common_type_t}; -otherwise there shall be no member \tcode{type}. - -\item If \tcode{sizeof...(T)} is two, -let the first and second types constituting \tcode{T} be denoted -by \tcode{T1} and \tcode{T2}, respectively, and -let \tcode{D1} and \tcode{D2} denote -the same types as \tcode{decay_t} and \tcode{decay_t}, respectively. - \begin{itemize} - \item If \tcode{is_same_v} is \tcode{false} or - \tcode{is_same_v} is \tcode{false}, - let \tcode{C} denote the same type, if any, - as \tcode{common_type_t}. - \item - \begin{note} - None of the following will apply if there is a specialization - \tcode{common_type}. - \end{note} - \item Otherwise, if -\begin{codeblock} -decay_t() : declval())> -\end{codeblock} - denotes a valid type, let \tcode{C} denote that type. - \item Otherwise, if - \tcode{\placeholdernc{COND-RES}(\placeholdernc{CREF}(D1), - \placeholdernc{CREF}(D2))} - denotes a type, let \tcode{C} denote the type - \tcode{decay_t<\placeholdernc{COND-RES}(\placeholdernc{CREF}(D1), - \placeholdernc{CREF}(D2))>}. - \end{itemize} -In either case, the member \grammarterm{typedef-name} \tcode{type} shall denote -the same type, if any, as \tcode{C}. -Otherwise, there shall be no member \tcode{type}. - -\item If \tcode{sizeof...(T)} is greater than two, -let \tcode{T1}, \tcode{T2}, and \tcode{R}, respectively, -denote the first, second, and (pack of) remaining types constituting \tcode{T}. -Let \tcode{C} denote the same type, if any, as \tcode{common_type_t}. -If there is such a type \tcode{C}, the member \grammarterm{typedef-name} \tcode{type} -shall denote the same type, if any, as \tcode{common_type_t}. -Otherwise, there shall be no member \tcode{type}. -\end{itemize} - -\pnum -Note B: Notwithstanding the provisions of \ref{meta.type.synop}, and -pursuant to \ref{namespace.std}, -a program may specialize \tcode{common_type} -for types \tcode{T1} and \tcode{T2} such that -\tcode{is_same_v>} and -\tcode{is_same_v>} are each \tcode{true}. -\begin{note} -Such specializations are needed when only explicit conversions -are desired between the template arguments. -\end{note} -Such a specialization need not have a member named \tcode{type}, -but if it does, -the \grammarterm{qualified-id} \tcode{common_type::type} shall denote -a cv-unqualified non-reference type -to which each of the types \tcode{T1} and \tcode{T2} is explicitly convertible. -Moreover, \tcode{common_type_t} shall denote -the same type, if any, as does \tcode{common_type_t}. -No diagnostic is required for a violation of this Note's rules. - -\pnum -Note C: For the \tcode{common_reference} trait applied to a parameter pack -\tcode{T} of types, the member \tcode{type} shall be either defined or not -present as follows: -\begin{itemize} -\item If \tcode{sizeof...(T)} is zero, there shall be no member \tcode{type}. - -\item Otherwise, if \tcode{sizeof...(T)} is one, let \tcode{T0} denote the sole - type in the pack \tcode{T}. The member typedef \tcode{type} shall denote the - same type as \tcode{T0}. - -\item Otherwise, if \tcode{sizeof...(T)} is two, let \tcode{T1} and \tcode{T2} - denote the two types in the pack \tcode{T}. Then - \begin{itemize} - \item If \tcode{T1} and \tcode{T2} are reference types and - \tcode{\placeholdernc{COMMON-REF}(T1, T2)} is well-formed, then the member - typedef \tcode{type} denotes that type. - - \item Otherwise, if - \tcode{basic_common_reference, remove_cvref_t, - \brk{}\placeholdernc{XREF}(\brk{}T1), \placeholdernc{XREF}(T2)>::type} - is well-formed, then the member typedef \tcode{type} denotes that type. - - \item Otherwise, if \tcode{\placeholdernc{COND-RES}(T1, T2)} is well-formed, - then the member typedef \tcode{type} denotes that type. - - \item Otherwise, if \tcode{common_type_t} is well-formed, then the - member typedef \tcode{type} denotes that type. - - \item Otherwise, there shall be no member \tcode{type}. - \end{itemize} - -\item Otherwise, if \tcode{sizeof...(T)} is greater than two, let \tcode{T1}, - \tcode{T2}, and \tcode{Rest}, respectively, denote the first, second, and - (pack of) remaining types comprising \tcode{T}. Let \tcode{C} be the type - \tcode{common_reference_t}. Then: - \begin{itemize} - \item If there is such a type \tcode{C}, the member typedef \tcode{type} shall - denote the same type, if any, as \tcode{common_reference_t}. - - \item Otherwise, there shall be no member \tcode{type}. - \end{itemize} -\end{itemize} - -\pnum -Note D: Notwithstanding the provisions of \ref{meta.type.synop}, and -pursuant to \ref{namespace.std}, a program may partially specialize -\tcode{basic_common_reference} -for types \tcode{T} and \tcode{U} such that -\tcode{is_same_v>} and -\tcode{is_same_v>} are each \tcode{true}. -\begin{note} -Such specializations -can be used to influence the result of \tcode{common_reference}, and -are needed when only explicit conversions are desired -between the template arguments. -\end{note} -Such a specialization need not have a member named \tcode{type}, but if it does, -the \grammarterm{qualified-id} -\tcode{basic_common_reference::type} -shall denote a type -to which each of the types \tcode{TQual} and -\tcode{UQual} is convertible. -Moreover, \tcode{basic_common_reference::type} shall denote -the same type, if any, as does -\tcode{basic_common_reference::type}. -No diagnostic is required for a violation of these rules. - -\pnum -\begin{example} -Given these definitions: -\begin{codeblock} -using PF1 = bool (&)(); -using PF2 = short (*)(long); - -struct S { - operator PF2() const; - double operator()(char, int&); - void fn(long) const; - char data; -}; - -using PMF = void (S::*)(long) const; -using PMD = char S::*; -\end{codeblock} -the following assertions will hold: -\begin{codeblock} -static_assert(is_same_v, short>); -static_assert(is_same_v, double>); -static_assert(is_same_v, bool>); -static_assert(is_same_v, int>, void>); -static_assert(is_same_v, char&&>); -static_assert(is_same_v, const char&>); -\end{codeblock} -\end{example} - -\rSec2[meta.logical]{Logical operator traits} - -\pnum -This subclause describes type traits for applying logical operators -to other type traits. - -\indexlibraryglobal{conjunction}% +\indexlibraryctor{boyer_moore_searcher}% \begin{itemdecl} -template struct conjunction : @\seebelow@ { }; +boyer_moore_searcher(RandomAccessIterator1 pat_first, + RandomAccessIterator1 pat_last, + Hash hf = Hash(), + BinaryPredicate pred = BinaryPredicate()); \end{itemdecl} \begin{itemdescr} \pnum -The class template \tcode{conjunction} -forms the logical conjunction of its template type arguments. - -\pnum -For a specialization \tcode{conjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>}, -if there is a template type argument $\tcode{B}_{i}$ -for which \tcode{bool($\tcode{B}_{i}$::value)} is \tcode{false}, -then instantiating \tcode{conjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>::value} -does not require the instantiation of \tcode{$\tcode{B}_{j}$::value} for $j > i$. -\begin{note} -This is analogous to the short-circuiting behavior of -the built-in operator \tcode{\&\&}. -\end{note} +\expects +The value type of \tcode{RandomAccessIterator1} meets +the \oldconcept{DefaultConstructible}, +the \oldconcept{Copy\-Constructible}, and +the \oldconcept{CopyAssignable} requirements. \pnum -Every template type argument -for which \tcode{$\tcode{B}_{i}$::value} is instantiated -shall be usable as a base class and -shall have a member \tcode{value} which -is convertible to \tcode{bool}, -is not hidden, and -is unambiguously available in the type. +Let \tcode{V} be \tcode{iterator_traits::val\-ue_type}. +For any two values \tcode{A} and \tcode{B} of type \tcode{V}, +if \tcode{pred(A, B) == true}, then \tcode{hf(A) == hf(B)} is \tcode{true}. \pnum -The specialization \tcode{conjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>} -has a public and unambiguous base that is either -\begin{itemize} -\item -the first type $\tcode{B}_{i}$ in the list \tcode{true_type, $\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$} -for which \tcode{bool($\tcode{B}_{i}$::value)} is \tcode{false}, or -\item -if there is no such $\tcode{B}_{i}$, the last type in the list. -\end{itemize} -\begin{note} -This means a specialization of \tcode{conjunction} -does not necessarily inherit from -either \tcode{true_type} or \tcode{false_type}. -\end{note} +\effects +Initializes +\tcode{pat_first_} with \tcode{pat_first}, +\tcode{pat_last_} with \tcode{pat_last}, +\tcode{hash_} with \tcode{hf}, and +\tcode{pred_} with \tcode{pred}. \pnum -The member names of the base class, other than \tcode{conjunction} and -\tcode{operator=}, shall not be hidden and shall be unambiguously available -in \tcode{conjunction}. +\throws +Any exception thrown by the copy constructor of \tcode{RandomAccessIterator1}, +or by the default constructor, copy constructor, or the copy assignment operator of the value type of \tcode{RandomAccess\-Iterator1}, +or the copy constructor or \tcode{operator()} of \tcode{BinaryPredicate} or \tcode{Hash}. +May throw \tcode{bad_alloc} if additional memory needed for internal data structures cannot be allocated. \end{itemdescr} -\indexlibraryglobal{disjunction}% +\indexlibrarymember{operator()}{boyer_moore_searcher}% \begin{itemdecl} -template struct disjunction : @\seebelow@ { }; +template + pair + operator()(RandomAccessIterator2 first, RandomAccessIterator2 last) const; \end{itemdecl} \begin{itemdescr} \pnum -The class template \tcode{disjunction} -forms the logical disjunction of its template type arguments. - -\pnum -For a specialization \tcode{disjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>}, -if there is a template type argument $\tcode{B}_{i}$ -for which \tcode{bool($\tcode{B}_{i}$::value)} is \tcode{true}, -then instantiating \tcode{disjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>::value} -does not require the instantiation of \tcode{$\tcode{B}_{j}$::value} for $j > i$. -\begin{note} -This is analogous to the short-circuiting behavior of -the built-in operator \tcode{||}. -\end{note} +\mandates +\tcode{RandomAccessIterator1} and \tcode{RandomAccessIterator2} +have the same value type. \pnum -Every template type argument -for which \tcode{$\tcode{B}_{i}$::value} is instantiated -shall be usable as a base class and -shall have a member \tcode{value} which -is convertible to \tcode{bool}, -is not hidden, and -is unambiguously available in the type. +\effects +Finds a subsequence of equal values in a sequence. \pnum -The specialization \tcode{disjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>} -has a public and unambiguous base that is either +\returns +A pair of iterators \tcode{i} and \tcode{j} such that \begin{itemize} -\item the first type $\tcode{B}_{i}$ in the list \tcode{false_type, $\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$} -for which \tcode{bool($\tcode{B}_{i}$::value)} is \tcode{true}, or -\item if there is no such $\tcode{B}_{i}$, the last type in the list. +\item \tcode{i} is the first iterator +in the range \range{first}{last - (pat_last_ - pat_first_)} such that +for every non-negative integer \tcode{n} less than \tcode{pat_last_ - pat_first_} +the following condition holds: +\tcode{pred(*(i + n), *(pat_first_ + n)) != false}, and +\item \tcode{j == next(i, distance(pat_first_, pat_last_))}. \end{itemize} -\begin{note} -This means a specialization of \tcode{disjunction} -does not necessarily inherit from -either \tcode{true_type} or \tcode{false_type}. -\end{note} +Returns \tcode{make_pair(first, first)} if \range{pat_first_}{pat_last_} is empty, +otherwise returns \tcode{make_pair(last, last)} if no such iterator is found. \pnum -The member names of the base class, -other than \tcode{disjunction} and \tcode{operator=}, -shall not be hidden and shall be unambiguously available in \tcode{disjunction}. +\complexity +At most \tcode{(last - first) * (pat_last_ - pat_first_)} applications of the predicate. \end{itemdescr} -\indexlibraryglobal{negation}% -\begin{itemdecl} -template struct negation : @\seebelow@ { }; -\end{itemdecl} +\rSec3[func.search.bmh]{Class template \tcode{boyer_moore_horspool_searcher}} -\begin{itemdescr} -\pnum -The class template \tcode{negation} -forms the logical negation of its template type argument. -The type \tcode{negation} -is a \oldconcept{UnaryTypeTrait} with a base characteristic of \tcode{bool_constant}. -\end{itemdescr} +\indexlibraryglobal{boyer_moore_horspool_searcher}% +\begin{codeblock} +namespace std { + template::value_type>, + class BinaryPredicate = equal_to<>> + class boyer_moore_horspool_searcher { + public: + boyer_moore_horspool_searcher(RandomAccessIterator1 pat_first, + RandomAccessIterator1 pat_last, + Hash hf = Hash(), + BinaryPredicate pred = BinaryPredicate()); + + template + pair + operator()(RandomAccessIterator2 first, RandomAccessIterator2 last) const; -\rSec2[meta.member]{Member relationships} + private: + RandomAccessIterator1 pat_first_; // \expos + RandomAccessIterator1 pat_last_; // \expos + Hash hash_; // \expos + BinaryPredicate pred_; // \expos + }; +} +\end{codeblock} -\indexlibraryglobal{is_pointer_interconvertible_with_class} +\indexlibraryctor{boyer_moore_horspool_searcher}% \begin{itemdecl} -template - constexpr bool is_pointer_interconvertible_with_class(M S::*m) noexcept; +boyer_moore_horspool_searcher(RandomAccessIterator1 pat_first, + RandomAccessIterator1 pat_last, + Hash hf = Hash(), + BinaryPredicate pred = BinaryPredicate()); \end{itemdecl} \begin{itemdescr} \pnum -\mandates -\tcode{S} is a complete type. +\expects +The value type of \tcode{RandomAccessIterator1} meets the \oldconcept{DefaultConstructible}, +\oldconcept{Copy\-Constructible}, and \oldconcept{CopyAssignable} requirements. \pnum -\returns -\tcode{true} if and only if - \tcode{S} is a standard-layout type, - \tcode{M} is an object type, - \tcode{m} is not null, - and each object \tcode{s} of type \tcode{S} - is pointer-interconvertible\iref{basic.compound} - with its subobject \tcode{s.*m}. -\end{itemdescr} - -\indexlibraryglobal{is_corresponding_member} -\begin{itemdecl} -template - constexpr bool is_corresponding_member(M1 S1::*m1, M2 S2::*m2) noexcept; -\end{itemdecl} +Let \tcode{V} be \tcode{iterator_traits::val\-ue_type}. +For any two values \tcode{A} and \tcode{B} of type \tcode{V}, +if \tcode{pred(A, B) == true}, then \tcode{hf(A) == hf(B)} is \tcode{true}. -\begin{itemdescr} \pnum -\mandates -\tcode{S1} and \tcode{S2} are complete types. +\effects +Initializes +\tcode{pat_first_} with \tcode{pat_first}, +\tcode{pat_last_} with \tcode{pat_last}, +\tcode{hash_} with \tcode{hf}, and +\tcode{pred_} with \tcode{pred}. \pnum -\returns -\tcode{true} if and only if - \tcode{S1} and \tcode{S2} are standard-layout struct\iref{class.prop} types, - \tcode{M1} and \tcode{M2} are object types, - \tcode{m1} and \tcode{m2} are not null, - and \tcode{m1} and \tcode{m2} point to corresponding members of - the common initial sequence\iref{class.mem} of \tcode{S1} and \tcode{S2}. +\throws +Any exception thrown by the copy constructor of \tcode{RandomAccessIterator1}, +or by the default constructor, copy constructor, or the copy assignment operator of the value type of \tcode{RandomAccess\-Iterator1}, +or the copy constructor or \tcode{operator()} of \tcode{BinaryPredicate} or \tcode{Hash}. +May throw \tcode{bad_alloc} if additional memory needed for internal data structures cannot be allocated. \end{itemdescr} -\pnum -\begin{note} -The type of a pointer-to-member expression \tcode{\&C::b} -is not always a pointer to member of \tcode{C}, -leading to potentially surprising results -when using these functions in conjunction with inheritance. -\begin{example} -\begin{codeblock} -struct A { int a; }; // a standard-layout class -struct B { int b; }; // a standard-layout class -struct C: public A, public B { }; // not a standard-layout class - -static_assert( is_pointer_interconvertible_with_class( &C::b ) ); - // Succeeds because, despite its appearance, \tcode{\&C::b} has type - // ``pointer to member of \tcode{B} of type \tcode{int}''. -static_assert( is_pointer_interconvertible_with_class( &C::b ) ); - // Forces the use of class \tcode{C}, and fails. - -static_assert( is_corresponding_member( &C::a, &C::b ) ); - // Succeeds because, despite its appearance, \tcode{\&C::a} and \tcode{\&C::b} have types - // ``pointer to member of \tcode{A} of type \tcode{int}'' and - // ``pointer to member of \tcode{B} of type \tcode{int}'', respectively. -static_assert( is_corresponding_member( &C::a, &C::b ) ); - // Forces the use of class \tcode{C}, and fails. -\end{codeblock} -\end{example} -\end{note} - -\rSec2[meta.const.eval]{Constant evaluation context} +\indexlibrarymember{operator()}{boyer_moore_horspool_searcher}% \begin{itemdecl} -constexpr bool is_constant_evaluated() noexcept; +template + pair + operator()(RandomAccessIterator2 first, RandomAccessIterator2 last) const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -if consteval { - return true; -} else { - return false; -} -\end{codeblock} +\mandates +\tcode{RandomAccessIterator1} and \tcode{RandomAccessIterator2} +have the same value type. \pnum -\begin{example} -\begin{codeblock} -constexpr void f(unsigned char *p, int n) { - if (std::is_constant_evaluated()) { // should not be a constexpr if statement - for (int k = 0; k} synopsis} - -\indexheader{ratio}% -\begin{codeblockdigitsep} -namespace std { - // \ref{ratio.ratio}, class template \tcode{ratio} - template class ratio; - - // \ref{ratio.arithmetic}, ratio arithmetic - template using ratio_add = @\seebelow@; - template using ratio_subtract = @\seebelow@; - template using ratio_multiply = @\seebelow@; - template using ratio_divide = @\seebelow@; - - // \ref{ratio.comparison}, ratio comparison - template struct ratio_equal; - template struct ratio_not_equal; - template struct ratio_less; - template struct ratio_less_equal; - template struct ratio_greater; - template struct ratio_greater_equal; - - template - inline constexpr bool @\libglobal{ratio_equal_v}@ = ratio_equal::value; - template - inline constexpr bool @\libglobal{ratio_not_equal_v}@ = ratio_not_equal::value; - template - inline constexpr bool @\libglobal{ratio_less_v}@ = ratio_less::value; - template - inline constexpr bool @\libglobal{ratio_less_equal_v}@ = ratio_less_equal::value; - template - inline constexpr bool @\libglobal{ratio_greater_v}@ = ratio_greater::value; - template - inline constexpr bool @\libglobal{ratio_greater_equal_v}@ = ratio_greater_equal::value; - - // \ref{ratio.si}, convenience SI typedefs - using yocto = ratio<1, 1'000'000'000'000'000'000'000'000>; // see below - using zepto = ratio<1, 1'000'000'000'000'000'000'000>; // see below - using atto = ratio<1, 1'000'000'000'000'000'000>; - using femto = ratio<1, 1'000'000'000'000'000>; - using pico = ratio<1, 1'000'000'000'000>; - using nano = ratio<1, 1'000'000'000>; - using micro = ratio<1, 1'000'000>; - using milli = ratio<1, 1'000>; - using centi = ratio<1, 100>; - using deci = ratio<1, 10>; - using deca = ratio< 10, 1>; - using hecto = ratio< 100, 1>; - using kilo = ratio< 1'000, 1>; - using mega = ratio< 1'000'000, 1>; - using giga = ratio< 1'000'000'000, 1>; - using tera = ratio< 1'000'000'000'000, 1>; - using peta = ratio< 1'000'000'000'000'000, 1>; - using exa = ratio< 1'000'000'000'000'000'000, 1>; - using zetta = ratio< 1'000'000'000'000'000'000'000, 1>; // see below - using yotta = ratio<1'000'000'000'000'000'000'000'000, 1>; // see below -} -\end{codeblockdigitsep} +\complexity +At most \tcode{(last - first) * (pat_last_ - pat_first_)} applications of the predicate. +\end{itemdescr} -\rSec2[ratio.ratio]{Class template \tcode{ratio}} +\rSec2[unord.hash]{Class template \tcode{hash}} -\indexlibraryglobal{ratio}% -\begin{codeblock} -namespace std { - template class ratio { - public: - static constexpr intmax_t num; - static constexpr intmax_t den; - using type = ratio; - }; -} -\end{codeblock} +\pnum +\indexlibraryglobal{hash}% +\indextext{\idxcode{hash}!instantiation restrictions}% +The unordered associative containers defined in \ref{unord} use +specializations of the class template \tcode{hash}\iref{functional.syn} +as the default hash function. \pnum -\indextext{signed integer representation!two's complement}% -If the template argument \tcode{D} is zero or the absolute values of either of the -template arguments \tcode{N} and \tcode{D} is not representable by type -\tcode{intmax_t}, the program is ill-formed. +Each specialization of \tcode{hash} is either enabled or disabled, +as described below. \begin{note} -These rules ensure that infinite -ratios are avoided and that for any negative input, there exists a representable value -of its absolute value which is positive. -This excludes the most negative value. +Enabled specializations meet the \oldconcept{Hash} requirements, and +disabled specializations do not. \end{note} +Each header that declares the template \tcode{hash} +provides enabled specializations of \tcode{hash} for \tcode{nullptr_t} and +all cv-unqualified arithmetic, enumeration, and pointer types. +For any type \tcode{Key} for which neither the library nor the user provides +an explicit or partial specialization of the class template \tcode{hash}, +\tcode{hash} is disabled. \pnum -The static data members \tcode{num} and \tcode{den} shall have the following values, -where \tcode{gcd} represents the greatest common divisor of the absolute values of -\tcode{N} and \tcode{D}: - -\begin{itemize} -\item \tcode{num} shall have the value \tcode{sign(N) * sign(D) * abs(N) / gcd}. -\item \tcode{den} shall have the value \tcode{abs(D) / gcd}. -\end{itemize} - -\rSec2[ratio.arithmetic]{Arithmetic on \tcode{ratio}{s}} - -\pnum -Each of the alias templates \tcode{ratio_add}, \tcode{ratio_subtract}, \tcode{ratio_multiply}, -and \tcode{ratio_divide} denotes the result of an arithmetic computation on two -\tcode{ratio}{s} \tcode{R1} and \tcode{R2}. With \tcode{X} and \tcode{Y} computed (in the -absence of arithmetic overflow) as specified by \tref{ratio.arithmetic}, each alias -denotes a \tcode{ratio} such that \tcode{U} is the same as \tcode{ratio::num} and -\tcode{V} is the same as \tcode{ratio::den}. - -\pnum -If it is not possible to represent \tcode{U} or \tcode{V} with \tcode{intmax_t}, the program is -ill-formed. Otherwise, an implementation should yield correct values of \tcode{U} and -\tcode{V}. If it is not possible to represent \tcode{X} or \tcode{Y} with \tcode{intmax_t}, the -program is ill-formed unless the implementation yields correct values of \tcode{U} and -\tcode{V}. - -\begin{floattable}{Expressions used to perform ratio arithmetic}{ratio.arithmetic} -{lll} -\topline -\lhdr{Type} & - \chdr{Value of \tcode{X}} & - \rhdr{Value of \tcode{Y}} \\ \rowsep - -\tcode{ratio_add} & - \tcode{R1::num * R2::den +} & - \tcode{R1::den * R2::den} \\ - & - \tcode{R2::num * R1::den} & - \\ \rowsep - -\tcode{ratio_subtract} & - \tcode{R1::num * R2::den -} & - \tcode{R1::den * R2::den} \\ - & - \tcode{R2::num * R1::den} & - \\ \rowsep - -\tcode{ratio_multiply} & - \tcode{R1::num * R2::num} & - \tcode{R1::den * R2::den} \\ \rowsep - -\tcode{ratio_divide} & - \tcode{R1::num * R2::den} & - \tcode{R1::den * R2::num} \\ -\end{floattable} - -\pnum -\begin{example} -\begin{codeblock} -static_assert(ratio_add, ratio<1, 6>>::num == 1, "1/3+1/6 == 1/2"); -static_assert(ratio_add, ratio<1, 6>>::den == 2, "1/3+1/6 == 1/2"); -static_assert(ratio_multiply, ratio<3, 2>>::num == 1, "1/3*3/2 == 1/2"); -static_assert(ratio_multiply, ratio<3, 2>>::den == 2, "1/3*3/2 == 1/2"); - -// The following cases may cause the program to be ill-formed under some implementations -static_assert(ratio_add, ratio<1, INT_MAX>>::num == 2, - "1/MAX+1/MAX == 2/MAX"); -static_assert(ratio_add, ratio<1, INT_MAX>>::den == INT_MAX, - "1/MAX+1/MAX == 2/MAX"); -static_assert(ratio_multiply, ratio>::num == 1, - "1/MAX * MAX/2 == 1/2"); -static_assert(ratio_multiply, ratio>::den == 2, - "1/MAX * MAX/2 == 1/2"); -\end{codeblock} - -\end{example} - -\rSec2[ratio.comparison]{Comparison of \tcode{ratio}{s}} - -\indexlibraryglobal{ratio_equal}% -\begin{itemdecl} -template - struct ratio_equal : bool_constant { }; -\end{itemdecl} - -\indexlibraryglobal{ratio_not_equal}% -\begin{itemdecl} -template - struct ratio_not_equal : bool_constant> { }; -\end{itemdecl} - -\indexlibraryglobal{ratio_less}% -\begin{itemdecl} -template - struct ratio_less : bool_constant<@\seebelow@> { }; -\end{itemdecl} +If the library provides an explicit or partial specialization of \tcode{hash}, +that specialization is enabled except as noted otherwise, +and its member functions are \keyword{noexcept} except as noted otherwise. -\begin{itemdescr} \pnum -If \tcode{R1::num} $\times$ \tcode{R2::den} is less than \tcode{R2::num} $\times$ \tcode{R1::den}, -\tcode{ratio_less} shall be -derived from \tcode{bool_constant}; otherwise it shall be derived from -\tcode{bool_constant}. Implementations may use other algorithms to -compute this relationship to avoid overflow. If overflow occurs, the program is ill-formed. -\end{itemdescr} - -\indexlibraryglobal{ratio_less_equal}% -\begin{itemdecl} -template - struct ratio_less_equal : bool_constant> { }; -\end{itemdecl} - -\indexlibraryglobal{ratio_greater}% -\begin{itemdecl} -template - struct ratio_greater : bool_constant> { }; -\end{itemdecl} - -\indexlibraryglobal{ratio_greater_equal}% -\begin{itemdecl} -template - struct ratio_greater_equal : bool_constant> { }; -\end{itemdecl} - -\rSec2[ratio.si]{SI types for \tcode{ratio}} +If \tcode{H} is a disabled specialization of \tcode{hash}, +these values are \tcode{false}: +\tcode{is_default_constructible_v}, +\tcode{is_copy_constructible_v}, +\tcode{is_move_constructible_v}, +\tcode{is_copy_assignable_v}, and +\tcode{is_move_assignable_v}. +Disabled specializations of \tcode{hash} +are not function object types\iref{function.objects}. +\begin{note} +This means that the specialization of \tcode{hash} exists, but +any attempts to use it as a \oldconcept{Hash} will be ill-formed. +\end{note} \pnum -For each of the \grammarterm{typedef-name}{s} \tcode{yocto}, \tcode{zepto}, -\tcode{zetta}, and \tcode{yotta}, if both of the constants used in its -specification are representable by \tcode{intmax_t}, the typedef is -defined; if either of the constants is not representable by \tcode{intmax_t}, -the typedef is not defined. +An enabled specialization \tcode{hash} will: +\begin{itemize} +\item meet the \oldconcept{Hash} requirements (\tref{cpp17.hash}), +with \tcode{Key} as the function +call argument type, the \oldconcept{Default\-Constructible} requirements (\tref{cpp17.defaultconstructible}), +the \oldconcept{CopyAssignable} requirements (\tref{cpp17.copyassignable}), +\item be swappable\iref{swappable.requirements} for lvalues, +\item meet the requirement that if \tcode{k1 == k2} is \tcode{true}, \tcode{h(k1) == h(k2)} is +also \tcode{true}, where \tcode{h} is an object of type \tcode{hash} and \tcode{k1} and \tcode{k2} +are objects of type \tcode{Key}; +\item meet the requirement that the expression \tcode{h(k)}, where \tcode{h} +is an object of type \tcode{hash} and \tcode{k} is an object of type +\tcode{Key}, shall not throw an exception unless \tcode{hash} is a +program-defined specialization. +\end{itemize} \rSec1[type.index]{Class \tcode{type_index}} @@ -24856,3 +15508,417 @@ \ensures \tcode{strcmp(what(), what_arg) == 0}. \end{itemdescr} + +\rSec1[bit]{Bit manipulation} + +\rSec2[bit.general]{General} + +\pnum +The header \libheaderdef{bit} provides components to access, +manipulate and process both individual bits and bit sequences. + +\rSec2[bit.syn]{Header \tcode{} synopsis} + +\begin{codeblock} +namespace std { + // \ref{bit.cast}, \tcode{bit_cast} + template + constexpr To bit_cast(const From& from) noexcept; + + // \ref{bit.byteswap}, \tcode{byteswap} + template + constexpr T byteswap(T value) noexcept; + + // \ref{bit.pow.two}, integral powers of 2 + template + constexpr bool has_single_bit(T x) noexcept; + template + constexpr T bit_ceil(T x); + template + constexpr T bit_floor(T x) noexcept; + template + constexpr T bit_width(T x) noexcept; + + // \ref{bit.rotate}, rotating + template + [[nodiscard]] constexpr T rotl(T x, int s) noexcept; + template + [[nodiscard]] constexpr T rotr(T x, int s) noexcept; + + // \ref{bit.count}, counting + template + constexpr int countl_zero(T x) noexcept; + template + constexpr int countl_one(T x) noexcept; + template + constexpr int countr_zero(T x) noexcept; + template + constexpr int countr_one(T x) noexcept; + template + constexpr int popcount(T x) noexcept; + + // \ref{bit.endian}, endian + enum class endian { + little = @\seebelow@, + big = @\seebelow@, + native = @\seebelow@ + }; +} +\end{codeblock} + +\rSec2[bit.cast]{Function template \tcode{bit_cast}} + +\indexlibraryglobal{bit_cast}% +\begin{itemdecl} +template + constexpr To bit_cast(const From& from) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item \tcode{sizeof(To) == sizeof(From)} is \tcode{true}; +\item \tcode{is_trivially_copyable_v} is \tcode{true}; and +\item \tcode{is_trivially_copyable_v} is \tcode{true}. +\end{itemize} + +\pnum +\returns +An object of type \tcode{To}. +Implicitly creates objects nested within the result\iref{intro.object}. +Each bit of the value representation of the result +is equal to the corresponding bit in the object representation +of \tcode{from}. Padding bits of the result are unspecified. +For the result and each object created within it, +if there is no value of the object's type corresponding to the +value representation produced, the behavior is undefined. +If there are multiple such values, which value is produced is unspecified. +A bit in the value representation of the result is indeterminate if +it does not correspond to a bit in the value representation of \tcode{from} or +corresponds to a bit of an object that is not within its lifetime or +has an indeterminate value\iref{basic.indet}. +For each bit in the value representation of the result that is indeterminate, +the smallest object containing that bit has an indeterminate value; +the behavior is undefined unless that object is +of unsigned ordinary character type or \tcode{std::byte} type. +The result does not otherwise contain any indeterminate values. + +\pnum +\remarks +This function is \keyword{constexpr} if and only if +\tcode{To}, \tcode{From}, and the types of all subobjects +of \tcode{To} and \tcode{From} are types \tcode{T} such that: +\begin{itemize} +\item \tcode{is_union_v} is \tcode{false}; +\item \tcode{is_pointer_v} is \tcode{false}; +\item \tcode{is_member_pointer_v} is \tcode{false}; +\item \tcode{is_volatile_v} is \tcode{false}; and +\item \tcode{T} has no non-static data members of reference type. +\end{itemize} +\end{itemdescr} + +\rSec2[bit.byteswap]{\tcode{byteswap}} + +\indexlibraryglobal{byteswap}% +\begin{itemdecl} +template + constexpr T byteswap(T value) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} models \libconcept{integral}. + +\pnum +\mandates +\tcode{T} does not have padding bits\iref{basic.types.general}. + +\pnum +Let the sequence $R$ comprise +the bytes of the object representation of \tcode{value} in reverse order. + +\pnum +\returns +An object \tcode{v} of type \tcode{T} +such that each byte in the object representation of \tcode{v} is equal to +the byte in the corresponding position in $R$. +\end{itemdescr} + +\rSec2[bit.pow.two]{Integral powers of 2} + +\indexlibraryglobal{has_single_bit}% +\begin{itemdecl} +template + constexpr bool has_single_bit(T x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +\tcode{true} if \tcode{x} is an integral power of two; +\tcode{false} otherwise. + +\end{itemdescr} + +\indexlibraryglobal{bit_ceil}% +\begin{itemdecl} +template + constexpr T bit_ceil(T x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let $N$ be the smallest power of 2 greater than or equal to \tcode{x}. + +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\expects +$N$ is representable as a value of type \tcode{T}. + +\pnum +\returns +$N$. + +\pnum +\throws +Nothing. + +\pnum +\remarks +A function call expression +that violates the precondition in the \expects element +is not a core constant expression\iref{expr.const}. +\end{itemdescr} + +\indexlibraryglobal{bit_floor}% +\begin{itemdecl} +template + constexpr T bit_floor(T x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +If \tcode{x == 0}, \tcode{0}; +otherwise the maximal value \tcode{y} +such that \tcode{has_single_bit(y)} is \tcode{true} and \tcode{y <= x}. + +\end{itemdescr} + +\indexlibraryglobal{bit_width}% +\begin{itemdecl} +template + constexpr T bit_width(T x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +If \tcode{x == 0}, \tcode{0}; +otherwise one plus the base-2 logarithm of \tcode{x}, +with any fractional part discarded. + +\end{itemdescr} + +\rSec2[bit.rotate]{Rotating} + +\pnum +In the following descriptions, +let \tcode{N} denote \tcode{numeric_limits::digits}. + +\begin{itemdecl} +template + [[nodiscard]] constexpr T rotl(T x, int s) noexcept; +\end{itemdecl} + +\indexlibraryglobal{rotl}% +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +Let \tcode{r} be \tcode{s \% N}. + +\pnum +\returns +If \tcode{r} is \tcode{0}, \tcode{x}; +if \tcode{r} is positive, \tcode{(x << r) | (x >> (N - r))}; +if \tcode{r} is negative, \tcode{rotr(x, -r)}. +\end{itemdescr} + +\begin{itemdecl} +template + [[nodiscard]] constexpr T rotr(T x, int s) noexcept; +\end{itemdecl} + +\indexlibraryglobal{rotr}% +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +Let \tcode{r} be \tcode{s \% N}. + +\pnum +\returns +If \tcode{r} is \tcode{0}, \tcode{x}; +if \tcode{r} is positive, \tcode{(x >> r) | (x << (N - r))}; +if \tcode{r} is negative, \tcode{rotl(x, -r)}. +\end{itemdescr} + +\rSec2[bit.count]{Counting} + +\pnum +In the following descriptions, +let \tcode{N} denote \tcode{numeric_limits::digits}. + +\begin{itemdecl} +template + constexpr int countl_zero(T x) noexcept; +\end{itemdecl} + +\indexlibraryglobal{countl_zero}% +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +The number of consecutive \tcode{0} bits in the value of \tcode{x}, +starting from the most significant bit. +\begin{note} +Returns \tcode{N} if \tcode{x == 0}. +\end{note} +\end{itemdescr} + +\begin{itemdecl} +template + constexpr int countl_one(T x) noexcept; +\end{itemdecl} + +\indexlibraryglobal{countl_one}% +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +The number of consecutive \tcode{1} bits in the value of \tcode{x}, +starting from the most significant bit. +\begin{note} +Returns \tcode{N} if \tcode{x == numeric_limits::max()}. +\end{note} +\end{itemdescr} + +\begin{itemdecl} +template + constexpr int countr_zero(T x) noexcept; +\end{itemdecl} + +\indexlibraryglobal{countr_zero}% +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +The number of consecutive \tcode{0} bits in the value of \tcode{x}, +starting from the least significant bit. +\begin{note} +Returns \tcode{N} if \tcode{x == 0}. +\end{note} +\end{itemdescr} + +\begin{itemdecl} +template + constexpr int countr_one(T x) noexcept; +\end{itemdecl} + +\indexlibraryglobal{countr_one}% +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +The number of consecutive \tcode{1} bits in the value of \tcode{x}, +starting from the least significant bit. +\begin{note} +Returns \tcode{N} if \tcode{x == numeric_limits::max()}. +\end{note} +\end{itemdescr} + +\begin{itemdecl} +template + constexpr int popcount(T x) noexcept; +\end{itemdecl} + +\indexlibraryglobal{popcount}% +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +The number of \tcode{1} bits in the value of \tcode{x}. +\end{itemdescr} + +\rSec2[bit.endian]{Endian} + +\pnum +Two common methods of byte ordering in multibyte scalar types are big-endian +and little-endian in the execution environment. Big-endian is a format for +storage of binary data in which the most significant byte is placed first, +with the rest in descending order. Little-endian is a format for storage of +binary data in which the least significant byte is placed first, with the rest +in ascending order. This subclause describes the endianness of the scalar types +of the execution environment. + +\indexlibraryglobal{endian}% +\indexlibrarymember{little}{endian}% +\indexlibrarymember{big}{endian}% +\indexlibrarymember{native}{endian}% +\begin{itemdecl} +enum class endian { + little = @\seebelow@, + big = @\seebelow@, + native = @\seebelow@ +}; +\end{itemdecl} + +\begin{itemdescr} +\pnum +If all scalar types have size 1 byte, then all of \tcode{endian::little}, +\tcode{endian::big}, and \tcode{endian::native} have the same value. +Otherwise, \tcode{endian::little} is not equal to \tcode{endian::big}. +If all scalar types are big-endian, \tcode{endian::native} is +equal to \tcode{endian::big}. +If all scalar types are little-endian, \tcode{endian::native} is +equal to \tcode{endian::little}. +Otherwise, \tcode{endian::native} is not equal +to either \tcode{endian::big} or \tcode{endian::little}. +\end{itemdescr} diff --git a/tools/check-source.sh b/tools/check-source.sh index 9a90e8b4db..fb1c2518cc 100755 --- a/tools/check-source.sh +++ b/tools/check-source.sh @@ -6,7 +6,7 @@ failed=0 # Ignore files where rules may be violated within macro definitions. texfiles=$(ls *.tex | grep -v macros.tex | grep -v layout.tex | grep -v tables.tex) -texlibdesc="support.tex concepts.tex diagnostics.tex utilities.tex strings.tex containers.tex iterators.tex ranges.tex algorithms.tex numerics.tex time.tex locales.tex iostreams.tex regex.tex atomics.tex threads.tex" +texlibdesc="support.tex concepts.tex diagnostics.tex memory.tex meta.tex utilities.tex strings.tex containers.tex iterators.tex ranges.tex algorithms.tex numerics.tex time.tex locales.tex iostreams.tex regex.tex threads.tex" texlib="lib-intro.tex $texlibdesc" # Filter that reformats the error message as a "workflow command",

); +static_assert(!is_final_v); +static_assert(is_final_v); +\end{codeblock} +\end{example} + +\indexlibraryglobal{is_constructible}% +\pnum +The predicate condition for a template specialization +\tcode{is_constructible} shall be satisfied if and only if the +following variable definition would be well-formed for some invented variable \tcode{t}: + +\begin{codeblock} +T t(declval()...); +\end{codeblock} + +\begin{note} +These tokens are never interpreted as a function declaration. +\end{note} +Access checking is performed as if in a context unrelated to \tcode{T} +and any of the \tcode{Args}. Only the validity of the immediate context of the +variable initialization is considered. +\begin{note} +The evaluation of the +initialization can result in side effects such as the instantiation of class +template specializations and function template specializations, the generation +of implicitly-defined functions, and so on. Such side effects are not in the +``immediate context'' and can result in the program being ill-formed. +\end{note} + +\indexlibraryglobal{has_unique_object_representations}% +\pnum +The predicate condition for a template specialization +\tcode{has_unique_object_representations} +shall be satisfied if and only if: +\begin{itemize} +\item \tcode{T} is trivially copyable, and +\item any two objects of type \tcode{T} with the same value +have the same object representation, where +two objects of array or non-union class type are considered to have the same value +if their respective sequences of direct subobjects have the same values, and +two objects of union type are considered to have the same value +if they have the same active member and the corresponding members have the same value. +\end{itemize} +The set of scalar types for which this condition holds is +\impldef{which scalar types have unique object representations}. +\begin{note} +If a type has padding bits, the condition does not hold; +otherwise, the condition holds true for integral types. +\end{note} + +\rSec2[meta.unary.prop.query]{Type property queries} + +\pnum +This subclause contains templates that may be used to query +properties of types at compile time. + +\begin{libreqtab2a}{Type property queries}{meta.unary.prop.query} +\\ \topline +\lhdr{Template} & \rhdr{Value} \\ \capsep +\endfirsthead +\continuedcaption\\ +\topline +\lhdr{Template} & \rhdr{Value} \\ \capsep +\endhead + +\indexlibraryglobal{alignment_of}% +\tcode{template\br + struct alignment_of;} & + \tcode{alignof(T)}.\br + \mandates + \tcode{alignof(T)} is a valid expression\iref{expr.alignof} \\ \rowsep + +\indexlibraryglobal{rank}% +\tcode{template\br + struct rank;} & + If \tcode{T} names an array type, an integer value representing + the number of dimensions of \tcode{T}; otherwise, 0. \\ \rowsep + +\indexlibraryglobal{extent}% +\tcode{template\br + struct extent;} & + If \tcode{T} is not an array type, or if it has rank less + than or equal to \tcode{I}, or if \tcode{I} is 0 and \tcode{T} + has type ``array of unknown bound of \tcode{U}'', then + 0; otherwise, the bound\iref{dcl.array} of the $\tcode{I}^\text{th}$ dimension of +\tcode{T}, where indexing of \tcode{I} is zero-based \\ +\end{libreqtab2a} + +\pnum +Each of these templates shall be a \oldconcept{UnaryTypeTrait}\iref{meta.rqmts} with a +base characteristic of \tcode{integral_constant}. + +\pnum +\begin{example} +\begin{codeblock} +// the following assertions hold: +assert(rank_v == 0); +assert(rank_v == 1); +assert(rank_v == 2); +\end{codeblock} +\end{example} + +\pnum +\begin{example} +\begin{codeblock} +// the following assertions hold: +assert(extent_v == 0); +assert(extent_v == 2); +assert(extent_v == 2); +assert(extent_v == 0); +assert((extent_v) == 0); +assert((extent_v) == 0); +assert((extent_v) == 4); +assert((extent_v) == 4); +\end{codeblock} +\end{example} + +\rSec2[meta.rel]{Relationships between types} + +\pnum +This subclause contains templates that may be used to query +relationships between types at compile time. + +\pnum +Each of these templates shall be a +\oldconcept{BinaryTypeTrait}\iref{meta.rqmts} +with a base characteristic of +\tcode{true_type} if the corresponding condition is true, otherwise +\tcode{false_type}. + +\begin{libreqtab3f}{Type relationship predicates}{meta.rel} +\\ \topline +\lhdr{Template} & \chdr{Condition} & \rhdr{Comments} \\ \capsep +\endfirsthead +\continuedcaption\\ +\topline +\lhdr{Template} & \chdr{Condition} & \rhdr{Comments} \\ \capsep +\endhead +\tcode{template}\br + \tcode{struct is_same;} & + \tcode{T} and \tcode{U} name the same type with the same cv-qualifications & \\ \rowsep + +\indexlibraryglobal{is_base_of}% +\tcode{template}\br + \tcode{struct is_base_of;} & + \tcode{Base} is a base class of \tcode{Derived}\iref{class.derived} + without regard to cv-qualifiers + or \tcode{Base} and \tcode{Derived} are not unions and + name the same class type + without regard to cv-qualifiers & + If \tcode{Base} and + \tcode{Derived} are non-union class types and are +not possibly cv-qualified versions of the same type, + \tcode{Derived} shall be a complete + type. + \begin{tailnote} +Base classes that are private, protected, or ambiguous + are, nonetheless, base classes. +\end{tailnote} +\\ \rowsep + +\indexlibraryglobal{is_convertible}% +\tcode{template}\br + \tcode{struct is_convertible;} & + \seebelow & + \tcode{From} and \tcode{To} shall be complete types, + \cv{}~\keyword{void}, or arrays of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_nothrow_convertible}% +\tcode{template}\br + \tcode{struct is_nothrow_convertible;} & + \tcode{is_convertible_v} is \tcode{true} and + the conversion, as defined by \tcode{is_convertible}, + is known not to throw any exceptions\iref{expr.unary.noexcept} & + \tcode{From} and \tcode{To} shall be complete types, + \cv{}~\keyword{void}, or arrays of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_layout_compatible}% +\tcode{template}\br + \tcode{struct is_layout_compatible;} & + \tcode{T} and \tcode{U} are layout-compatible\iref{term.layout.compatible.type} & + \tcode{T} and \tcode{U} shall be complete types, + \cv{}~\keyword{void}, + or arrays of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_pointer_interconvertible_base_of}% +\tcode{template}\br + \tcode{struct is_pointer_interconvertible_base_of;} & + \tcode{Derived} is unambiguously derived from \tcode{Base} + without regard to cv-qualifiers, + and each object of type \tcode{Derived} + is pointer-interconvertible\iref{basic.compound} with + its \tcode{Base} subobject, + or \tcode{Base} and \tcode{Derived} are not unions + and name the same class type + without regard to cv-qualifiers. & + If \tcode{Base} and \tcode{Derived} are non-union class types + and are not (possibly cv-qualified versions of) the same type, + \tcode{Derived} shall be a complete type. \\ \rowsep + +\indexlibraryglobal{is_invocable}% +\tcode{template}\br + \tcode{struct is_invocable;} & + The expression \tcode{\placeholdernc{INVOKE}(declval(), declval()...)} + is well-formed when treated as an unevaluated operand\iref{term.unevaluated.operand} & + \tcode{Fn} and all types in the template parameter pack \tcode{ArgTypes} + shall be complete types, \cv{}~\keyword{void}, or + arrays of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_invocable_r}% +\tcode{template}\br + \tcode{struct is_invocable_r;} & + The expression \tcode{\placeholdernc{INVOKE}(declval(), declval()...)} + is well-formed when treated as an unevaluated operand & + \tcode{Fn}, \tcode{R}, and all types in the template parameter pack \tcode{ArgTypes} + shall be complete types, \cv{}~\keyword{void}, or + arrays of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_nothrow_invocable}% +\tcode{template}\br + \tcode{struct is_nothrow_invocable;} & + \tcode{is_invocable_v<}\br\tcode{Fn, ArgTypes...>} is \tcode{true} and + the expression \tcode{\placeholdernc{INVOKE}(declval(), declval()...)} + is known not to throw any exceptions\iref{expr.unary.noexcept} & + \tcode{Fn} and all types in the template parameter pack \tcode{ArgTypes} + shall be complete types, \cv{}~\keyword{void}, or + arrays of unknown bound. \\ \rowsep + +\indexlibraryglobal{is_nothrow_invocable_r}% +\tcode{template}\br + \tcode{struct is_nothrow_invocable_r;} & + \tcode{is_invocable_r_v<}\br\tcode{R, Fn, ArgTypes...>} is \tcode{true} and + the expression \tcode{\placeholdernc{INVOKE}(declval(), declval()...)} + is known not to throw any exceptions\iref{expr.unary.noexcept} & + \tcode{Fn}, \tcode{R}, and all types in the template parameter pack \tcode{ArgTypes} + shall be complete types, \cv{}~\keyword{void}, or + arrays of unknown bound. \\ +\end{libreqtab3f} + +\pnum +For the purpose of defining the templates in this subclause, +a function call expression \tcode{declval()} for any type \tcode{T} +is considered to be a trivial\iref{term.trivial.type,special} function call +that is not an odr-use\iref{term.odr.use} of \tcode{declval} +in the context of the corresponding definition +notwithstanding the restrictions of~\ref{declval}. + +\pnum +\begin{example} +\begin{codeblock} +struct B {}; +struct B1 : B {}; +struct B2 : B {}; +struct D : private B1, private B2 {}; + +is_base_of_v // \tcode{true} +is_base_of_v // \tcode{true} +is_base_of_v // \tcode{true} +is_base_of_v // \tcode{true} +is_base_of_v // \tcode{false} +is_base_of_v // \tcode{false} +is_base_of_v // \tcode{false} +is_base_of_v // \tcode{false} +\end{codeblock} +\end{example} + +\indexlibraryglobal{is_convertible}% +\pnum +The predicate condition for a template specialization \tcode{is_convertible} +shall be satisfied if and only if the return expression in the following code would be +well-formed, including any implicit conversions to the return type of the function: + +\begin{codeblock} +To test() { + return declval(); +} +\end{codeblock} + +\begin{note} +This requirement gives well-defined results for reference types, +array types, function types, and \cv{}~\keyword{void}. +\end{note} +Access checking is performed +in a context unrelated to \tcode{To} and \tcode{From}. Only the validity of +the immediate context of the \grammarterm{expression} of the \tcode{return} statement\iref{stmt.return} +(including initialization of the returned object or reference) is considered. +\begin{note} +The +initialization can result in side effects such as the +instantiation of class template specializations and function template +specializations, the generation of implicitly-defined functions, and so on. Such +side effects are not in the ``immediate context'' and can result in the program +being ill-formed. +\end{note} + +\rSec2[meta.trans]{Transformations between types} + +\rSec3[meta.trans.general]{General} +\pnum +Subclause \ref{meta.trans} contains templates that may be used to transform one +type to another following some predefined rule. + +\pnum +Each of the templates in \ref{meta.trans} shall be a +\oldconcept{TransformationTrait}\iref{meta.rqmts}. + +\rSec3[meta.trans.cv]{Const-volatile modifications} + +\begin{libreqtab2a}{Const-volatile modifications}{meta.trans.cv} +\\ \topline +\lhdr{Template} & \rhdr{Comments} \\ \capsep +\endfirsthead +\continuedcaption\\ +\topline +\lhdr{Template} & \rhdr{Comments} \\ \capsep +\endhead + +\indexlibraryglobal{remove_const}% +\tcode{template\br + struct remove_const;} & + The member typedef \tcode{type} names + the same type as \tcode{T} + except that any top-level const-qualifier has been removed. + \begin{tailexample} +\tcode{remove_const_t} evaluates + to \tcode{volatile int}, whereas \tcode{remove_const_t} evaluates to + \tcode{const int*}. +\end{tailexample} +\\ \rowsep + +\indexlibraryglobal{remove_volatile}% +\tcode{template\br + struct remove_volatile;} & + The member typedef \tcode{type} names + the same type as \tcode{T} + except that any top-level volatile-qualifier has been removed. + \begin{tailexample} +\tcode{remove_volatile_t} + evaluates to \tcode{const int}, + whereas \tcode{remove_volatile_t} evaluates to \tcode{volatile int*}. + \end{tailexample} +\\ \rowsep + +\indexlibraryglobal{remove_cv}% +\tcode{template\br + struct remove_cv;} & + The member typedef \tcode{type} shall be the same as \tcode{T} + except that any top-level cv-qualifier has been removed. + \begin{tailexample} +\tcode{remove_cv_t} + evaluates to \tcode{int}, whereas \tcode{remove_cv_t} + evaluates to \tcode{const volatile int*}. +\end{tailexample} +\\ \rowsep + +\indexlibraryglobal{add_const}% +\tcode{template\br + struct add_const;} & + If \tcode{T} is a reference, function, or top-level const-qualified + type, then \tcode{type} names + the same type as \tcode{T}, otherwise + \tcode{T const}. \\ \rowsep + +\indexlibraryglobal{add_volatile}% +\tcode{template\br + struct add_volatile;} & + If \tcode{T} is a reference, function, or top-level volatile-qualified + type, then \tcode{type} names + the same type as \tcode{T}, otherwise + \tcode{T volatile}. \\ \rowsep + +\indexlibraryglobal{add_cv}% +\tcode{template\br + struct add_cv;} & + The member typedef \tcode{type} names + the same type as + \tcode{add_const_t>}. \\ +\end{libreqtab2a} + +\rSec3[meta.trans.ref]{Reference modifications} + +\begin{libreqtab2a}{Reference modifications}{meta.trans.ref} +\\ \topline +\lhdr{Template} & \rhdr{Comments} \\ \capsep +\endfirsthead +\continuedcaption\\ +\topline +\lhdr{Template} & \rhdr{Comments} \\ \capsep +\endhead + +\indexlibraryglobal{remove_reference}% +\tcode{template\br + struct remove_reference;} & + If \tcode{T} has type ``reference to \tcode{T1}'' then the + member typedef \tcode{type} names \tcode{T1}; + otherwise, \tcode{type} names \tcode{T}.\\ \rowsep + +\indexlibraryglobal{add_lvalue_reference}% +\tcode{template\br + struct add_lvalue_reference;} & + If \tcode{T} names a referenceable type\iref{defns.referenceable} then + the member typedef \tcode{type} names \tcode{T\&}; + otherwise, \tcode{type} names \tcode{T}. + \begin{tailnote} + This rule reflects the semantics of reference collapsing\iref{dcl.ref}. + \end{tailnote} +\\ \rowsep + +\indexlibraryglobal{add_rvalue_reference}% +\tcode{template}\br + \tcode{struct add_rvalue_reference;} & + If \tcode{T} names a referenceable type then + the member typedef \tcode{type} names \tcode{T\&\&}; + otherwise, \tcode{type} names \tcode{T}. + \begin{tailnote} +This rule reflects the semantics of reference collapsing\iref{dcl.ref}. + For example, when a type \tcode{T} names a type \tcode{T1\&}, the type + \tcode{add_rvalue_reference_t} is not an rvalue reference. + \end{tailnote} +\\ +\end{libreqtab2a} + +\rSec3[meta.trans.sign]{Sign modifications} +\begin{libreqtab2a}{Sign modifications}{meta.trans.sign} +\\ \topline +\lhdr{Template} & \rhdr{Comments} \\ \capsep +\endfirsthead +\continuedcaption\\ +\topline +\lhdr{Template} & \rhdr{Comments} \\ \capsep +\endhead + +\indexlibraryglobal{make_signed}% +\tcode{template}\br + \tcode{struct make_signed;} & + If \tcode{T} names a (possibly cv-qualified) signed integer + type\iref{basic.fundamental} then the member typedef + \tcode{type} names the type \tcode{T}; otherwise, + if \tcode{T} names a (possibly cv-qualified) unsigned integer + type then \tcode{type} names the corresponding + signed integer type, with the same cv-qualifiers as \tcode{T}; + otherwise, \tcode{type} names the signed integer type with smallest + rank\iref{conv.rank} for which + \tcode{sizeof(T) == sizeof(type)}, with the same + cv-qualifiers as \tcode{T}.\br + \mandates \tcode{T} is an integral or enumeration type + other than \cv~\tcode{bool}.\\ \rowsep + +\indexlibraryglobal{make_unsigned}% +\tcode{template}\br + \tcode{struct make_unsigned;} & + If \tcode{T} names a (possibly cv-qualified) unsigned integer + type\iref{basic.fundamental} then the member typedef + \tcode{type} names the type \tcode{T}; otherwise, + if \tcode{T} names a (possibly cv-qualified) signed integer + type then \tcode{type} names the corresponding + unsigned integer type, with the same cv-qualifiers as \tcode{T}; + otherwise, \tcode{type} names the unsigned integer type with smallest + rank\iref{conv.rank} for which + \tcode{sizeof(T) == sizeof(type)}, with the same + cv-qualifiers as \tcode{T}.\br + \mandates \tcode{T} is an integral or enumeration type + other than \cv~\tcode{bool}.\\ +\end{libreqtab2a} + +\rSec3[meta.trans.arr]{Array modifications} +\begin{libreqtab2a}{Array modifications}{meta.trans.arr} +\\ \topline +\lhdr{Template} & \rhdr{Comments} \\ \capsep +\endfirsthead +\continuedcaption\\ +\topline +\lhdr{Template} & \rhdr{Comments} \\ \capsep +\endhead + +\indexlibraryglobal{remove_extent}% +\tcode{template\br + struct remove_extent;} & + If \tcode{T} names a type ``array of \tcode{U}'', + the member typedef \tcode{type} shall + be \tcode{U}, otherwise \tcode{T}. + \begin{tailnote} +For multidimensional arrays, only the first array dimension is + removed. For a type ``array of \tcode{const U}'', the resulting type is + \tcode{const U}. +\end{tailnote} +\\ \rowsep + +\indexlibraryglobal{remove_all_extents}% +\tcode{template\br + struct remove_all_extents;} & + If \tcode{T} is ``multi-dimensional array of \tcode{U}'', the resulting member + typedef \tcode{type} is \tcode{U}, otherwise \tcode{T}. \\ +\end{libreqtab2a} + +\pnum +\begin{example} +\begin{codeblock} +// the following assertions hold: +assert((is_same_v, int>)); +assert((is_same_v, int>)); +assert((is_same_v, int[3]>)); +assert((is_same_v, int[3]>)); +\end{codeblock} +\end{example} + +\pnum +\begin{example} +\begin{codeblock} +// the following assertions hold: +assert((is_same_v, int>)); +assert((is_same_v, int>)); +assert((is_same_v, int>)); +assert((is_same_v, int>)); +\end{codeblock} +\end{example} + +\rSec3[meta.trans.ptr]{Pointer modifications} +\begin{libreqtab2a}{Pointer modifications}{meta.trans.ptr} +\\ \topline +\lhdr{Template} & \rhdr{Comments} \\ \capsep +\endfirsthead +\continuedcaption\\ +\topline +\lhdr{Template} & \rhdr{Comments} \\ \capsep +\endhead + +\indexlibraryglobal{remove_pointer}% +\tcode{template\br + struct remove_pointer;} & + If \tcode{T} has type ``(possibly cv-qualified) pointer + to \tcode{T1}'' then the member typedef \tcode{type} + names \tcode{T1}; otherwise, it names \tcode{T}.\\ \rowsep + +\indexlibraryglobal{add_pointer}% +\tcode{template\br + struct add_pointer;} & + If \tcode{T} names a referenceable type\iref{defns.referenceable} or a + \cv{}~\keyword{void} type then + the member typedef \tcode{type} names the same type as + \tcode{remove_reference_t*}; + otherwise, \tcode{type} names \tcode{T}. \\ +\end{libreqtab2a} + +\rSec3[meta.trans.other]{Other transformations} + +\begin{libreqtab2a}{Other transformations}{meta.trans.other} +\\ \topline +\lhdr{Template} & \rhdr{Comments} \\ \capsep +\endfirsthead +\continuedcaption\\ +\topline +\lhdr{Template} & \rhdr{Comments} \\ \capsep +\endhead + +\indexlibraryglobal{type_identity}% +\tcode{template\br + struct type_identity;} + & + The member typedef \tcode{type} names the type \tcode{T}. \\ \rowsep + +\indexlibraryglobal{remove_cvref}% +\tcode{template\br struct remove_cvref;} + & + The member typedef \tcode{type} names the same type as + \tcode{remove_cv_t>}. + \\ \rowsep + +\indexlibraryglobal{decay}% +\tcode{template\br struct decay;} + & + Let \tcode{U} be \tcode{remove_reference_t}. If \tcode{is_array_v} is + \tcode{true}, the member typedef \tcode{type} equals + \tcode{remove_extent_t*}. If \tcode{is_function_v} is \tcode{true}, + the member typedef \tcode{type} equals \tcode{add_pointer_t}. Otherwise + the member typedef \tcode{type} equals \tcode{remove_cv_t}. +\begin{tailnote} +This behavior is similar to the lvalue-to-rvalue\iref{conv.lval}, +array-to-pointer\iref{conv.array}, and function-to-pointer\iref{conv.func} +conversions applied when an lvalue is used as an rvalue, but also +strips cv-qualifiers from class types in order to more closely model by-value +argument passing. +\end{tailnote} + \\ \rowsep + +\indexlibraryglobal{enable_if}% +\tcode{template} \tcode{struct enable_if;} + & + If \tcode{B} is \tcode{true}, the member typedef \tcode{type} + shall equal \tcode{T}; otherwise, there shall be no member + \tcode{type}. \\ \rowsep + +\tcode{template}\br + \tcode{struct conditional;} + & + If \tcode{B} is \tcode{true}, the member typedef \tcode{type} shall equal \tcode{T}. + If \tcode{B} is \tcode{false}, the member typedef \tcode{type} shall equal \tcode{F}. \\ \rowsep + + \tcode{template} \tcode{struct common_type;} + & + Unless this trait is specialized (as specified in Note B, below), + the member \tcode{type} is defined or omitted as specified in Note A, below. + If it is omitted, there shall be no member \tcode{type}. + Each type in the template parameter pack \tcode{T} shall be + complete, \cv{}~\keyword{void}, or an array of unknown bound. \\ \rowsep + +\indexlibraryglobal{basic_common_reference}% +\tcode{template class,} + \hspace*{2ex}\tcode{template class>} + \keyword{struct} + \hspace*{2ex}\tcode{basic_common_reference;} + & + Unless this trait is specialized (as specified in Note D, below), + there shall be no member \tcode{type}. \\ \rowsep + +\indexlibraryglobal{common_reference}% +\tcode{template} \tcode{struct common_reference;} + & + The member \grammarterm{typedef-name} \tcode{type} is defined or omitted + as specified in Note C, below. Each type in the parameter pack \tcode{T} shall + be complete or \cv{} \keyword{void}. \\ \rowsep + +\indexlibraryglobal{underlying_type}% +\tcode{template}\br + \tcode{struct underlying_type;} + & + If \tcode{T} is an enumeration type, the member typedef \tcode{type} names + the underlying type of \tcode{T}\iref{dcl.enum}; + otherwise, there is no member \tcode{type}.\br + \mandates \tcode{T} is not an incomplete enumeration type. \\ \rowsep + +\tcode{template}\br + \tcode{struct invoke_result;} + & + If the expression \tcode{\placeholdernc{INVOKE}(declval(), declval()...)} + is well-formed when treated as an unevaluated operand\iref{term.unevaluated.operand}, + the member typedef \tcode{type} names the type + \tcode{decltype(\placeholdernc{INVOKE}(declval(), declval()...))}; + otherwise, there shall be no member \tcode{type}. Access checking is + performed as if in a context unrelated to \tcode{Fn} and + \tcode{ArgTypes}. Only the validity of the immediate context of the + expression is considered. + \begin{note} + The compilation of the expression can result in side effects such as + the instantiation of class template specializations and function + template specializations, the generation of implicitly-defined + functions, and so on. Such side effects are not in the ``immediate + context'' and can result in the program being ill-formed. + \end{note} + \expects \tcode{Fn} and all types in the template parameter pack \tcode{ArgTypes} + are complete types, \cv{}~\keyword{void}, or arrays of + unknown bound.\\ \rowsep + +\indexlibraryglobal{unwrap_reference}% +\tcode{template} \tcode{struct unwrap_reference;} + & + If \tcode{T} is + a specialization \tcode{reference_wrapper} for some type \tcode{X}, + the member typedef \tcode{type} of \tcode{unwrap_reference} is \tcode{X\&}, + otherwise it is \tcode{T}. \\ \rowsep + +\indexlibraryglobal{unwrap_ref_decay}% +\tcode{template} \tcode{unwrap_ref_decay;} + & + The member typedef \tcode{type} of \tcode{unwrap_ref_decay} + denotes the type \tcode{unwrap_reference_t>}.\\ +\end{libreqtab2a} + +\pnum +In addition to being available via inclusion +of the \tcode{} header, the templates +\tcode{unwrap_reference}, +\tcode{unwrap_ref_decay}, +\tcode{unwrap_reference_t}, and +\tcode{unwrap_ref_decay_t} +are available +when the header \tcode{}\iref{functional.syn} is included. + +\indexlibraryglobal{common_type}% +\pnum +Let: +\begin{itemize} +\item \tcode{\placeholdernc{CREF}(A)} be + \tcode{add_lvalue_reference_t{}>}, +\item \tcode{\placeholdernc{XREF}(A)} denote a unary alias template \tcode{T} + such that \tcode{T} denotes the same type as \tcode{U} with the addition + of \tcode{A}'s cv and reference qualifiers, for a non-reference cv-unqualified + type \tcode{U}, +\item \tcode{\placeholdernc{COPYCV}(FROM, TO)} be an alias for type \tcode{TO} + with the addition of \tcode{FROM}'s top-level cv-qualifiers, + \begin{example} + \tcode{\placeholdernc{COPYCV}(const int, volatile short)} is an alias for + \tcode{const volatile short}. + \end{example} +\item \tcode{\placeholdernc{COND-RES}(X, Y)} be + \tcode{decltype(false ?\ declval()() :\ declval()())}. +\end{itemize} +Given types \tcode{A} and \tcode{B}, +let \tcode{X} be \tcode{remove_reference_t}, +let \tcode{Y} be \tcode{remove_reference_t}, and +let \tcode{\placeholdernc{COMMON-\brk{}REF}(A, B)} be: +\begin{itemize} +\item If \tcode{A} and \tcode{B} are both lvalue reference types, + \tcode{\placeholdernc{COMMON-REF}(A, B)} is + \tcode{\placeholdernc{COND-RES}(\placeholdernc{COPYCV}(X, Y) \&, + \placeholdernc{COPYCV}(\brk{}Y, X) \&)} if that type exists + and is a reference type. +\item Otherwise, let \tcode{C} be + \tcode{remove_reference_t<\placeholdernc{COMMON-REF}(X\&, Y\&)>\&\&}. + If \tcode{A} and \tcode{B} are both rvalue reference types, + \tcode{C} is well-formed, and + \tcode{is_convertible_v \&\& is_convertible_v} is \tcode{true}, + then \tcode{\placeholdernc{COMMON-REF}(A, B)} is \tcode{C}. +\item Otherwise, let \tcode{D} be + \tcode{\placeholdernc{COMMON-REF}(const X\&, Y\&)}. If \tcode{A} is an rvalue + reference and \tcode{B} is an lvalue reference and \tcode{D} is + well-formed and \tcode{is_convertible_v} is + \tcode{true}, then \tcode{\placeholdernc{COMMON-REF}(A, B)} is \tcode{D}. +\item Otherwise, if \tcode{A} is an lvalue reference and \tcode{B} + is an rvalue reference, then \tcode{\placeholdernc{COMMON-REF}(A, B)} is + \tcode{\placeholdernc{COMMON-REF}(B, A)}. +\item Otherwise, \tcode{\placeholdernc{COMMON-REF}(A, B)} is ill-formed. +\end{itemize} + +If any of the types computed above is ill-formed, then +\tcode{\placeholdernc{COMMON-REF}(A, B)} is ill-formed. + +\pnum +Note A: +For the \tcode{common_type} trait applied to a template parameter pack \tcode{T} of types, +the member \tcode{type} shall be either defined or not present as follows: + +\begin{itemize} +\item If \tcode{sizeof...(T)} is zero, there shall be no member \tcode{type}. + +\item If \tcode{sizeof...(T)} is one, let \tcode{T0} denote the sole type +constituting the pack \tcode{T}. +The member \grammarterm{typedef-name} \tcode{type} shall denote the same +type, if any, as \tcode{common_type_t}; +otherwise there shall be no member \tcode{type}. + +\item If \tcode{sizeof...(T)} is two, +let the first and second types constituting \tcode{T} be denoted +by \tcode{T1} and \tcode{T2}, respectively, and +let \tcode{D1} and \tcode{D2} denote +the same types as \tcode{decay_t} and \tcode{decay_t}, respectively. + \begin{itemize} + \item If \tcode{is_same_v} is \tcode{false} or + \tcode{is_same_v} is \tcode{false}, + let \tcode{C} denote the same type, if any, + as \tcode{common_type_t}. + \item + \begin{note} + None of the following will apply if there is a specialization + \tcode{common_type}. + \end{note} + \item Otherwise, if +\begin{codeblock} +decay_t() : declval())> +\end{codeblock} + denotes a valid type, let \tcode{C} denote that type. + \item Otherwise, if + \tcode{\placeholdernc{COND-RES}(\placeholdernc{CREF}(D1), + \placeholdernc{CREF}(D2))} + denotes a type, let \tcode{C} denote the type + \tcode{decay_t<\placeholdernc{COND-RES}(\placeholdernc{CREF}(D1), + \placeholdernc{CREF}(D2))>}. + \end{itemize} +In either case, the member \grammarterm{typedef-name} \tcode{type} shall denote +the same type, if any, as \tcode{C}. +Otherwise, there shall be no member \tcode{type}. + +\item If \tcode{sizeof...(T)} is greater than two, +let \tcode{T1}, \tcode{T2}, and \tcode{R}, respectively, +denote the first, second, and (pack of) remaining types constituting \tcode{T}. +Let \tcode{C} denote the same type, if any, as \tcode{common_type_t}. +If there is such a type \tcode{C}, the member \grammarterm{typedef-name} \tcode{type} +shall denote the same type, if any, as \tcode{common_type_t}. +Otherwise, there shall be no member \tcode{type}. +\end{itemize} + +\pnum +Note B: Notwithstanding the provisions of \ref{meta.type.synop}, and +pursuant to \ref{namespace.std}, +a program may specialize \tcode{common_type} +for types \tcode{T1} and \tcode{T2} such that +\tcode{is_same_v>} and +\tcode{is_same_v>} are each \tcode{true}. +\begin{note} +Such specializations are needed when only explicit conversions +are desired between the template arguments. +\end{note} +Such a specialization need not have a member named \tcode{type}, +but if it does, +the \grammarterm{qualified-id} \tcode{common_type::type} shall denote +a cv-unqualified non-reference type +to which each of the types \tcode{T1} and \tcode{T2} is explicitly convertible. +Moreover, \tcode{common_type_t} shall denote +the same type, if any, as does \tcode{common_type_t}. +No diagnostic is required for a violation of this Note's rules. + +\pnum +Note C: For the \tcode{common_reference} trait applied to a parameter pack +\tcode{T} of types, the member \tcode{type} shall be either defined or not +present as follows: +\begin{itemize} +\item If \tcode{sizeof...(T)} is zero, there shall be no member \tcode{type}. + +\item Otherwise, if \tcode{sizeof...(T)} is one, let \tcode{T0} denote the sole + type in the pack \tcode{T}. The member typedef \tcode{type} shall denote the + same type as \tcode{T0}. + +\item Otherwise, if \tcode{sizeof...(T)} is two, let \tcode{T1} and \tcode{T2} + denote the two types in the pack \tcode{T}. Then + \begin{itemize} + \item If \tcode{T1} and \tcode{T2} are reference types and + \tcode{\placeholdernc{COMMON-REF}(T1, T2)} is well-formed, then the member + typedef \tcode{type} denotes that type. + + \item Otherwise, if + \tcode{basic_common_reference, remove_cvref_t, + \brk{}\placeholdernc{XREF}(\brk{}T1), \placeholdernc{XREF}(T2)>::type} + is well-formed, then the member typedef \tcode{type} denotes that type. + + \item Otherwise, if \tcode{\placeholdernc{COND-RES}(T1, T2)} is well-formed, + then the member typedef \tcode{type} denotes that type. + + \item Otherwise, if \tcode{common_type_t} is well-formed, then the + member typedef \tcode{type} denotes that type. + + \item Otherwise, there shall be no member \tcode{type}. + \end{itemize} + +\item Otherwise, if \tcode{sizeof...(T)} is greater than two, let \tcode{T1}, + \tcode{T2}, and \tcode{Rest}, respectively, denote the first, second, and + (pack of) remaining types comprising \tcode{T}. Let \tcode{C} be the type + \tcode{common_reference_t}. Then: + \begin{itemize} + \item If there is such a type \tcode{C}, the member typedef \tcode{type} shall + denote the same type, if any, as \tcode{common_reference_t}. + + \item Otherwise, there shall be no member \tcode{type}. + \end{itemize} +\end{itemize} + +\pnum +Note D: Notwithstanding the provisions of \ref{meta.type.synop}, and +pursuant to \ref{namespace.std}, a program may partially specialize +\tcode{basic_common_reference} +for types \tcode{T} and \tcode{U} such that +\tcode{is_same_v>} and +\tcode{is_same_v>} are each \tcode{true}. +\begin{note} +Such specializations +can be used to influence the result of \tcode{common_reference}, and +are needed when only explicit conversions are desired +between the template arguments. +\end{note} +Such a specialization need not have a member named \tcode{type}, but if it does, +the \grammarterm{qualified-id} +\tcode{basic_common_reference::type} +shall denote a type +to which each of the types \tcode{TQual} and +\tcode{UQual} is convertible. +Moreover, \tcode{basic_common_reference::type} shall denote +the same type, if any, as does +\tcode{basic_common_reference::type}. +No diagnostic is required for a violation of these rules. + +\pnum +\begin{example} +Given these definitions: +\begin{codeblock} +using PF1 = bool (&)(); +using PF2 = short (*)(long); + +struct S { + operator PF2() const; + double operator()(char, int&); + void fn(long) const; + char data; +}; + +using PMF = void (S::*)(long) const; +using PMD = char S::*; +\end{codeblock} +the following assertions will hold: +\begin{codeblock} +static_assert(is_same_v, short>); +static_assert(is_same_v, double>); +static_assert(is_same_v, bool>); +static_assert(is_same_v, int>, void>); +static_assert(is_same_v, char&&>); +static_assert(is_same_v, const char&>); +\end{codeblock} +\end{example} + +\rSec2[meta.logical]{Logical operator traits} + +\pnum +This subclause describes type traits for applying logical operators +to other type traits. + +\indexlibraryglobal{conjunction}% +\begin{itemdecl} +template struct conjunction : @\seebelow@ { }; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The class template \tcode{conjunction} +forms the logical conjunction of its template type arguments. + +\pnum +For a specialization \tcode{conjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>}, +if there is a template type argument $\tcode{B}_{i}$ +for which \tcode{bool($\tcode{B}_{i}$::value)} is \tcode{false}, +then instantiating \tcode{conjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>::value} +does not require the instantiation of \tcode{$\tcode{B}_{j}$::value} for $j > i$. +\begin{note} +This is analogous to the short-circuiting behavior of +the built-in operator \tcode{\&\&}. +\end{note} + +\pnum +Every template type argument +for which \tcode{$\tcode{B}_{i}$::value} is instantiated +shall be usable as a base class and +shall have a member \tcode{value} which +is convertible to \tcode{bool}, +is not hidden, and +is unambiguously available in the type. + +\pnum +The specialization \tcode{conjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>} +has a public and unambiguous base that is either +\begin{itemize} +\item +the first type $\tcode{B}_{i}$ in the list \tcode{true_type, $\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$} +for which \tcode{bool($\tcode{B}_{i}$::value)} is \tcode{false}, or +\item +if there is no such $\tcode{B}_{i}$, the last type in the list. +\end{itemize} +\begin{note} +This means a specialization of \tcode{conjunction} +does not necessarily inherit from +either \tcode{true_type} or \tcode{false_type}. +\end{note} + +\pnum +The member names of the base class, other than \tcode{conjunction} and +\tcode{operator=}, shall not be hidden and shall be unambiguously available +in \tcode{conjunction}. +\end{itemdescr} + +\indexlibraryglobal{disjunction}% +\begin{itemdecl} +template struct disjunction : @\seebelow@ { }; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The class template \tcode{disjunction} +forms the logical disjunction of its template type arguments. + +\pnum +For a specialization \tcode{disjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>}, +if there is a template type argument $\tcode{B}_{i}$ +for which \tcode{bool($\tcode{B}_{i}$::value)} is \tcode{true}, +then instantiating \tcode{disjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>::value} +does not require the instantiation of \tcode{$\tcode{B}_{j}$::value} for $j > i$. +\begin{note} +This is analogous to the short-circuiting behavior of +the built-in operator \tcode{||}. +\end{note} + +\pnum +Every template type argument +for which \tcode{$\tcode{B}_{i}$::value} is instantiated +shall be usable as a base class and +shall have a member \tcode{value} which +is convertible to \tcode{bool}, +is not hidden, and +is unambiguously available in the type. + +\pnum +The specialization \tcode{disjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>} +has a public and unambiguous base that is either +\begin{itemize} +\item the first type $\tcode{B}_{i}$ in the list \tcode{false_type, $\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$} +for which \tcode{bool($\tcode{B}_{i}$::value)} is \tcode{true}, or +\item if there is no such $\tcode{B}_{i}$, the last type in the list. +\end{itemize} +\begin{note} +This means a specialization of \tcode{disjunction} +does not necessarily inherit from +either \tcode{true_type} or \tcode{false_type}. +\end{note} + +\pnum +The member names of the base class, +other than \tcode{disjunction} and \tcode{operator=}, +shall not be hidden and shall be unambiguously available in \tcode{disjunction}. +\end{itemdescr} + +\indexlibraryglobal{negation}% +\begin{itemdecl} +template struct negation : @\seebelow@ { }; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The class template \tcode{negation} +forms the logical negation of its template type argument. +The type \tcode{negation} +is a \oldconcept{UnaryTypeTrait} with a base characteristic of \tcode{bool_constant}. +\end{itemdescr} + +\rSec2[meta.member]{Member relationships} + +\indexlibraryglobal{is_pointer_interconvertible_with_class} +\begin{itemdecl} +template + constexpr bool is_pointer_interconvertible_with_class(M S::*m) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{S} is a complete type. + +\pnum +\returns +\tcode{true} if and only if + \tcode{S} is a standard-layout type, + \tcode{M} is an object type, + \tcode{m} is not null, + and each object \tcode{s} of type \tcode{S} + is pointer-interconvertible\iref{basic.compound} + with its subobject \tcode{s.*m}. +\end{itemdescr} + +\indexlibraryglobal{is_corresponding_member} +\begin{itemdecl} +template + constexpr bool is_corresponding_member(M1 S1::*m1, M2 S2::*m2) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{S1} and \tcode{S2} are complete types. + +\pnum +\returns +\tcode{true} if and only if + \tcode{S1} and \tcode{S2} are standard-layout struct\iref{class.prop} types, + \tcode{M1} and \tcode{M2} are object types, + \tcode{m1} and \tcode{m2} are not null, + and \tcode{m1} and \tcode{m2} point to corresponding members of + the common initial sequence\iref{class.mem} of \tcode{S1} and \tcode{S2}. +\end{itemdescr} + +\pnum +\begin{note} +The type of a pointer-to-member expression \tcode{\&C::b} +is not always a pointer to member of \tcode{C}, +leading to potentially surprising results +when using these functions in conjunction with inheritance. +\begin{example} +\begin{codeblock} +struct A { int a; }; // a standard-layout class +struct B { int b; }; // a standard-layout class +struct C: public A, public B { }; // not a standard-layout class + +static_assert( is_pointer_interconvertible_with_class( &C::b ) ); + // Succeeds because, despite its appearance, \tcode{\&C::b} has type + // ``pointer to member of \tcode{B} of type \tcode{int}''. +static_assert( is_pointer_interconvertible_with_class( &C::b ) ); + // Forces the use of class \tcode{C}, and fails. + +static_assert( is_corresponding_member( &C::a, &C::b ) ); + // Succeeds because, despite its appearance, \tcode{\&C::a} and \tcode{\&C::b} have types + // ``pointer to member of \tcode{A} of type \tcode{int}'' and + // ``pointer to member of \tcode{B} of type \tcode{int}'', respectively. +static_assert( is_corresponding_member( &C::a, &C::b ) ); + // Forces the use of class \tcode{C}, and fails. +\end{codeblock} +\end{example} +\end{note} + +\rSec2[meta.const.eval]{Constant evaluation context} +\begin{itemdecl} +constexpr bool is_constant_evaluated() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +if consteval { + return true; +} else { + return false; +} +\end{codeblock} + +\pnum +\begin{example} +\begin{codeblock} +constexpr void f(unsigned char *p, int n) { + if (std::is_constant_evaluated()) { // should not be a constexpr if statement + for (int k = 0; k} synopsis} + +\indexheader{ratio}% +\begin{codeblockdigitsep} +namespace std { + // \ref{ratio.ratio}, class template \tcode{ratio} + template class ratio; + + // \ref{ratio.arithmetic}, ratio arithmetic + template using ratio_add = @\seebelow@; + template using ratio_subtract = @\seebelow@; + template using ratio_multiply = @\seebelow@; + template using ratio_divide = @\seebelow@; + + // \ref{ratio.comparison}, ratio comparison + template struct ratio_equal; + template struct ratio_not_equal; + template struct ratio_less; + template struct ratio_less_equal; + template struct ratio_greater; + template struct ratio_greater_equal; + + template + inline constexpr bool @\libglobal{ratio_equal_v}@ = ratio_equal::value; + template + inline constexpr bool @\libglobal{ratio_not_equal_v}@ = ratio_not_equal::value; + template + inline constexpr bool @\libglobal{ratio_less_v}@ = ratio_less::value; + template + inline constexpr bool @\libglobal{ratio_less_equal_v}@ = ratio_less_equal::value; + template + inline constexpr bool @\libglobal{ratio_greater_v}@ = ratio_greater::value; + template + inline constexpr bool @\libglobal{ratio_greater_equal_v}@ = ratio_greater_equal::value; + + // \ref{ratio.si}, convenience SI typedefs + using yocto = ratio<1, 1'000'000'000'000'000'000'000'000>; // see below + using zepto = ratio<1, 1'000'000'000'000'000'000'000>; // see below + using atto = ratio<1, 1'000'000'000'000'000'000>; + using femto = ratio<1, 1'000'000'000'000'000>; + using pico = ratio<1, 1'000'000'000'000>; + using nano = ratio<1, 1'000'000'000>; + using micro = ratio<1, 1'000'000>; + using milli = ratio<1, 1'000>; + using centi = ratio<1, 100>; + using deci = ratio<1, 10>; + using deca = ratio< 10, 1>; + using hecto = ratio< 100, 1>; + using kilo = ratio< 1'000, 1>; + using mega = ratio< 1'000'000, 1>; + using giga = ratio< 1'000'000'000, 1>; + using tera = ratio< 1'000'000'000'000, 1>; + using peta = ratio< 1'000'000'000'000'000, 1>; + using exa = ratio< 1'000'000'000'000'000'000, 1>; + using zetta = ratio< 1'000'000'000'000'000'000'000, 1>; // see below + using yotta = ratio<1'000'000'000'000'000'000'000'000, 1>; // see below +} +\end{codeblockdigitsep} + +\rSec2[ratio.ratio]{Class template \tcode{ratio}} + +\indexlibraryglobal{ratio}% +\begin{codeblock} +namespace std { + template class ratio { + public: + static constexpr intmax_t num; + static constexpr intmax_t den; + using type = ratio; + }; +} +\end{codeblock} + +\pnum +\indextext{signed integer representation!two's complement}% +If the template argument \tcode{D} is zero or the absolute values of either of the +template arguments \tcode{N} and \tcode{D} is not representable by type +\tcode{intmax_t}, the program is ill-formed. +\begin{note} +These rules ensure that infinite +ratios are avoided and that for any negative input, there exists a representable value +of its absolute value which is positive. +This excludes the most negative value. +\end{note} + +\pnum +The static data members \tcode{num} and \tcode{den} shall have the following values, +where \tcode{gcd} represents the greatest common divisor of the absolute values of +\tcode{N} and \tcode{D}: + +\begin{itemize} +\item \tcode{num} shall have the value \tcode{sign(N) * sign(D) * abs(N) / gcd}. +\item \tcode{den} shall have the value \tcode{abs(D) / gcd}. +\end{itemize} + +\rSec2[ratio.arithmetic]{Arithmetic on \tcode{ratio}{s}} + +\pnum +Each of the alias templates \tcode{ratio_add}, \tcode{ratio_subtract}, \tcode{ratio_multiply}, +and \tcode{ratio_divide} denotes the result of an arithmetic computation on two +\tcode{ratio}{s} \tcode{R1} and \tcode{R2}. With \tcode{X} and \tcode{Y} computed (in the +absence of arithmetic overflow) as specified by \tref{ratio.arithmetic}, each alias +denotes a \tcode{ratio} such that \tcode{U} is the same as \tcode{ratio::num} and +\tcode{V} is the same as \tcode{ratio::den}. + +\pnum +If it is not possible to represent \tcode{U} or \tcode{V} with \tcode{intmax_t}, the program is +ill-formed. Otherwise, an implementation should yield correct values of \tcode{U} and +\tcode{V}. If it is not possible to represent \tcode{X} or \tcode{Y} with \tcode{intmax_t}, the +program is ill-formed unless the implementation yields correct values of \tcode{U} and +\tcode{V}. + +\begin{floattable}{Expressions used to perform ratio arithmetic}{ratio.arithmetic} +{lll} +\topline +\lhdr{Type} & + \chdr{Value of \tcode{X}} & + \rhdr{Value of \tcode{Y}} \\ \rowsep + +\tcode{ratio_add} & + \tcode{R1::num * R2::den +} & + \tcode{R1::den * R2::den} \\ + & + \tcode{R2::num * R1::den} & + \\ \rowsep + +\tcode{ratio_subtract} & + \tcode{R1::num * R2::den -} & + \tcode{R1::den * R2::den} \\ + & + \tcode{R2::num * R1::den} & + \\ \rowsep + +\tcode{ratio_multiply} & + \tcode{R1::num * R2::num} & + \tcode{R1::den * R2::den} \\ \rowsep + +\tcode{ratio_divide} & + \tcode{R1::num * R2::den} & + \tcode{R1::den * R2::num} \\ +\end{floattable} + +\pnum +\begin{example} +\begin{codeblock} +static_assert(ratio_add, ratio<1, 6>>::num == 1, "1/3+1/6 == 1/2"); +static_assert(ratio_add, ratio<1, 6>>::den == 2, "1/3+1/6 == 1/2"); +static_assert(ratio_multiply, ratio<3, 2>>::num == 1, "1/3*3/2 == 1/2"); +static_assert(ratio_multiply, ratio<3, 2>>::den == 2, "1/3*3/2 == 1/2"); + +// The following cases may cause the program to be ill-formed under some implementations +static_assert(ratio_add, ratio<1, INT_MAX>>::num == 2, + "1/MAX+1/MAX == 2/MAX"); +static_assert(ratio_add, ratio<1, INT_MAX>>::den == INT_MAX, + "1/MAX+1/MAX == 2/MAX"); +static_assert(ratio_multiply, ratio>::num == 1, + "1/MAX * MAX/2 == 1/2"); +static_assert(ratio_multiply, ratio>::den == 2, + "1/MAX * MAX/2 == 1/2"); +\end{codeblock} + +\end{example} + +\rSec2[ratio.comparison]{Comparison of \tcode{ratio}{s}} + +\indexlibraryglobal{ratio_equal}% +\begin{itemdecl} +template + struct ratio_equal : bool_constant { }; +\end{itemdecl} + +\indexlibraryglobal{ratio_not_equal}% +\begin{itemdecl} +template + struct ratio_not_equal : bool_constant> { }; +\end{itemdecl} + +\indexlibraryglobal{ratio_less}% +\begin{itemdecl} +template + struct ratio_less : bool_constant<@\seebelow@> { }; +\end{itemdecl} + +\begin{itemdescr} +\pnum +If \tcode{R1::num} $\times$ \tcode{R2::den} is less than \tcode{R2::num} $\times$ \tcode{R1::den}, +\tcode{ratio_less} shall be +derived from \tcode{bool_constant}; otherwise it shall be derived from +\tcode{bool_constant}. Implementations may use other algorithms to +compute this relationship to avoid overflow. If overflow occurs, the program is ill-formed. +\end{itemdescr} + +\indexlibraryglobal{ratio_less_equal}% +\begin{itemdecl} +template + struct ratio_less_equal : bool_constant> { }; +\end{itemdecl} + +\indexlibraryglobal{ratio_greater}% +\begin{itemdecl} +template + struct ratio_greater : bool_constant> { }; +\end{itemdecl} + +\indexlibraryglobal{ratio_greater_equal}% +\begin{itemdecl} +template + struct ratio_greater_equal : bool_constant> { }; +\end{itemdecl} + +\rSec2[ratio.si]{SI types for \tcode{ratio}} + +\pnum +For each of the \grammarterm{typedef-name}{s} \tcode{yocto}, \tcode{zepto}, +\tcode{zetta}, and \tcode{yotta}, if both of the constants used in its +specification are representable by \tcode{intmax_t}, the typedef is +defined; if either of the constants is not representable by \tcode{intmax_t}, +the typedef is not defined. diff --git a/source/numerics.tex b/source/numerics.tex index 735d2a3238..811f7d9d90 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -20,7 +20,6 @@ \ref{numeric.requirements} & Requirements & \\ \rowsep \ref{cfenv} & Floating-point environment & \tcode{} \\ \rowsep \ref{complex.numbers} & Complex numbers & \tcode{} \\ \rowsep -\ref{bit} & Bit manipulation & \tcode{} \\ \rowsep \ref{rand} & Random number generation & \tcode{} \\ \rowsep \ref{numarray} & Numeric arrays & \tcode{} \\ \rowsep \ref{c.math} & Mathematical functions for floating-point types & @@ -1274,420 +1273,6 @@ \end{itemdescr} -\rSec1[bit]{Bit manipulation} - -\rSec2[bit.general]{General} - -\pnum -The header \libheaderdef{bit} provides components to access, -manipulate and process both individual bits and bit sequences. - -\rSec2[bit.syn]{Header \tcode{} synopsis} - -\begin{codeblock} -namespace std { - // \ref{bit.cast}, \tcode{bit_cast} - template - constexpr To bit_cast(const From& from) noexcept; - - // \ref{bit.byteswap}, \tcode{byteswap} - template - constexpr T byteswap(T value) noexcept; - - // \ref{bit.pow.two}, integral powers of 2 - template - constexpr bool has_single_bit(T x) noexcept; - template - constexpr T bit_ceil(T x); - template - constexpr T bit_floor(T x) noexcept; - template - constexpr T bit_width(T x) noexcept; - - // \ref{bit.rotate}, rotating - template - [[nodiscard]] constexpr T rotl(T x, int s) noexcept; - template - [[nodiscard]] constexpr T rotr(T x, int s) noexcept; - - // \ref{bit.count}, counting - template - constexpr int countl_zero(T x) noexcept; - template - constexpr int countl_one(T x) noexcept; - template - constexpr int countr_zero(T x) noexcept; - template - constexpr int countr_one(T x) noexcept; - template - constexpr int popcount(T x) noexcept; - - // \ref{bit.endian}, endian - enum class endian { - little = @\seebelow@, - big = @\seebelow@, - native = @\seebelow@ - }; -} -\end{codeblock} - -\rSec2[bit.cast]{Function template \tcode{bit_cast}} - -\indexlibraryglobal{bit_cast}% -\begin{itemdecl} -template - constexpr To bit_cast(const From& from) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\begin{itemize} -\item \tcode{sizeof(To) == sizeof(From)} is \tcode{true}; -\item \tcode{is_trivially_copyable_v} is \tcode{true}; and -\item \tcode{is_trivially_copyable_v} is \tcode{true}. -\end{itemize} - -\pnum -\returns -An object of type \tcode{To}. -Implicitly creates objects nested within the result\iref{intro.object}. -Each bit of the value representation of the result -is equal to the corresponding bit in the object representation -of \tcode{from}. Padding bits of the result are unspecified. -For the result and each object created within it, -if there is no value of the object's type corresponding to the -value representation produced, the behavior is undefined. -If there are multiple such values, which value is produced is unspecified. -A bit in the value representation of the result is indeterminate if -it does not correspond to a bit in the value representation of \tcode{from} or -corresponds to a bit of an object that is not within its lifetime or -has an indeterminate value\iref{basic.indet}. -For each bit in the value representation of the result that is indeterminate, -the smallest object containing that bit has an indeterminate value; -the behavior is undefined unless that object is -of unsigned ordinary character type or \tcode{std::byte} type. -The result does not otherwise contain any indeterminate values. - -\pnum -\remarks -This function is \keyword{constexpr} if and only if -\tcode{To}, \tcode{From}, and the types of all subobjects -of \tcode{To} and \tcode{From} are types \tcode{T} such that: -\begin{itemize} -\item \tcode{is_union_v} is \tcode{false}; -\item \tcode{is_pointer_v} is \tcode{false}; -\item \tcode{is_member_pointer_v} is \tcode{false}; -\item \tcode{is_volatile_v} is \tcode{false}; and -\item \tcode{T} has no non-static data members of reference type. -\end{itemize} -\end{itemdescr} - -\rSec2[bit.byteswap]{\tcode{byteswap}} - -\indexlibraryglobal{byteswap}% -\begin{itemdecl} -template - constexpr T byteswap(T value) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{T} models \libconcept{integral}. - -\pnum -\mandates -\tcode{T} does not have padding bits\iref{basic.types.general}. - -\pnum -Let the sequence $R$ comprise -the bytes of the object representation of \tcode{value} in reverse order. - -\pnum -\returns -An object \tcode{v} of type \tcode{T} -such that each byte in the object representation of \tcode{v} is equal to -the byte in the corresponding position in $R$. -\end{itemdescr} - -\rSec2[bit.pow.two]{Integral powers of 2} - -\indexlibraryglobal{has_single_bit}% -\begin{itemdecl} -template - constexpr bool has_single_bit(T x) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{T} is an unsigned integer type\iref{basic.fundamental}. - -\pnum -\returns -\tcode{true} if \tcode{x} is an integral power of two; -\tcode{false} otherwise. - -\end{itemdescr} - -\indexlibraryglobal{bit_ceil}% -\begin{itemdecl} -template - constexpr T bit_ceil(T x); -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let $N$ be the smallest power of 2 greater than or equal to \tcode{x}. - -\pnum -\constraints -\tcode{T} is an unsigned integer type\iref{basic.fundamental}. - -\pnum -\expects -$N$ is representable as a value of type \tcode{T}. - -\pnum -\returns -$N$. - -\pnum -\throws -Nothing. - -\pnum -\remarks -A function call expression -that violates the precondition in the \expects element -is not a core constant expression\iref{expr.const}. -\end{itemdescr} - -\indexlibraryglobal{bit_floor}% -\begin{itemdecl} -template - constexpr T bit_floor(T x) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{T} is an unsigned integer type\iref{basic.fundamental}. - -\pnum -\returns -If \tcode{x == 0}, \tcode{0}; -otherwise the maximal value \tcode{y} -such that \tcode{has_single_bit(y)} is \tcode{true} and \tcode{y <= x}. - -\end{itemdescr} - -\indexlibraryglobal{bit_width}% -\begin{itemdecl} -template - constexpr T bit_width(T x) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{T} is an unsigned integer type\iref{basic.fundamental}. - -\pnum -\returns -If \tcode{x == 0}, \tcode{0}; -otherwise one plus the base-2 logarithm of \tcode{x}, -with any fractional part discarded. - -\end{itemdescr} - -\rSec2[bit.rotate]{Rotating} - -\pnum -In the following descriptions, -let \tcode{N} denote \tcode{numeric_limits::digits}. - -\begin{itemdecl} -template - [[nodiscard]] constexpr T rotl(T x, int s) noexcept; -\end{itemdecl} - -\indexlibraryglobal{rotl}% -\begin{itemdescr} -\pnum -\constraints -\tcode{T} is an unsigned integer type\iref{basic.fundamental}. - -\pnum -Let \tcode{r} be \tcode{s \% N}. - -\pnum -\returns -If \tcode{r} is \tcode{0}, \tcode{x}; -if \tcode{r} is positive, \tcode{(x << r) | (x >> (N - r))}; -if \tcode{r} is negative, \tcode{rotr(x, -r)}. -\end{itemdescr} - -\begin{itemdecl} -template - [[nodiscard]] constexpr T rotr(T x, int s) noexcept; -\end{itemdecl} - -\indexlibraryglobal{rotr}% -\begin{itemdescr} -\pnum -\constraints -\tcode{T} is an unsigned integer type\iref{basic.fundamental}. - -\pnum -Let \tcode{r} be \tcode{s \% N}. - -\pnum -\returns -If \tcode{r} is \tcode{0}, \tcode{x}; -if \tcode{r} is positive, \tcode{(x >> r) | (x << (N - r))}; -if \tcode{r} is negative, \tcode{rotl(x, -r)}. -\end{itemdescr} - -\rSec2[bit.count]{Counting} - -\pnum -In the following descriptions, -let \tcode{N} denote \tcode{numeric_limits::digits}. - -\begin{itemdecl} -template - constexpr int countl_zero(T x) noexcept; -\end{itemdecl} - -\indexlibraryglobal{countl_zero}% -\begin{itemdescr} -\pnum -\constraints -\tcode{T} is an unsigned integer type\iref{basic.fundamental}. - -\pnum -\returns -The number of consecutive \tcode{0} bits in the value of \tcode{x}, -starting from the most significant bit. -\begin{note} -Returns \tcode{N} if \tcode{x == 0}. -\end{note} -\end{itemdescr} - -\begin{itemdecl} -template - constexpr int countl_one(T x) noexcept; -\end{itemdecl} - -\indexlibraryglobal{countl_one}% -\begin{itemdescr} -\pnum -\constraints -\tcode{T} is an unsigned integer type\iref{basic.fundamental}. - -\pnum -\returns -The number of consecutive \tcode{1} bits in the value of \tcode{x}, -starting from the most significant bit. -\begin{note} -Returns \tcode{N} if \tcode{x == numeric_limits::max()}. -\end{note} -\end{itemdescr} - -\begin{itemdecl} -template - constexpr int countr_zero(T x) noexcept; -\end{itemdecl} - -\indexlibraryglobal{countr_zero}% -\begin{itemdescr} -\pnum -\constraints -\tcode{T} is an unsigned integer type\iref{basic.fundamental}. - -\pnum -\returns -The number of consecutive \tcode{0} bits in the value of \tcode{x}, -starting from the least significant bit. -\begin{note} -Returns \tcode{N} if \tcode{x == 0}. -\end{note} -\end{itemdescr} - -\begin{itemdecl} -template - constexpr int countr_one(T x) noexcept; -\end{itemdecl} - -\indexlibraryglobal{countr_one}% -\begin{itemdescr} -\pnum -\constraints -\tcode{T} is an unsigned integer type\iref{basic.fundamental}. - -\pnum -\returns -The number of consecutive \tcode{1} bits in the value of \tcode{x}, -starting from the least significant bit. -\begin{note} -Returns \tcode{N} if \tcode{x == numeric_limits::max()}. -\end{note} -\end{itemdescr} - -\begin{itemdecl} -template - constexpr int popcount(T x) noexcept; -\end{itemdecl} - -\indexlibraryglobal{popcount}% -\begin{itemdescr} -\pnum -\constraints -\tcode{T} is an unsigned integer type\iref{basic.fundamental}. - -\pnum -\returns -The number of \tcode{1} bits in the value of \tcode{x}. -\end{itemdescr} - -\rSec2[bit.endian]{Endian} - -\pnum -Two common methods of byte ordering in multibyte scalar types are big-endian -and little-endian in the execution environment. Big-endian is a format for -storage of binary data in which the most significant byte is placed first, -with the rest in descending order. Little-endian is a format for storage of -binary data in which the least significant byte is placed first, with the rest -in ascending order. This subclause describes the endianness of the scalar types -of the execution environment. - -\indexlibraryglobal{endian}% -\indexlibrarymember{little}{endian}% -\indexlibrarymember{big}{endian}% -\indexlibrarymember{native}{endian}% -\begin{itemdecl} -enum class endian { - little = @\seebelow@, - big = @\seebelow@, - native = @\seebelow@ -}; -\end{itemdecl} - -\begin{itemdescr} -\pnum -If all scalar types have size 1 byte, then all of \tcode{endian::little}, -\tcode{endian::big}, and \tcode{endian::native} have the same value. -Otherwise, \tcode{endian::little} is not equal to \tcode{endian::big}. -If all scalar types are big-endian, \tcode{endian::native} is -equal to \tcode{endian::big}. -If all scalar types are little-endian, \tcode{endian::native} is -equal to \tcode{endian::little}. -Otherwise, \tcode{endian::native} is not equal -to either \tcode{endian::big} or \tcode{endian::little}. -\end{itemdescr} - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/source/std.tex b/source/std.tex index 552d663558..040decb135 100644 --- a/source/std.tex +++ b/source/std.tex @@ -119,6 +119,8 @@ \include{support} \include{concepts} \include{diagnostics} +\include{memory} +\include{meta} \include{utilities} \include{strings} \include{containers} @@ -130,7 +132,6 @@ \include{locales} \include{iostreams} \include{regex} -\include{atomics} \include{threads} %%-------------------------------------------------- diff --git a/source/strings.tex b/source/strings.tex index 783a688896..46d10379b4 100644 --- a/source/strings.tex +++ b/source/strings.tex @@ -19,8 +19,8 @@ \begin{libsumtab}[x{2.1in}]{Strings library summary}{strings.summary} \ref{char.traits} & Character traits & \tcode{} \\ -\ref{string.classes} & String classes & \\ \rowsep \ref{string.view} & String view classes & \tcode{} \\ \rowsep +\ref{string.classes} & String classes & \\ \rowsep \ref{c.strings} & Null-terminated sequence utilities & \tcode{}, \tcode{}, \tcode{}, \tcode{}, \tcode{}, \tcode{} \\ @@ -515,2224 +515,1983 @@ returns \tcode{WEOF}. -\rSec1[string.classes]{String classes} +\rSec1[string.view]{String view classes} -\rSec2[string.classes.general]{General} +\rSec2[string.view.general]{General} \pnum -The header \tcode{} defines the -\tcode{basic_string} class template for manipulating -varying-length sequences of char-like objects and five -\grammarterm{typedef-name}{s}, \tcode{string}, -\tcode{u8string}, -\tcode{u16string}, -\tcode{u32string}, -and \tcode{wstring}, that name -the specializations -\tcode{basic_string}, -\tcode{basic_string}, -\tcode{basic_string}, -\tcode{basic_string}, -and -\tcode{basic_string<\brk{}wchar_t>}, respectively. +The class template \tcode{basic_string_view} describes an object that can refer to a constant contiguous sequence of char-like\iref{strings.general} objects with the first element of the sequence at position zero. +In the rest of \ref{string.view}, the type of the char-like objects held in a \tcode{basic_string_view} object is designated by \tcode{charT}. -\rSec2[string.syn]{Header \tcode{} synopsis} -\indexheader{string}% +\pnum +\begin{note} +The library provides implicit conversions from \tcode{const charT*} and \tcode{std::basic_string} to \tcode{std::basic_string_view} so that user code can accept just \tcode{std::basic_string_view} as a non-templated parameter wherever a sequence of characters is expected. +User-defined types can define their own implicit conversions to \tcode{std::basic_string_view} in order to interoperate with these functions. +\end{note} + +\rSec2[string.view.synop]{Header \tcode{} synopsis} +\indexheader{string_view}% \begin{codeblock} #include // see \ref{compare.syn} -#include // see \ref{initializer.list.syn} namespace std { - // \ref{char.traits}, character traits - template struct char_traits; - template<> struct char_traits; - template<> struct char_traits; - template<> struct char_traits; - template<> struct char_traits; - template<> struct char_traits; - - // \ref{basic.string}, \tcode{basic_string} - template, class Allocator = allocator> - class basic_string; - - template - constexpr basic_string - operator+(const basic_string& lhs, - const basic_string& rhs); - template - constexpr basic_string - operator+(basic_string&& lhs, - const basic_string& rhs); - template - constexpr basic_string - operator+(const basic_string& lhs, - basic_string&& rhs); - template - constexpr basic_string - operator+(basic_string&& lhs, - basic_string&& rhs); - template - constexpr basic_string - operator+(const charT* lhs, - const basic_string& rhs); - template - constexpr basic_string - operator+(const charT* lhs, - basic_string&& rhs); - template - constexpr basic_string - operator+(charT lhs, - const basic_string& rhs); - template - constexpr basic_string - operator+(charT lhs, - basic_string&& rhs); - template - constexpr basic_string - operator+(const basic_string& lhs, - const charT* rhs); - template - constexpr basic_string - operator+(basic_string&& lhs, - const charT* rhs); - template - constexpr basic_string - operator+(const basic_string& lhs, - charT rhs); - template - constexpr basic_string - operator+(basic_string&& lhs, - charT rhs); + // \ref{string.view.template}, class template \tcode{basic_string_view} + template> + class basic_string_view; - template - constexpr bool - operator==(const basic_string& lhs, - const basic_string& rhs) noexcept; - template - constexpr bool operator==(const basic_string& lhs, - const charT* rhs); + template + inline constexpr bool ranges::enable_view> = true; + template + inline constexpr bool ranges::enable_borrowed_range> = true; - template - constexpr @\seebelow@ operator<=>(const basic_string& lhs, - @\itcorr@ const basic_string& rhs) noexcept; - template - constexpr @\seebelow@ operator<=>(const basic_string& lhs, - @\itcorr@ const charT* rhs); + // \ref{string.view.comparison}, non-member comparison functions + template + constexpr bool operator==(basic_string_view x, + basic_string_view y) noexcept; + template + constexpr @\seebelow@ operator<=>(basic_string_view x, + @\itcorr@ basic_string_view y) noexcept; - // \ref{string.special}, swap - template - constexpr void - swap(basic_string& lhs, - basic_string& rhs) - noexcept(noexcept(lhs.swap(rhs))); + // see \ref{string.view.comparison}, sufficient additional overloads of comparison functions - // \ref{string.io}, inserters and extractors - template - basic_istream& - operator>>(basic_istream& is, - basic_string& str); - template + // \ref{string.view.io}, inserters and extractors + template basic_ostream& operator<<(basic_ostream& os, - const basic_string& str); - template - basic_istream& - getline(basic_istream& is, - basic_string& str, - charT delim); - template - basic_istream& - getline(basic_istream&& is, - basic_string& str, - charT delim); - template - basic_istream& - getline(basic_istream& is, - basic_string& str); - template - basic_istream& - getline(basic_istream&& is, - basic_string& str); - - // \ref{string.erasure}, erasure - template - constexpr typename basic_string::size_type - erase(basic_string& c, const U& value); - template - constexpr typename basic_string::size_type - erase_if(basic_string& c, Predicate pred); - - // \tcode{basic_string} \grammarterm{typedef-name}s - using @\libglobal{string}@ = basic_string; - using @\libglobal{u8string}@ = basic_string; - using @\libglobal{u16string}@ = basic_string; - using @\libglobal{u32string}@ = basic_string; - using @\libglobal{wstring}@ = basic_string; - - // \ref{string.conversions}, numeric conversions - int stoi(const string& str, size_t* idx = nullptr, int base = 10); - long stol(const string& str, size_t* idx = nullptr, int base = 10); - unsigned long stoul(const string& str, size_t* idx = nullptr, int base = 10); - long long stoll(const string& str, size_t* idx = nullptr, int base = 10); - unsigned long long stoull(const string& str, size_t* idx = nullptr, int base = 10); - float stof(const string& str, size_t* idx = nullptr); - double stod(const string& str, size_t* idx = nullptr); - long double stold(const string& str, size_t* idx = nullptr); - string to_string(int val); - string to_string(unsigned val); - string to_string(long val); - string to_string(unsigned long val); - string to_string(long long val); - string to_string(unsigned long long val); - string to_string(float val); - string to_string(double val); - string to_string(long double val); - - int stoi(const wstring& str, size_t* idx = nullptr, int base = 10); - long stol(const wstring& str, size_t* idx = nullptr, int base = 10); - unsigned long stoul(const wstring& str, size_t* idx = nullptr, int base = 10); - long long stoll(const wstring& str, size_t* idx = nullptr, int base = 10); - unsigned long long stoull(const wstring& str, size_t* idx = nullptr, int base = 10); - float stof(const wstring& str, size_t* idx = nullptr); - double stod(const wstring& str, size_t* idx = nullptr); - long double stold(const wstring& str, size_t* idx = nullptr); - wstring to_wstring(int val); - wstring to_wstring(unsigned val); - wstring to_wstring(long val); - wstring to_wstring(unsigned long val); - wstring to_wstring(long long val); - wstring to_wstring(unsigned long long val); - wstring to_wstring(float val); - wstring to_wstring(double val); - wstring to_wstring(long double val); - - namespace pmr { - template> - using basic_string = std::basic_string>; + basic_string_view str); - using string = basic_string; - using u8string = basic_string; - using u16string = basic_string; - using u32string = basic_string; - using wstring = basic_string; - } + // \tcode{basic_string_view} \grammarterm{typedef-name}s + using string_view = basic_string_view; + using u8string_view = basic_string_view; + using u16string_view = basic_string_view; + using u32string_view = basic_string_view; + using wstring_view = basic_string_view; - // \ref{basic.string.hash}, hash support + // \ref{string.view.hash}, hash support template struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; + template<> struct hash; + template<> struct hash; + template<> struct hash; + template<> struct hash; + template<> struct hash; inline namespace literals { - inline namespace string_literals { - // \ref{basic.string.literals}, suffix for \tcode{basic_string} literals - constexpr string operator""s(const char* str, size_t len); - constexpr u8string operator""s(const char8_t* str, size_t len); - constexpr u16string operator""s(const char16_t* str, size_t len); - constexpr u32string operator""s(const char32_t* str, size_t len); - constexpr wstring operator""s(const wchar_t* str, size_t len); + inline namespace string_view_literals { + // \ref{string.view.literals}, suffix for \tcode{basic_string_view} literals + constexpr string_view operator""sv(const char* str, size_t len) noexcept; + constexpr u8string_view operator""sv(const char8_t* str, size_t len) noexcept; + constexpr u16string_view operator""sv(const char16_t* str, size_t len) noexcept; + constexpr u32string_view operator""sv(const char32_t* str, size_t len) noexcept; + constexpr wstring_view operator""sv(const wchar_t* str, size_t len) noexcept; } } } \end{codeblock} -\rSec2[basic.string]{Class template \tcode{basic_string}} - -\rSec3[basic.string.general]{General} - -\pnum -\indexlibraryglobal{basic_string}% -The -class template -\tcode{basic_string} -describes objects that can store a sequence consisting of a varying number of -arbitrary char-like objects with the first element of the sequence at position zero. -Such a sequence is also called a ``string'' if the type of the -char-like objects that it holds -is clear from context. -In the rest of \ref{basic.string}, -the type of the char-like objects held in a \tcode{basic_string} object -is designated by \tcode{charT}. - \pnum -A specialization of \tcode{basic_string} is a contiguous container\iref{container.requirements.general}. +The function templates defined in \ref{utility.swap} and \ref{iterator.range} +are available when \tcode{} is included. -\pnum -In all cases, -\crange{data()}{data() + size()} is a valid range, -\tcode{data() + size()} points at an object with value \tcode{charT()} -(a ``null terminator''\indextext{string!null terminator}), -and \tcode{size() <= capacity()} is \tcode{true}. +\rSec2[string.view.template]{Class template \tcode{basic_string_view}} +\rSec3[string.view.template.general]{General} -\indexlibraryglobal{basic_string}% -\indexlibrarymember{traits_type}{basic_string}% -\indexlibrarymember{value_type}{basic_string}% -\indexlibrarymember{allocator_type}{basic_string}% -\indexlibrarymember{size_type}{basic_string}% -\indexlibrarymember{difference_type}{basic_string}% -\indexlibrarymember{pointer}{basic_string}% -\indexlibrarymember{const_pointer}{basic_string}% -\indexlibrarymember{reference}{basic_string}% -\indexlibrarymember{const_reference}{basic_string}% -\indexlibrarymember{iterator}{basic_string}% -\indexlibrarymember{const_iterator}{basic_string}% -\indexlibrarymember{reverse_iterator}{basic_string}% -\indexlibrarymember{const_reverse_iterator}{basic_string}% +\indexlibraryglobal{basic_string_view}% +\indexlibrarymember{traits_type}{basic_string_view}% +\indexlibrarymember{value_type}{basic_string_view}% +\indexlibrarymember{pointer}{basic_string_view}% +\indexlibrarymember{const_pointer}{basic_string_view}% +\indexlibrarymember{reference}{basic_string_view}% +\indexlibrarymember{const_reference}{basic_string_view}% +\indexlibrarymember{const_iterator}{basic_string_view}% +\indexlibrarymember{iterator}{basic_string_view}% +\indexlibrarymember{const_reverse_iterator}{basic_string_view}% +\indexlibrarymember{reverse_iterator}{basic_string_view}% +\indexlibrarymember{size_type}{basic_string_view}% +\indexlibrarymember{difference_type}{basic_string_view}% \begin{codeblock} namespace std { - template, - class Allocator = allocator> - class basic_string { + template> + class basic_string_view { public: // types using traits_type = traits; using value_type = charT; - using allocator_type = Allocator; - using size_type = typename allocator_traits::size_type; - using difference_type = typename allocator_traits::difference_type; - using pointer = typename allocator_traits::pointer; - using const_pointer = typename allocator_traits::const_pointer; + using pointer = value_type*; + using const_pointer = const value_type*; using reference = value_type&; using const_reference = const value_type&; - - using iterator = @\impdefx{type of \tcode{basic_string::iterator}}@; // see \ref{container.requirements} - using const_iterator = @\impdefx{type of \tcode{basic_string::const_iterator}}@; // see \ref{container.requirements} - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; + using const_iterator = @\impdefx{type of \tcode{basic_string_view::const_iterator}}@; // see \ref{string.view.iterators} + using iterator = const_iterator;@ +\begin{footnote} +Because \tcode{basic_string_view} refers to a constant sequence, \tcode{iterator} and \tcode{const_iterator} are the same type. +\end{footnote}@ + using const_reverse_iterator = reverse_iterator; + using reverse_iterator = const_reverse_iterator; + using size_type = size_t; + using difference_type = ptrdiff_t; static constexpr size_type npos = size_type(-1); - // \ref{string.cons}, construct/copy/destroy - constexpr basic_string() noexcept(noexcept(Allocator())) : basic_string(Allocator()) { } - constexpr explicit basic_string(const Allocator& a) noexcept; - constexpr basic_string(const basic_string& str); - constexpr basic_string(basic_string&& str) noexcept; - constexpr basic_string(const basic_string& str, size_type pos, - const Allocator& a = Allocator()); - constexpr basic_string(const basic_string& str, size_type pos, size_type n, - const Allocator& a = Allocator()); - template - constexpr basic_string(const T& t, size_type pos, size_type n, - const Allocator& a = Allocator()); - template - constexpr explicit basic_string(const T& t, const Allocator& a = Allocator()); - constexpr basic_string(const charT* s, size_type n, const Allocator& a = Allocator()); - constexpr basic_string(const charT* s, const Allocator& a = Allocator()); - basic_string(nullptr_t) = delete; - constexpr basic_string(size_type n, charT c, const Allocator& a = Allocator()); - template - constexpr basic_string(InputIterator begin, InputIterator end, - const Allocator& a = Allocator()); - template<@\exposconcept{container-compatible-range}@ R> - constexpr basic_string(from_range_t, R&& rg, const Allocator& a = Allocator()); - constexpr basic_string(initializer_list, const Allocator& = Allocator()); - constexpr basic_string(const basic_string&, const Allocator&); - constexpr basic_string(basic_string&&, const Allocator&); - constexpr ~basic_string(); - - constexpr basic_string& operator=(const basic_string& str); - constexpr basic_string& operator=(basic_string&& str) - noexcept(allocator_traits::propagate_on_container_move_assignment::value || - allocator_traits::is_always_equal::value); - template - constexpr basic_string& operator=(const T& t); - constexpr basic_string& operator=(const charT* s); - basic_string& operator=(nullptr_t) = delete; - constexpr basic_string& operator=(charT c); - constexpr basic_string& operator=(initializer_list); + // \ref{string.view.cons}, construction and assignment + constexpr basic_string_view() noexcept; + constexpr basic_string_view(const basic_string_view&) noexcept = default; + constexpr basic_string_view& operator=(const basic_string_view&) noexcept = default; + constexpr basic_string_view(const charT* str); + basic_string_view(nullptr_t) = delete; + constexpr basic_string_view(const charT* str, size_type len); + template + constexpr basic_string_view(It begin, End end); + template + constexpr basic_string_view(R&& r); - // \ref{string.iterators}, iterators - constexpr iterator begin() noexcept; + // \ref{string.view.iterators}, iterator support constexpr const_iterator begin() const noexcept; - constexpr iterator end() noexcept; constexpr const_iterator end() const noexcept; - - constexpr reverse_iterator rbegin() noexcept; + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cend() const 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; - // \ref{string.capacity}, capacity + // \ref{string.view.capacity}, capacity constexpr size_type size() const noexcept; constexpr size_type length() const noexcept; constexpr size_type max_size() const noexcept; - constexpr void resize(size_type n, charT c); - constexpr void resize(size_type n); - template constexpr void resize_and_overwrite(size_type n, Operation op); - constexpr size_type capacity() const noexcept; - constexpr void reserve(size_type res_arg); - constexpr void shrink_to_fit(); - constexpr void clear() noexcept; [[nodiscard]] constexpr bool empty() const noexcept; - // \ref{string.access}, element access + // \ref{string.view.access}, element access constexpr const_reference operator[](size_type pos) const; - constexpr reference operator[](size_type pos); - constexpr const_reference at(size_type n) const; - constexpr reference at(size_type n); - - constexpr const charT& front() const; - constexpr charT& front(); - constexpr const charT& back() const; - constexpr charT& back(); + constexpr const_reference at(size_type pos) const; + constexpr const_reference front() const; + constexpr const_reference back() const; + constexpr const_pointer data() const noexcept; - // \ref{string.modifiers}, modifiers - constexpr basic_string& operator+=(const basic_string& str); - template - constexpr basic_string& operator+=(const T& t); - constexpr basic_string& operator+=(const charT* s); - constexpr basic_string& operator+=(charT c); - constexpr basic_string& operator+=(initializer_list); - constexpr basic_string& append(const basic_string& str); - constexpr basic_string& append(const basic_string& str, size_type pos, size_type n = npos); - template - constexpr basic_string& append(const T& t); - template - constexpr basic_string& append(const T& t, size_type pos, size_type n = npos); - constexpr basic_string& append(const charT* s, size_type n); - constexpr basic_string& append(const charT* s); - constexpr basic_string& append(size_type n, charT c); - template - constexpr basic_string& append(InputIterator first, InputIterator last); - template<@\exposconcept{container-compatible-range}@ R> - constexpr basic_string& append_range(R&& rg); - constexpr basic_string& append(initializer_list); + // \ref{string.view.modifiers}, modifiers + constexpr void remove_prefix(size_type n); + constexpr void remove_suffix(size_type n); + constexpr void swap(basic_string_view& s) noexcept; - constexpr void push_back(charT c); + // \ref{string.view.ops}, string operations + constexpr size_type copy(charT* s, size_type n, size_type pos = 0) const; - constexpr basic_string& assign(const basic_string& str); - constexpr basic_string& assign(basic_string&& str) - noexcept(allocator_traits::propagate_on_container_move_assignment::value || - allocator_traits::is_always_equal::value); - constexpr basic_string& assign(const basic_string& str, size_type pos, size_type n = npos); - template - constexpr basic_string& assign(const T& t); - template - constexpr basic_string& assign(const T& t, size_type pos, size_type n = npos); - constexpr basic_string& assign(const charT* s, size_type n); - constexpr basic_string& assign(const charT* s); - constexpr basic_string& assign(size_type n, charT c); - template - constexpr basic_string& assign(InputIterator first, InputIterator last); - template<@\exposconcept{container-compatible-range}@ R> - constexpr basic_string& assign_range(R&& rg); - constexpr basic_string& assign(initializer_list); + constexpr basic_string_view substr(size_type pos = 0, size_type n = npos) const; - constexpr basic_string& insert(size_type pos, const basic_string& str); - constexpr basic_string& insert(size_type pos1, const basic_string& str, - size_type pos2, size_type n = npos); - template - constexpr basic_string& insert(size_type pos, const T& t); - template - constexpr basic_string& insert(size_type pos1, const T& t, - size_type pos2, size_type n = npos); - constexpr basic_string& insert(size_type pos, const charT* s, size_type n); - constexpr basic_string& insert(size_type pos, const charT* s); - constexpr basic_string& insert(size_type pos, size_type n, charT c); - constexpr iterator insert(const_iterator p, charT c); - constexpr iterator insert(const_iterator p, size_type n, charT c); - template - constexpr iterator insert(const_iterator p, InputIterator first, InputIterator last); - template<@\exposconcept{container-compatible-range}@ R> - constexpr iterator insert_range(const_iterator p, R&& rg); - constexpr iterator insert(const_iterator p, initializer_list); + constexpr int compare(basic_string_view s) const noexcept; + constexpr int compare(size_type pos1, size_type n1, basic_string_view s) const; + constexpr int compare(size_type pos1, size_type n1, basic_string_view s, + size_type pos2, size_type n2) const; + constexpr int compare(const charT* s) const; + constexpr int compare(size_type pos1, size_type n1, const charT* s) const; + constexpr int compare(size_type pos1, size_type n1, const charT* s, size_type n2) const; - constexpr basic_string& erase(size_type pos = 0, size_type n = npos); - constexpr iterator erase(const_iterator p); - constexpr iterator erase(const_iterator first, const_iterator last); + constexpr bool starts_with(basic_string_view x) const noexcept; + constexpr bool starts_with(charT x) const noexcept; + constexpr bool starts_with(const charT* x) const; + constexpr bool ends_with(basic_string_view x) const noexcept; + constexpr bool ends_with(charT x) const noexcept; + constexpr bool ends_with(const charT* x) const; - constexpr void pop_back(); + constexpr bool contains(basic_string_view x) const noexcept; + constexpr bool contains(charT x) const noexcept; + constexpr bool contains(const charT* x) const; - constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str); - constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str, - size_type pos2, size_type n2 = npos); - template - constexpr basic_string& replace(size_type pos1, size_type n1, const T& t); - template - constexpr basic_string& replace(size_type pos1, size_type n1, const T& t, - size_type pos2, size_type n2 = npos); - constexpr basic_string& replace(size_type pos, size_type n1, const charT* s, size_type n2); - constexpr basic_string& replace(size_type pos, size_type n1, const charT* s); - constexpr basic_string& replace(size_type pos, size_type n1, size_type n2, charT c); - constexpr basic_string& replace(const_iterator i1, const_iterator i2, - const basic_string& str); - template - constexpr basic_string& replace(const_iterator i1, const_iterator i2, const T& t); - constexpr basic_string& replace(const_iterator i1, const_iterator i2, const charT* s, - size_type n); - constexpr basic_string& replace(const_iterator i1, const_iterator i2, const charT* s); - constexpr basic_string& replace(const_iterator i1, const_iterator i2, size_type n, charT c); - template - constexpr basic_string& replace(const_iterator i1, const_iterator i2, - InputIterator j1, InputIterator j2); - template<@\exposconcept{container-compatible-range}@ R> - constexpr basic_string& replace_with_range(const_iterator i1, const_iterator i2, R&& rg); - constexpr basic_string& replace(const_iterator, const_iterator, initializer_list); - - constexpr size_type copy(charT* s, size_type n, size_type pos = 0) const; - - constexpr void swap(basic_string& str) - noexcept(allocator_traits::propagate_on_container_swap::value || - allocator_traits::is_always_equal::value); - - // \ref{string.ops}, string operations - constexpr const charT* c_str() const noexcept; - constexpr const charT* data() const noexcept; - constexpr charT* data() noexcept; - constexpr operator basic_string_view() const noexcept; - constexpr allocator_type get_allocator() const noexcept; - - template - constexpr size_type find(const T& t, size_type pos = 0) const noexcept(@\seebelow@); - constexpr size_type find(const basic_string& str, size_type pos = 0) const noexcept; + // \ref{string.view.find}, searching + constexpr size_type find(basic_string_view s, size_type pos = 0) const noexcept; + constexpr size_type find(charT c, size_type pos = 0) const noexcept; constexpr size_type find(const charT* s, size_type pos, size_type n) const; constexpr size_type find(const charT* s, size_type pos = 0) const; - constexpr size_type find(charT c, size_type pos = 0) const noexcept; - template - constexpr size_type rfind(const T& t, size_type pos = npos) const noexcept(@\seebelow@); - constexpr size_type rfind(const basic_string& str, size_type pos = npos) const noexcept; + constexpr size_type rfind(basic_string_view s, size_type pos = npos) const noexcept; + constexpr size_type rfind(charT c, size_type pos = npos) const noexcept; constexpr size_type rfind(const charT* s, size_type pos, size_type n) const; constexpr size_type rfind(const charT* s, size_type pos = npos) const; - constexpr size_type rfind(charT c, size_type pos = npos) const noexcept; - template - constexpr size_type find_first_of(const T& t, size_type pos = 0) const noexcept(@\seebelow@); - constexpr size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept; + constexpr size_type find_first_of(basic_string_view s, size_type pos = 0) const noexcept; + constexpr size_type find_first_of(charT c, size_type pos = 0) const noexcept; constexpr size_type find_first_of(const charT* s, size_type pos, size_type n) const; constexpr size_type find_first_of(const charT* s, size_type pos = 0) const; - constexpr size_type find_first_of(charT c, size_type pos = 0) const noexcept; - template - constexpr size_type find_last_of(const T& t, - size_type pos = npos) const noexcept(@\seebelow@); - constexpr size_type find_last_of(const basic_string& str, - size_type pos = npos) const noexcept; + constexpr size_type find_last_of(basic_string_view s, size_type pos = npos) const noexcept; + constexpr size_type find_last_of(charT c, size_type pos = npos) const noexcept; constexpr size_type find_last_of(const charT* s, size_type pos, size_type n) const; constexpr size_type find_last_of(const charT* s, size_type pos = npos) const; - constexpr size_type find_last_of(charT c, size_type pos = npos) const noexcept; - - template - constexpr size_type find_first_not_of(const T& t, - size_type pos = 0) const noexcept(@\seebelow@); - constexpr size_type find_first_not_of(const basic_string& str, - size_type pos = 0) const noexcept; - constexpr size_type find_first_not_of(const charT* s, size_type pos, size_type n) const; - constexpr size_type find_first_not_of(const charT* s, size_type pos = 0) const; + constexpr size_type find_first_not_of(basic_string_view s, size_type pos = 0) const noexcept; constexpr size_type find_first_not_of(charT c, size_type pos = 0) const noexcept; - template - constexpr size_type find_last_not_of(const T& t, - size_type pos = npos) const noexcept(@\seebelow@); - constexpr size_type find_last_not_of(const basic_string& str, + constexpr size_type find_first_not_of(const charT* s, size_type pos, + size_type n) const; + constexpr size_type find_first_not_of(const charT* s, size_type pos = 0) const; + constexpr size_type find_last_not_of(basic_string_view s, size_type pos = npos) const noexcept; - constexpr size_type find_last_not_of(const charT* s, size_type pos, size_type n) const; - constexpr size_type find_last_not_of(const charT* s, size_type pos = npos) const; constexpr size_type find_last_not_of(charT c, size_type pos = npos) const noexcept; + constexpr size_type find_last_not_of(const charT* s, size_type pos, + size_type n) const; + constexpr size_type find_last_not_of(const charT* s, size_type pos = npos) const; - constexpr basic_string substr(size_type pos = 0, size_type n = npos) const; - - template - constexpr int compare(const T& t) const noexcept(@\seebelow@); - template - constexpr int compare(size_type pos1, size_type n1, const T& t) const; - template - constexpr int compare(size_type pos1, size_type n1, const T& t, - size_type pos2, size_type n2 = npos) const; - constexpr int compare(const basic_string& str) const noexcept; - constexpr int compare(size_type pos1, size_type n1, const basic_string& str) const; - constexpr int compare(size_type pos1, size_type n1, const basic_string& str, - size_type pos2, size_type n2 = npos) const; - constexpr int compare(const charT* s) const; - constexpr int compare(size_type pos1, size_type n1, const charT* s) const; - constexpr int compare(size_type pos1, size_type n1, const charT* s, size_type n2) const; - - constexpr bool starts_with(basic_string_view x) const noexcept; - constexpr bool starts_with(charT x) const noexcept; - constexpr bool starts_with(const charT* x) const; - constexpr bool ends_with(basic_string_view x) const noexcept; - constexpr bool ends_with(charT x) const noexcept; - constexpr bool ends_with(const charT* x) const; - - constexpr bool contains(basic_string_view x) const noexcept; - constexpr bool contains(charT x) const noexcept; - constexpr bool contains(const charT* x) const; + private: + const_pointer data_; // \expos + size_type size_; // \expos }; - template::value_type>> - basic_string(InputIterator, InputIterator, Allocator = Allocator()) - -> basic_string::value_type, - char_traits::value_type>, - Allocator>; - - template>> - basic_string(from_range_t, R&&, Allocator = Allocator()) - -> basic_string, char_traits>, - Allocator>; - - template> - explicit basic_string(basic_string_view, const Allocator& = Allocator()) - -> basic_string; - - template> - basic_string(basic_string_view, - typename @\seebelow@::size_type, typename @\seebelow@::size_type, - const Allocator& = Allocator()) - -> basic_string; + // \ref{string.view.deduct}, deduction guides + template + basic_string_view(It, End) -> basic_string_view>; + template + basic_string_view(R&&) -> basic_string_view>; } \end{codeblock} \pnum -A \tcode{size_type} parameter type in -a \tcode{basic_string} deduction guide -refers to the \tcode{size_type} member type of -the type deduced by the deduction guide. - -\pnum -The types \tcode{iterator} and \tcode{const_iterator} meet -the constexpr iterator requirements\iref{iterator.requirements.general}. - -\rSec3[string.require]{General requirements} - -\pnum -If any operation would cause \tcode{size()} to -exceed \tcode{max_size()}, that operation throws an -exception object of type \tcode{length_error}. - -\pnum -If any member function or operator of \tcode{basic_string} throws an exception, that -function or operator has no other effect on the \tcode{basic_string} object. - -\pnum -In every specialization \tcode{basic_string}, -the type \tcode{allocator_traits::value_type} shall name the same type -as \tcode{charT}. Every object of type -\tcode{basic_string} uses an object of type -\tcode{Allocator} to allocate and free storage for the contained \tcode{charT} -objects as needed. The \tcode{Allocator} object used is -obtained as described in \ref{container.requirements.general}. -In every specialization \tcode{basic_string}, -the type \tcode{traits} shall meet -the character traits requirements\iref{char.traits}. -\begin{note} -Every specialization \tcode{basic_string} is -an allocator-aware container, -but does not use the allocator's \tcode{construct} and \tcode{destroy} -member functions\iref{container.requirements.general}. -\end{note} +In every specialization \tcode{basic_string_view}, the type \tcode{traits} shall meet the character traits requirements\iref{char.traits}. \begin{note} -The program is ill-formed if \tcode{traits::char_type} -is not the same type as \tcode{charT}. +The program is ill-formed if \tcode{traits::char_type} is not the same type as \tcode{charT}. \end{note} \pnum -References, pointers, and iterators referring to the elements of a -\tcode{basic_string} sequence may be -invalidated by the following uses of that \tcode{basic_string} object: +For a \tcode{basic_string_view str}, +any operation that invalidates a pointer +in the range \range{str.data()}{\brk{}str.data() + str.size()} +invalidates pointers, iterators, and references +returned from \tcode{str}'s member functions. -\begin{itemize} -\item Passing as an argument to any standard library function taking a reference to non-const -\tcode{basic_string} as an argument. -\begin{footnote} -For example, as an argument to non-member -functions \tcode{swap()}\iref{string.special}, -\tcode{operator>{}>()}\iref{string.io}, and \tcode{getline()}\iref{string.io}, or as -an argument to \tcode{basic_string::swap()}. -\end{footnote} +\pnum +The complexity of \tcode{basic_string_view} member functions is \bigoh{1} +unless otherwise specified. -\item Calling non-const member functions, except -\tcode{operator[]}, -\tcode{at}, -\tcode{data}, -\tcode{front}, -\tcode{back}, -\tcode{begin}, -\tcode{rbegin}, -\tcode{end}, -and -\tcode{rend}. -\end{itemize} +\pnum +\tcode{basic_string_view} is +a trivially copyable type\iref{term.trivially.copyable.type}. -\rSec3[string.cons]{Constructors and assignment operators} +\rSec3[string.view.cons]{Construction and assignment} -\indexlibraryctor{basic_string}% +\indexlibraryctor{basic_string_view}% \begin{itemdecl} -constexpr explicit basic_string(const Allocator& a) noexcept; +constexpr basic_string_view() noexcept; \end{itemdecl} \begin{itemdescr} - \pnum \ensures -\tcode{size()} is equal to \tcode{0}. +\tcode{size_ == 0} and \tcode{data_ == nullptr}. \end{itemdescr} -\indexlibraryctor{basic_string}% +\indexlibraryctor{basic_string_view}% \begin{itemdecl} -constexpr basic_string(const basic_string& str); -constexpr basic_string(basic_string&& str) noexcept; +constexpr basic_string_view(const charT* str); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\range{str}{str + traits::length(str)} is a valid range. + \pnum \effects -Constructs an object whose -value is that of \tcode{str} prior to this call. +Constructs a \tcode{basic_string_view}, initializing \tcode{data_} with \tcode{str} +and initializing \tcode{size_} with \tcode{traits::length(str)}. \pnum -\remarks -In the second form, \tcode{str} is left in a valid but unspecified state. +\complexity +\bigoh{\tcode{traits::length(str)}}. \end{itemdescr} -\indexlibraryctor{basic_string}% +\indexlibraryctor{basic_string_view}% \begin{itemdecl} -constexpr basic_string(const basic_string& str, size_type pos, - const Allocator& a = Allocator()); -constexpr basic_string(const basic_string& str, size_type pos, size_type n, - const Allocator& a = Allocator()); +constexpr basic_string_view(const charT* str, size_type len); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\range{str}{str + len} is a valid range. + \pnum \effects -Let \tcode{n} be \tcode{npos} for the first overload. Equivalent to: -\begin{codeblock} -basic_string(basic_string_view(str).substr(pos, n), a) -\end{codeblock} +Constructs a \tcode{basic_string_view}, initializing \tcode{data_} with \tcode{str} +and initializing \tcode{size_} with \tcode{len}. \end{itemdescr} -\indexlibraryctor{basic_string}% +\indexlibraryctor{basic_string_view}% \begin{itemdecl} -template - constexpr basic_string(const T& t, size_type pos, size_type n, const Allocator& a = Allocator()); +template + constexpr basic_string_view(It begin, End end); \end{itemdecl} \begin{itemdescr} \pnum \constraints -\tcode{is_convertible_v>} -is \tcode{true}. +\begin{itemize} +\item \tcode{It} satisfies \libconcept{contiguous_iterator}. +\item \tcode{End} satisfies \tcode{\libconcept{sized_sentinel_for}}. +\item \tcode{is_same_v, charT>} is \tcode{true}. +\item \tcode{is_convertible_v} is \tcode{false}. +\end{itemize} + +\pnum +\expects +\begin{itemize} +\item \range{begin}{end} is a valid range. +\item \tcode{It} models \libconcept{contiguous_iterator}. +\item \tcode{End} models \tcode{\libconcept{sized_sentinel_for}}. +\end{itemize} \pnum \effects -Creates a variable, \tcode{sv}, -as if by \tcode{basic_string_view sv = t;} -and then behaves the same as: -\begin{codeblock} -basic_string(sv.substr(pos, n), a); -\end{codeblock} +Initializes \tcode{data_} with \tcode{to_address(begin)} and +initializes \tcode{size_} with \tcode{end - begin}. + +\pnum +\throws +When and what \tcode{end - begin} throws. \end{itemdescr} -\indexlibraryctor{basic_string}% +\indexlibraryctor{basic_string_view}% \begin{itemdecl} -template - constexpr explicit basic_string(const T& t, const Allocator& a = Allocator()); +template + constexpr basic_string_view(R&& r); \end{itemdecl} \begin{itemdescr} +\pnum +Let \tcode{d} be an lvalue of type \tcode{remove_cvref_t}. + \pnum \constraints \begin{itemize} \item -\tcode{is_convertible_v>} is -\tcode{true} and +\tcode{remove_cvref_t} is not the same type as \tcode{basic_string_view}, \item -\tcode{is_convertible_v} is -\tcode{false}. +\tcode{R} models +\tcode{ranges::\libconcept{contiguous_range}} and \tcode{ranges::\libconcept{sized_range}}, +\item +\tcode{is_same_v, charT>} is \tcode{true}, +\item +\tcode{is_convertible_v} is \tcode{false}, +\item +\tcode{d.operator ::std::basic_string_view()} +is not a valid expression, and +\item +if the \grammarterm{qualified-id} \tcode{remove_reference_t::traits_type} +is valid and denotes a type, +\tcode{is_same_v::traits_type, traits>} is \tcode{true}. \end{itemize} \pnum \effects -Creates a variable, \tcode{sv}, as if by -\tcode{basic_string_view sv = t;} and -then behaves the same as \tcode{basic_string(sv.data(), sv.size(), a)}. -\end{itemdescr} - -\indexlibraryctor{basic_string}% -\begin{itemdecl} -constexpr basic_string(const charT* s, size_type n, const Allocator& a = Allocator()); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\range{s}{s + n} is a valid range. - -\pnum -\effects -Constructs an object whose initial value is the range \range{s}{s + n}. +Initializes \tcode{data_} with \tcode{ranges::data(r)} and +\tcode{size_} with \tcode{ranges::size(r)}. \pnum -\ensures -\tcode{size()} is equal to \tcode{n}, and -\tcode{traits::compare(data(), s, n)} is equal to \tcode{0}. +\throws +Any exception thrown by \tcode{ranges::data(r)} and \tcode{ranges::size(r)}. \end{itemdescr} -\indexlibraryctor{basic_string}% +\rSec3[string.view.iterators]{Iterator support} + +\indexlibrarymember{const_iterator}{basic_string_view}% \begin{itemdecl} -constexpr basic_string(const charT* s, const Allocator& a = Allocator()); +using const_iterator = @\impdefx{type of \tcode{basic_string_view::const_iterator}}@; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{Allocator} is a type -that qualifies as an allocator\iref{container.requirements.general}. -\begin{note} -This affects class template argument deduction. -\end{note} +A type that meets the requirements +of a constant +\oldconcept{RandomAccessIterator}\iref{random.access.iterators}, +models \libconcept{contiguous_iterator}\iref{iterator.concept.contiguous}, and +meets the constexpr iterator requirements\iref{iterator.requirements.general}, +whose \tcode{value_type} is the template parameter \tcode{charT}. \pnum -\effects -Equivalent to: \tcode{basic_string(s, traits::length(s), a)}. +All requirements on container iterators\iref{container.requirements} apply to \tcode{basic_string_view::const_iterator} as well. \end{itemdescr} -\indexlibraryctor{basic_string}% +\indexlibrarymember{begin}{basic_string_view}% +\indexlibrarymember{cbegin}{basic_string_view}% \begin{itemdecl} -constexpr basic_string(size_type n, charT c, const Allocator& a = Allocator()); +constexpr const_iterator begin() const noexcept; +constexpr const_iterator cbegin() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{Allocator} is a type -that qualifies as an allocator\iref{container.requirements.general}. -\begin{note} -This affects class template argument deduction. -\end{note} - -\pnum -\effects -Constructs an object whose value consists of \tcode{n} copies of \tcode{c}. +\returns +An iterator such that +\begin{itemize} +\item if \tcode{!empty()}, \tcode{addressof(*begin()) == data_}, +\item otherwise, an unspecified value such that \range{begin()}{end()} is a valid range. +\end{itemize} \end{itemdescr} -\indexlibraryctor{basic_string}% +\indexlibrarymember{end}{basic_string_view}% +\indexlibrarymember{cend}{basic_string_view}% \begin{itemdecl} -template - constexpr basic_string(InputIterator begin, InputIterator end, const Allocator& a = Allocator()); +constexpr const_iterator end() const noexcept; +constexpr const_iterator cend() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{InputIterator} is a type that qualifies as an input -iterator\iref{container.requirements.general}. - -\pnum -\effects -Constructs a string from the values in the range \range{begin}{end}, -as specified in \ref{sequence.reqmts}. +\returns +\tcode{begin() + size()}. \end{itemdescr} -\indexlibraryctor{basic_string}% +\indexlibrarymember{rbegin}{basic_string_view}% +\indexlibrarymember{crbegin}{basic_string_view}% \begin{itemdecl} -template<@\exposconcept{container-compatible-range}@ R> - constexpr basic_string(from_range_t, R&& rg, const Allocator& = Allocator()); +constexpr const_reverse_iterator rbegin() const noexcept; +constexpr const_reverse_iterator crbegin() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Constructs a string from the values in the range \tcode{rg}, -as specified in \ref{sequence.reqmts}. +\returns +\tcode{const_reverse_iterator(end())}. \end{itemdescr} -\indexlibraryctor{basic_string}% +\indexlibrarymember{rend}{basic_string_view}% +\indexlibrarymember{crend}{basic_string_view}% \begin{itemdecl} -constexpr basic_string(initializer_list il, const Allocator& a = Allocator()); +constexpr const_reverse_iterator rend() const noexcept; +constexpr const_reverse_iterator crend() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to \tcode{basic_string(il.begin(), il.end(), a)}. +\returns +\tcode{const_reverse_iterator(begin())}. \end{itemdescr} -\indexlibraryctor{basic_string}% +\rSec3[string.view.capacity]{Capacity} + +\indexlibrarymember{size}{basic_string_view}% +\indexlibrarymember{length}{basic_string_view}% \begin{itemdecl} -constexpr basic_string(const basic_string& str, const Allocator& alloc); -constexpr basic_string(basic_string&& str, const Allocator& alloc); +constexpr size_type size() const noexcept; +constexpr size_type length() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Constructs an object whose value is -that of \tcode{str} prior to this call. -The stored allocator is constructed from \tcode{alloc}. -In the second form, \tcode{str} is left in a valid but unspecified state. - -\pnum -\throws -The second form throws nothing if \tcode{alloc == str.get_allocator()}. +\returns +\tcode{size_}. \end{itemdescr} + +\indexlibrarymember{max_size}{basic_string_view}% \begin{itemdecl} -template::value_type>> - basic_string(InputIterator, InputIterator, Allocator = Allocator()) - -> basic_string::value_type, - char_traits::value_type>, - Allocator>; +constexpr size_type max_size() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{InputIterator} is a type that qualifies as an input iterator, -and \tcode{Allocator} is a type that qualifies as an allocator\iref{container.requirements.general}. +\returns +The largest possible number of char-like objects that can be referred to by a \tcode{basic_string_view}. \end{itemdescr} +\indexlibrarymember{empty}{basic_string_view}% \begin{itemdecl} -template> - explicit basic_string(basic_string_view, const Allocator& = Allocator()) - -> basic_string; - -template> - basic_string(basic_string_view, - typename @\seebelow@::size_type, typename @\seebelow@::size_type, - const Allocator& = Allocator()) - -> basic_string; +[[nodiscard]] constexpr bool empty() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{Allocator} is a type that qualifies as -an allocator\iref{container.requirements.general}. +\returns +\tcode{size_ == 0}. \end{itemdescr} -\indexlibrarymember{operator=}{basic_string}% +\rSec3[string.view.access]{Element access} + +\indexlibrarymember{operator[]}{basic_string_view}% \begin{itemdecl} -constexpr basic_string& operator=(const basic_string& str); +constexpr const_reference operator[](size_type pos) const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -If \tcode{*this} and \tcode{str} are the same object, has no effect. -Otherwise, replaces the value of \tcode{*this} with a copy of \tcode{str}. +\expects +\tcode{pos < size()}. \pnum \returns -\tcode{*this}. +\tcode{data_[pos]}. + +\pnum +\throws +Nothing. + +\pnum +\begin{note} +Unlike \tcode{basic_string::operator[]}, +\tcode{basic_string_view::operator[](size())} has undefined behavior instead of returning \tcode{charT()}. +\end{note} \end{itemdescr} -\indexlibrarymember{operator=}{basic_string}% +\indexlibrarymember{at}{basic_string_view}% \begin{itemdecl} -constexpr basic_string& operator=(basic_string&& str) - noexcept(allocator_traits::propagate_on_container_move_assignment::value || - allocator_traits::is_always_equal::value); +constexpr const_reference at(size_type pos) const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Move assigns as a sequence container\iref{container.requirements}, -except that iterators, pointers and references may be invalidated. +\returns +\tcode{data_[pos]}. \pnum -\returns -\tcode{*this}. +\throws +\tcode{out_of_range} if \tcode{pos >= size()}. \end{itemdescr} -\indexlibrarymember{operator=}{basic_string}% +\indexlibrarymember{front}{basic_string_view}% \begin{itemdecl} -template - constexpr basic_string& operator=(const T& t); +constexpr const_reference front() const; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\begin{itemize} -\item \tcode{is_convertible_v>} -is \tcode{true} and -\item \tcode{is_convertible_v} -is \tcode{false}. -\end{itemize} +\expects +\tcode{!empty()}. \pnum -\effects -Equivalent to: -\begin{codeblock} -basic_string_view sv = t; -return assign(sv); -\end{codeblock} +\returns +\tcode{data_[0]}. + +\pnum +\throws +Nothing. \end{itemdescr} -\indexlibrarymember{operator=}{basic_string}% +\indexlibrarymember{back}{basic_string_view}% \begin{itemdecl} -constexpr basic_string& operator=(const charT* s); +constexpr const_reference back() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\tcode{return *this = basic_string_view(s);} +\expects +\tcode{!empty()}. + +\pnum +\returns +\tcode{data_[size() - 1]}. + +\pnum +\throws +Nothing. \end{itemdescr} -\indexlibrarymember{operator=}{basic_string}% +\indexlibrarymember{data}{basic_string_view}% \begin{itemdecl} -constexpr basic_string& operator=(charT c); +constexpr const_pointer data() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -return *this = basic_string_view(addressof(c), 1); -\end{codeblock} +\returns +\tcode{data_}. + +\pnum +\begin{note} +Unlike \tcode{basic_string::data()} and \grammarterm{string-literal}s, +\tcode{data()} can return a pointer to a buffer that is not null-terminated. +Therefore it is typically a mistake to pass \tcode{data()} to a function that takes just a \tcode{const charT*} and expects a null-terminated string. +\end{note} \end{itemdescr} -\indexlibrarymember{operator=}{basic_string}% +\rSec3[string.view.modifiers]{Modifiers} + +\indexlibrarymember{remove_prefix}{basic_string_view}% \begin{itemdecl} -constexpr basic_string& operator=(initializer_list il); +constexpr void remove_prefix(size_type n); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{n <= size()}. + \pnum \effects -Equivalent to: -\begin{codeblock} -return *this = basic_string_view(il.begin(), il.size()); -\end{codeblock} +Equivalent to: \tcode{data_ += n; size_ -= n;} \end{itemdescr} -\rSec3[string.iterators]{Iterator support} - -\indexlibrarymember{begin}{basic_string}% -\indexlibrarymember{cbegin}{basic_string}% +\indexlibrarymember{remove_suffix}{basic_string_view}% \begin{itemdecl} -constexpr iterator begin() noexcept; -constexpr const_iterator begin() const noexcept; -constexpr const_iterator cbegin() const noexcept; +constexpr void remove_suffix(size_type n); \end{itemdecl} \begin{itemdescr} \pnum -\returns -An iterator referring to the first character in the string. +\expects +\tcode{n <= size()}. + +\pnum +\effects +Equivalent to: \tcode{size_ -= n;} \end{itemdescr} -\indexlibrarymember{end}{basic_string}% -\indexlibrarymember{cend}{basic_string}% +\indexlibrarymember{swap}{basic_string_view}% \begin{itemdecl} -constexpr iterator end() noexcept; -constexpr const_iterator end() const noexcept; -constexpr const_iterator cend() const noexcept; +constexpr void swap(basic_string_view& s) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns -An iterator which is the past-the-end value. +\effects +Exchanges the values of \tcode{*this} and \tcode{s}. \end{itemdescr} -\indexlibrarymember{rbegin}{basic_string}% -\indexlibrarymember{crbegin}{basic_string}% +\rSec3[string.view.ops]{String operations} + +\indexlibrarymember{copy}{basic_string_view}% \begin{itemdecl} -constexpr reverse_iterator rbegin() noexcept; -constexpr const_reverse_iterator rbegin() const noexcept; -constexpr const_reverse_iterator crbegin() const noexcept; +constexpr size_type copy(charT* s, size_type n, size_type pos = 0) const; \end{itemdecl} \begin{itemdescr} +\pnum +Let \tcode{rlen} be the smaller of \tcode{n} and \tcode{size() - pos}. + +\pnum +\expects +\range{s}{s + rlen} is a valid range. + +\pnum +\effects +Equivalent to \tcode{traits::copy(s, data() + pos, rlen)}. + \pnum \returns -An iterator which is semantically equivalent to -\tcode{reverse_iterator(end())}. +\tcode{rlen}. + +\pnum +\throws +\tcode{out_of_range} if \tcode{pos > size()}. + +\pnum +\complexity +\bigoh{\tcode{rlen}}. \end{itemdescr} -\indexlibrarymember{rend}{basic_string}% -\indexlibrarymember{crend}{basic_string}% +\indexlibrarymember{substr}{basic_string_view}% \begin{itemdecl} -constexpr reverse_iterator rend() noexcept; -constexpr const_reverse_iterator rend() const noexcept; -constexpr const_reverse_iterator crend() const noexcept; +constexpr basic_string_view substr(size_type pos = 0, size_type n = npos) const; \end{itemdecl} \begin{itemdescr} +\pnum +Let \tcode{rlen} be the smaller of \tcode{n} and \tcode{size() - pos}. + +\pnum +\effects +Determines \tcode{rlen}, the effective length of the string to reference. + \pnum \returns -An iterator which is semantically equivalent to -\tcode{reverse_iterator(begin())}. -\end{itemdescr} +\tcode{basic_string_view(data() + pos, rlen)}. -\rSec3[string.capacity]{Capacity} +\pnum +\throws +\tcode{out_of_range} if \tcode{pos > size()}. +\end{itemdescr} -\indexlibrarymember{size}{basic_string}% -\indexlibrarymember{length}{basic_string}% +\indexlibrarymember{compare}{basic_string_view}% \begin{itemdecl} -constexpr size_type size() const noexcept; -constexpr size_type length() const noexcept; +constexpr int compare(basic_string_view str) const noexcept; \end{itemdecl} \begin{itemdescr} +\pnum +Let \tcode{rlen} be the smaller of \tcode{size()} and \tcode{str.size()}. + +\pnum +\effects +Determines \tcode{rlen}, the effective length of the strings to compare. +The function then compares the two strings by calling \tcode{traits::compare(data(), str.data(), rlen)}. + \pnum \returns -A count of the number of char-like objects currently in the string. +The nonzero result if the result of the comparison is nonzero. +Otherwise, returns a value as indicated in \tref{string.view.compare}. +\begin{libtab2}{\tcode{compare()} results}{string.view.compare}{cc}{Condition}{Return Value} +\tcode{size() < str.size()} & \tcode{< 0}\\ +\tcode{size() == str.size()} & \tcode{ \ 0}\\ +\tcode{size() > str.size()} & \tcode{> 0}\\ +\end{libtab2} \pnum \complexity -Constant time. +\bigoh{\tcode{rlen}}. \end{itemdescr} -\indexlibrarymember{max_size}{basic_string}% +\indexlibrarymember{compare}{basic_string_view}% \begin{itemdecl} -constexpr size_type max_size() const noexcept; +constexpr int compare(size_type pos1, size_type n1, basic_string_view str) const; \end{itemdecl} \begin{itemdescr} \pnum -\returns -The largest possible number of char-like objects that can be stored in a -\tcode{basic_string}. +\effects +Equivalent to: \tcode{return substr(pos1, n1).compare(str);} +\end{itemdescr} + +\indexlibrarymember{compare}{basic_string_view}% +\begin{itemdecl} +constexpr int compare(size_type pos1, size_type n1, basic_string_view str, + size_type pos2, size_type n2) const; +\end{itemdecl} +\begin{itemdescr} \pnum -\complexity -Constant time. +\effects +Equivalent to: \tcode{return substr(pos1, n1).compare(str.substr(pos2, n2));} \end{itemdescr} -\indexlibrarymember{resize}{basic_string}% +\indexlibrarymember{compare}{basic_string_view}% \begin{itemdecl} -constexpr void resize(size_type n, charT c); +constexpr int compare(const charT* s) const; \end{itemdecl} \begin{itemdescr} \pnum \effects -Alters the value of -\tcode{*this} -as follows: -\begin{itemize} -\item -If -\tcode{n <= size()}, -erases the last \tcode{size() - n} elements. -\item -If -\tcode{n > size()}, -appends \tcode{n - size()} copies of \tcode{c}. -\end{itemize} +Equivalent to: \tcode{return compare(basic_string_view(s));} \end{itemdescr} -\indexlibrarymember{resize}{basic_string}% +\indexlibrarymember{compare}{basic_string_view}% \begin{itemdecl} -constexpr void resize(size_type n); +constexpr int compare(size_type pos1, size_type n1, const charT* s) const; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to \tcode{resize(n, charT())}. +Equivalent to: \tcode{return substr(pos1, n1).compare(basic_string_view(s));} \end{itemdescr} -\indexlibrarymember{resize_and_overwrite}{basic_string}% +\indexlibrarymember{compare}{basic_string_view}% \begin{itemdecl} -template constexpr void resize_and_overwrite(size_type n, Operation op); +constexpr int compare(size_type pos1, size_type n1, const charT* s, size_type n2) const; \end{itemdecl} \begin{itemdescr} -\pnum -Let -\begin{itemize} -\item -\tcode{o = size()} before the call to \tcode{resize_and_overwrite}. -\item -\tcode{k} be \tcode{min(o, n)}. -\item -\tcode{p} be a \tcode{charT*}, -such that the range \crange{p}{p + n} is valid and -\tcode{this->compare(0, k, p, k) == 0} is \tcode{true} before the call. -The values in the range \crange{p + k}{p + n} may be indeterminate\iref{basic.indet}. -\item -$OP$ be the expression \tcode{std::move(op)(p, n)}. -\item -\tcode{r} = $OP$. -\end{itemize} - -\pnum -\mandates -$OP$ has an integer-like type\iref{iterator.concept.winc}. - -\pnum -\expects -\begin{itemize} -\item -$OP$ does not throw an exception or modify \tcode{p} or \tcode{n}. -\item -$\tcode{r} \geq 0$. -\item -$\tcode{r} \leq \tcode{n}$. -\item -After evaluating $OP$ -there are no indeterminate values in the range \range{p}{p + r}. -\end{itemize} - \pnum \effects -Evaluates $OP$, -replaces the contents of \tcode{*this} with \range{p}{p + r}, and -invalidates all pointers and references to the range \crange{p}{p + n}. - -\pnum -\recommended -Implementations should avoid unnecessary copies and allocations -by, for example, making \tcode{p} a pointer into internal storage and -by restoring \tcode{*(p + r)} to \tcode{charT()} after evaluating $OP$. +Equivalent to: \tcode{return substr(pos1, n1).compare(basic_string_view(s, n2));} \end{itemdescr} -\indexlibrarymember{capacity}{basic_string}% +\indexlibrarymember{starts_with}{basic_string_view}% \begin{itemdecl} -constexpr size_type capacity() const noexcept; +constexpr bool starts_with(basic_string_view x) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns -The size of the allocated storage in the string. - -\pnum -\complexity -Constant time. +\effects +Equivalent to: \tcode{return substr(0, x.size()) == x;} \end{itemdescr} -\indexlibrarymember{reserve}{basic_string}% +\indexlibrarymember{starts_with}{basic_string_view}% \begin{itemdecl} -constexpr void reserve(size_type res_arg); +constexpr bool starts_with(charT x) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects -A directive that informs a \tcode{basic_string} of a planned change in size, -so that the storage allocation can be managed accordingly. -After -\tcode{reserve()}, -\tcode{capacity()} -is greater or equal to the argument of -\tcode{reserve} -if reallocation happens; and -equal to the previous value of -\tcode{capacity()} -otherwise. -Reallocation happens at this point if and only if -the current capacity is less than the argument of \tcode{reserve()}. - -\pnum -\throws -\tcode{length_error} -if -\tcode{res_arg > max_size()} or any exceptions thrown by -\tcode{allocator_traits} \tcode{::allocate}. +Equivalent to: \tcode{return !empty() \&\& traits::eq(front(), x);} \end{itemdescr} -\indexlibrarymember{shrink_to_fit}{basic_string}% +\indexlibrarymember{starts_with}{basic_string_view}% \begin{itemdecl} -constexpr void shrink_to_fit(); +constexpr bool starts_with(const charT* x) const; \end{itemdecl} \begin{itemdescr} \pnum \effects -\tcode{shrink_to_fit} is a non-binding request to reduce -\tcode{capacity()} to \tcode{size()}. -\begin{note} -The request is non-binding to -allow latitude for implementation-specific optimizations. -\end{note} -It does not increase \tcode{capacity()}, but may reduce \tcode{capacity()} -by causing reallocation. +Equivalent to: \tcode{return starts_with(basic_string_view(x));} +\end{itemdescr} -\pnum -\complexity -If the size is not equal to the old capacity, -linear in the size of the sequence; -otherwise constant. +\indexlibrarymember{ends_with}{basic_string_view}% +\begin{itemdecl} +constexpr bool ends_with(basic_string_view x) const noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -\remarks -Reallocation invalidates all the references, pointers, and iterators -referring to the elements in the sequence, as well as the past-the-end iterator. -\begin{note} -If no reallocation happens, they remain valid. -\end{note} +\effects +Equivalent to: +\begin{codeblock} +return size() >= x.size() && compare(size() - x.size(), npos, x) == 0; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{clear}{basic_string}% +\indexlibrarymember{ends_with}{basic_string_view}% \begin{itemdecl} -constexpr void clear() noexcept; +constexpr bool ends_with(charT x) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{erase(begin(), end());} +Equivalent to: \tcode{return !empty() \&\& traits::eq(back(), x);} \end{itemdescr} -\indexlibrarymember{empty}{basic_string}% +\indexlibrarymember{ends_with}{basic_string_view}% \begin{itemdecl} -[[nodiscard]] constexpr bool empty() const noexcept; +constexpr bool ends_with(const charT* x) const; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\tcode{return size() == 0;} +Equivalent to: \tcode{return ends_with(basic_string_view(x));} \end{itemdescr} -\rSec3[string.access]{Element access} - -\indexlibrarymember{operator[]}{basic_string}% +\indexlibrarymember{contains}{basic_string_view}% \begin{itemdecl} -constexpr const_reference operator[](size_type pos) const; -constexpr reference operator[](size_type pos); +constexpr bool contains(basic_string_view x) const noexcept; +constexpr bool contains(charT x) const noexcept; +constexpr bool contains(const charT* x) const; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{pos <= size()}. +\effects +Equivalent to: \tcode{return find(x) != npos;} +\end{itemdescr} -\pnum -\returns -\tcode{*(begin() + pos)} if \tcode{pos < size()}. Otherwise, -returns a reference to an object of type \tcode{charT} with value -\tcode{charT()}, where modifying the object to any value other than -\tcode{charT()} leads to undefined behavior. +\rSec3[string.view.find]{Searching} \pnum -\throws -Nothing. +Member functions in this subclause have complexity \bigoh{\tcode{size() * str.size()}} at worst, +although implementations should do better. \pnum -\complexity -Constant time. -\end{itemdescr} +Let \placeholder{F} be one of +\tcode{find}, +\tcode{rfind}, +\tcode{find_first_of}, +\tcode{find_last_of}, +\tcode{find_first_not_of}, +and +\tcode{find_last_not_of}. +\begin{itemize} +\item +Each member function of the form +\begin{codeblock} +constexpr @\placeholder{return-type}@ @\placeholder{F}@(const charT* s, size_type pos) const; +\end{codeblock} +has effects equivalent to: \tcode{return \placeholder{F}(basic_string_view(s), pos);} -\indexlibrarymember{at}{basic_string}% +\item +Each member function of the form +\begin{codeblock} +constexpr @\placeholder{return-type}@ @\placeholder{F}@(const charT* s, size_type pos, size_type n) const; +\end{codeblock} +has effects equivalent to: \tcode{return \placeholder{F}(basic_string_view(s, n), pos);} + +\item +Each member function of the form +\begin{codeblock} +constexpr @\placeholder{return-type}@ @\placeholder{F}@(charT c, size_type pos) const noexcept; +\end{codeblock} +has effects equivalent to: \tcode{return \placeholder{F}(basic_string_view(addressof(c), 1), pos);} +\end{itemize} + +\indexlibrarymember{find}{basic_string_view}% \begin{itemdecl} -constexpr const_reference at(size_type pos) const; -constexpr reference at(size_type pos); +constexpr size_type find(basic_string_view str, size_type pos = 0) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{operator[](pos)}. +Let \tcode{xpos} be the lowest position, if possible, such that the following conditions hold: +\begin{itemize} +\item +\tcode{pos <= xpos} +\item +\tcode{xpos + str.size() <= size()} +\item +\tcode{traits::eq(at(xpos + I), str.at(I))} for all elements \tcode{I} of the string referenced by \tcode{str}. +\end{itemize} \pnum -\throws -\tcode{out_of_range} -if -\tcode{pos >= size()}. +\effects +Determines \tcode{xpos}. + +\pnum +\returns +\tcode{xpos} if the function can determine such a value for \tcode{xpos}. +Otherwise, returns \tcode{npos}. \end{itemdescr} -\indexlibrarymember{front}{basic_string}% +\indexlibrarymember{rfind}{basic_string_view}% \begin{itemdecl} -constexpr const charT& front() const; -constexpr charT& front(); +constexpr size_type rfind(basic_string_view str, size_type pos = npos) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{!empty()}. +Let \tcode{xpos} be the highest position, if possible, such that the following conditions hold: +\begin{itemize} +\item +\tcode{xpos <= pos} +\item +\tcode{xpos + str.size() <= size()} +\item +\tcode{traits::eq(at(xpos + I), str.at(I))} for all elements \tcode{I} of the string referenced by \tcode{str}. +\end{itemize} \pnum \effects -Equivalent to: \tcode{return operator[](0);} +Determines \tcode{xpos}. + +\pnum +\returns +\tcode{xpos} if the function can determine such a value for \tcode{xpos}. +Otherwise, returns \tcode{npos}. \end{itemdescr} -\indexlibrarymember{back}{basic_string}% +\indexlibrarymember{find_first_of}{basic_string_view}% \begin{itemdecl} -constexpr const charT& back() const; -constexpr charT& back(); +constexpr size_type find_first_of(basic_string_view str, size_type pos = 0) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{!empty()}. +Let \tcode{xpos} be the lowest position, if possible, such that the following conditions hold: +\begin{itemize} +\item +\tcode{pos <= xpos} +\item +\tcode{xpos < size()} +\item +\tcode{traits::eq(at(xpos), str.at(I))} for some element \tcode{I} of the string referenced by \tcode{str}. +\end{itemize} \pnum \effects -Equivalent to: \tcode{return operator[](size() - 1);} -\end{itemdescr} - -\rSec3[string.modifiers]{Modifiers} +Determines \tcode{xpos}. -\rSec4[string.op.append]{\tcode{basic_string::operator+=}} +\pnum +\returns +\tcode{xpos} if the function can determine such a value for \tcode{xpos}. +Otherwise, returns \tcode{npos}. +\end{itemdescr} -\indexlibrarymember{operator+=}{basic_string}% +\indexlibrarymember{find_last_of}{basic_string_view}% \begin{itemdecl} -constexpr basic_string& operator+=(const basic_string& str); +constexpr size_type find_last_of(basic_string_view str, size_type pos = npos) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return append(str);} +Let \tcode{xpos} be the highest position, if possible, such that the following conditions hold: +\begin{itemize} +\item +\tcode{xpos <= pos} +\item +\tcode{xpos < size()} +\item +\tcode{traits::eq(at(xpos), str.at(I))} for some element \tcode{I} of the string referenced by \tcode{str}. +\end{itemize} +\pnum +\effects +Determines \tcode{xpos}. +\pnum +\returns +\tcode{xpos} if the function can determine such a value for \tcode{xpos}. +Otherwise, returns \tcode{npos}. \end{itemdescr} -\indexlibrarymember{operator+=}{basic_string}% +\indexlibrarymember{find_first_not_of}{basic_string_view}% \begin{itemdecl} -template - constexpr basic_string& operator+=(const T& t); +constexpr size_type find_first_not_of(basic_string_view str, size_type pos = 0) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\constraints +Let \tcode{xpos} be the lowest position, if possible, such that the following conditions hold: \begin{itemize} \item -\tcode{is_convertible_v>} is -\tcode{true} and +\tcode{pos <= xpos} \item -\tcode{is_convertible_v} is -\tcode{false}. +\tcode{xpos < size()} +\item +\tcode{traits::eq(at(xpos), str.at(I))} for no element \tcode{I} of the string referenced by \tcode{str}. \end{itemize} \pnum \effects -Equivalent to: -\begin{codeblock} -basic_string_view sv = t; -return append(sv); -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{operator+=}{basic_string}% -\begin{itemdecl} -constexpr basic_string& operator+=(const charT* s); -\end{itemdecl} +Determines \tcode{xpos}. -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return append(s);} +\returns +\tcode{xpos} if the function can determine such a value for \tcode{xpos}. Otherwise, returns \tcode{npos}. \end{itemdescr} -\indexlibrarymember{operator+=}{basic_string}% +\indexlibrarymember{find_last_not_of}{basic_string_view}% \begin{itemdecl} -constexpr basic_string& operator+=(charT c); +constexpr size_type find_last_not_of(basic_string_view str, size_type pos = npos) const noexcept; \end{itemdecl} \begin{itemdescr} +\pnum +Let \tcode{xpos} be the highest position, if possible, such that the following conditions hold: +\begin{itemize} +\item +\tcode{xpos <= pos} +\item +\tcode{xpos < size()} +\item +\tcode{traits::eq(at(xpos), str.at(I))} for no element \tcode{I} of the string referenced by \tcode{str}. +\end{itemize} + \pnum \effects -Equivalent to: \tcode{return append(size_type\{1\}, c);} +Determines \tcode{xpos}. + +\pnum +\returns +\tcode{xpos} if the function can determine such a value for \tcode{xpos}. +Otherwise, returns \tcode{npos}. \end{itemdescr} -\indexlibrarymember{operator+=}{basic_string}% +\rSec2[string.view.deduct]{Deduction guides} + \begin{itemdecl} -constexpr basic_string& operator+=(initializer_list il); +template + basic_string_view(It, End) -> basic_string_view>; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return append(il);} +\constraints +\begin{itemize} +\item \tcode{It} satisfies \libconcept{contiguous_iterator}. +\item \tcode{End} satisfies \tcode{\libconcept{sized_sentinel_for}}. +\end{itemize} \end{itemdescr} - -\rSec4[string.append]{\tcode{basic_string::append}} - -\indexlibrarymember{append}{basic_string}% \begin{itemdecl} -constexpr basic_string& append(const basic_string& str); +template + basic_string_view(R&&) -> basic_string_view>; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return append(str.data(), str.size());} +\constraints +\tcode{R} satisfies \tcode{ranges::\libconcept{contiguous_range}}. \end{itemdescr} -\indexlibrarymember{append}{basic_string}% -\begin{itemdecl} -constexpr basic_string& append(const basic_string& str, size_type pos, size_type n = npos); -\end{itemdecl} +\rSec2[string.view.comparison]{Non-member comparison functions} -\begin{itemdescr} \pnum -\effects -Equivalent to: +Let \tcode{S} be \tcode{basic_string_view}, and \tcode{sv} be an instance of \tcode{S}. +Implementations shall provide sufficient additional overloads marked \keyword{constexpr} and \keyword{noexcept} +so that an object \tcode{t} with an implicit conversion to \tcode{S} can be compared according to \tref{string.view.comparison.overloads}. +\begin{libtab2}{Additional \tcode{basic_string_view} comparison overloads}{string.view.comparison.overloads}{cc}{Expression}{Equivalent to} +\tcode{t == sv} & \tcode{S(t) == sv} \\ +\tcode{sv == t} & \tcode{sv == S(t)} \\ +\tcode{t != sv} & \tcode{S(t) != sv} \\ +\tcode{sv != t} & \tcode{sv != S(t)} \\ +\tcode{t < sv} & \tcode{S(t) < sv} \\ +\tcode{sv < t} & \tcode{sv < S(t)} \\ +\tcode{t > sv} & \tcode{S(t) > sv} \\ +\tcode{sv > t} & \tcode{sv > S(t)} \\ +\tcode{t <= sv} & \tcode{S(t) <= sv} \\ +\tcode{sv <= t} & \tcode{sv <= S(t)} \\ +\tcode{t >= sv} & \tcode{S(t) >= sv} \\ +\tcode{sv >= t} & \tcode{sv >= S(t)} \\ +\tcode{t <=> sv} & \tcode{S(t) <=> sv} \\ +\tcode{sv <=> t} & \tcode{sv <=> S(t)} \\ +\end{libtab2} +\begin{example} +A sample conforming implementation for \tcode{operator==} would be: \begin{codeblock} -return append(basic_string_view(str).substr(pos, n)); +template + constexpr bool operator==(basic_string_view lhs, + basic_string_view rhs) noexcept { + return lhs.compare(rhs) == 0; + } +template + constexpr bool operator==(basic_string_view lhs, + type_identity_t> rhs) noexcept { + return lhs.compare(rhs) == 0; + } \end{codeblock} -\end{itemdescr} +\end{example} -\indexlibrarymember{append}{basic_string}% +\indexlibrarymember{operator==}{basic_string_view}% \begin{itemdecl} -template - constexpr basic_string& append(const T& t); +template + constexpr bool operator==(basic_string_view lhs, + basic_string_view rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\begin{itemize} -\item -\tcode{is_convertible_v>} is -\tcode{true} and -\item -\tcode{is_convertible_v} is -\tcode{false}. -\end{itemize} - -\pnum -\effects -Equivalent to: -\begin{codeblock} -basic_string_view sv = t; -return append(sv.data(), sv.size()); -\end{codeblock} +\returns +\tcode{lhs.compare(rhs) == 0}. \end{itemdescr} -\indexlibrarymember{append}{basic_string}% +\indexlibrarymember{operator<=>}{basic_string_view}% \begin{itemdecl} -template - constexpr basic_string& append(const T& t, size_type pos, size_type n = npos); +template + constexpr @\seebelow@ operator<=>(basic_string_view lhs, + @\itcorr@ basic_string_view rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\begin{itemize} -\item -\tcode{is_convertible_v>} is -\tcode{true} and -\item -\tcode{is_convertible_v} is -\tcode{false}. -\end{itemize} +Let \tcode{R} denote the type \tcode{traits::comparison_category} if +that \grammarterm{qualified-id} is valid and denotes a type\iref{temp.deduct}, +otherwise \tcode{R} is \tcode{weak_ordering}. \pnum -\effects -Equivalent to: -\begin{codeblock} -basic_string_view sv = t; -return append(sv.substr(pos, n)); -\end{codeblock} +\mandates +\tcode{R} denotes a comparison category type\iref{cmp.categories}. + +\pnum +\returns +\tcode{static_cast(lhs.compare(rhs) <=> 0)}. \end{itemdescr} -\indexlibrarymember{append}{basic_string}% +\rSec2[string.view.io]{Inserters and extractors} + +\indexlibrarymember{operator<<}{basic_string_view}% \begin{itemdecl} -constexpr basic_string& append(const charT* s, size_type n); +template + basic_ostream& + operator<<(basic_ostream& os, basic_string_view str); \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\range{s}{s + n} is a valid range. - \pnum \effects -Appends a copy of the range \range{s}{s + n} to the string. +Behaves as a formatted output +function\iref{ostream.formatted.reqmts} of \tcode{os}. Forms a character sequence +\tcode{seq}, initially consisting of the elements defined by the range +\range{str.begin()}{str.end()}. Determines padding for \tcode{seq} +as described in~\ref{ostream.formatted.reqmts}. +Then inserts \tcode{seq} as if by calling +\tcode{os.rdbuf()->sputn(\brk{}seq, n)}, where \tcode{n} is the larger +of \tcode{os.width()} and \tcode{str.size()}; +then calls \tcode{os.\brk{}width(0)}. \pnum \returns -\tcode{*this}. +\tcode{os} \end{itemdescr} -\indexlibrarymember{append}{basic_string}% +\rSec2[string.view.hash]{Hash support} + +\indexlibrarymember{hash}{string_view}% +\indexlibrarymember{hash}{u8string_view}% +\indexlibrarymember{hash}{u16string_view}% +\indexlibrarymember{hash}{u32string_view}% +\indexlibrarymember{hash}{wstring_view}% \begin{itemdecl} -constexpr basic_string& append(const charT* s); +template<> struct hash; +template<> struct hash; +template<> struct hash; +template<> struct hash; +template<> struct hash; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return append(s, traits::length(s));} +The specialization is enabled\iref{unord.hash}. +\begin{note} +The hash value of a string view object is equal to the hash value of +the corresponding string object\iref{basic.string.hash}. +\end{note} \end{itemdescr} -\indexlibrarymember{append}{basic_string}% +\rSec2[string.view.literals]{Suffix for \tcode{basic_string_view} literals} + +\indexlibrarymember{operator""""sv}{string_view}% \begin{itemdecl} -constexpr basic_string& append(size_type n, charT c); +constexpr string_view operator""sv(const char* str, size_t len) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\effects -Appends \tcode{n} copies of \tcode{c} to the string. - \pnum \returns -\tcode{*this}. +\tcode{string_view\{str, len\}}. \end{itemdescr} -\indexlibrarymember{append}{basic_string}% +\indexlibrarymember{operator""""sv}{u8string_view}% \begin{itemdecl} -template - constexpr basic_string& append(InputIterator first, InputIterator last); +constexpr u8string_view operator""sv(const char8_t* str, size_t len) noexcept; \end{itemdecl} - \begin{itemdescr} \pnum -\constraints -\tcode{InputIterator} is a type that qualifies as an input -iterator\iref{container.requirements.general}. - -\pnum -\effects -Equivalent to: \tcode{return append(basic_string(first, last, get_allocator()));} +\returns +\tcode{u8string_view\{str, len\}}. \end{itemdescr} -\indexlibrarymember{append_range}{basic_string}% +\indexlibrarymember{operator""""sv}{u16string_view}% \begin{itemdecl} -template<@\exposconcept{container-compatible-range}@ R> - constexpr basic_string& append_range(R&& rg); +constexpr u16string_view operator""sv(const char16_t* str, size_t len) noexcept; \end{itemdecl} - \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return append(basic_string(from_range, std::forward(rg), get_allocator()));} +\returns +\tcode{u16string_view\{str, len\}}. \end{itemdescr} -\indexlibrarymember{append}{basic_string}% +\indexlibrarymember{operator""""sv}{u32string_view}% \begin{itemdecl} -constexpr basic_string& append(initializer_list il); +constexpr u32string_view operator""sv(const char32_t* str, size_t len) noexcept; \end{itemdecl} - \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return append(il.begin(), il.size());} +\returns +\tcode{u32string_view\{str, len\}}. \end{itemdescr} -\indexlibrarymember{push_back}{basic_string}% +\indexlibrarymember{operator""""sv}{wstring_view}% \begin{itemdecl} -constexpr void push_back(charT c); +constexpr wstring_view operator""sv(const wchar_t* str, size_t len) noexcept; \end{itemdecl} - \begin{itemdescr} \pnum -\effects -Equivalent to -\tcode{append(size_type\{1\}, c)}. +\returns +\tcode{wstring_view\{str, len\}}. \end{itemdescr} -\rSec4[string.assign]{\tcode{basic_string::assign}} - -\indexlibrarymember{assign}{basic_string}% -\begin{itemdecl} -constexpr basic_string& assign(const basic_string& str); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return *this = str;} -\end{itemdescr} +\rSec1[string.classes]{String classes} -\indexlibrarymember{assign}{basic_string}% -\begin{itemdecl} -constexpr basic_string& assign(basic_string&& str) - noexcept(allocator_traits::propagate_on_container_move_assignment::value || - allocator_traits::is_always_equal::value); -\end{itemdecl} +\rSec2[string.classes.general]{General} -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return *this = std::move(str);} -\end{itemdescr} - +The header \tcode{} defines the +\tcode{basic_string} class template for manipulating +varying-length sequences of char-like objects and five +\grammarterm{typedef-name}{s}, \tcode{string}, +\tcode{u8string}, +\tcode{u16string}, +\tcode{u32string}, +and \tcode{wstring}, that name +the specializations +\tcode{basic_string}, +\tcode{basic_string}, +\tcode{basic_string}, +\tcode{basic_string}, +and +\tcode{basic_string<\brk{}wchar_t>}, respectively. -\indexlibrarymember{assign}{basic_string}% -\begin{itemdecl} -constexpr basic_string& assign(const basic_string& str, size_type pos, size_type n = npos); -\end{itemdecl} +\rSec2[string.syn]{Header \tcode{} synopsis} +\indexheader{string}% -\begin{itemdescr} -\pnum -\effects -Equivalent to: \begin{codeblock} -return assign(basic_string_view(str).substr(pos, n)); -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{assign}{basic_string}% -\begin{itemdecl} -template - constexpr basic_string& assign(const T& t); -\end{itemdecl} +#include // see \ref{compare.syn} +#include // see \ref{initializer.list.syn} -\begin{itemdescr} -\pnum -\constraints -\begin{itemize} -\item -\tcode{is_convertible_v>} is -\tcode{true} and -\item -\tcode{is_convertible_v} is -\tcode{false}. -\end{itemize} +namespace std { + // \ref{char.traits}, character traits + template struct char_traits; + template<> struct char_traits; + template<> struct char_traits; + template<> struct char_traits; + template<> struct char_traits; + template<> struct char_traits; -\pnum -\effects -Equivalent to: -\begin{codeblock} -basic_string_view sv = t; -return assign(sv.data(), sv.size()); -\end{codeblock} -\end{itemdescr} + // \ref{basic.string}, \tcode{basic_string} + template, class Allocator = allocator> + class basic_string; -\indexlibrarymember{assign}{basic_string}% -\begin{itemdecl} -template - constexpr basic_string& assign(const T& t, size_type pos, size_type n = npos); -\end{itemdecl} + template + constexpr basic_string + operator+(const basic_string& lhs, + const basic_string& rhs); + template + constexpr basic_string + operator+(basic_string&& lhs, + const basic_string& rhs); + template + constexpr basic_string + operator+(const basic_string& lhs, + basic_string&& rhs); + template + constexpr basic_string + operator+(basic_string&& lhs, + basic_string&& rhs); + template + constexpr basic_string + operator+(const charT* lhs, + const basic_string& rhs); + template + constexpr basic_string + operator+(const charT* lhs, + basic_string&& rhs); + template + constexpr basic_string + operator+(charT lhs, + const basic_string& rhs); + template + constexpr basic_string + operator+(charT lhs, + basic_string&& rhs); + template + constexpr basic_string + operator+(const basic_string& lhs, + const charT* rhs); + template + constexpr basic_string + operator+(basic_string&& lhs, + const charT* rhs); + template + constexpr basic_string + operator+(const basic_string& lhs, + charT rhs); + template + constexpr basic_string + operator+(basic_string&& lhs, + charT rhs); -\begin{itemdescr} -\pnum -\constraints -\begin{itemize} -\item -\tcode{is_convertible_v>} is -\tcode{true} and -\item -\tcode{is_convertible_v} is -\tcode{false}. -\end{itemize} + template + constexpr bool + operator==(const basic_string& lhs, + const basic_string& rhs) noexcept; + template + constexpr bool operator==(const basic_string& lhs, + const charT* rhs); -\pnum -\effects -Equivalent to: -\begin{codeblock} -basic_string_view sv = t; -return assign(sv.substr(pos, n)); -\end{codeblock} -\end{itemdescr} + template + constexpr @\seebelow@ operator<=>(const basic_string& lhs, + @\itcorr@ const basic_string& rhs) noexcept; + template + constexpr @\seebelow@ operator<=>(const basic_string& lhs, + @\itcorr@ const charT* rhs); -\indexlibrarymember{assign}{basic_string}% -\begin{itemdecl} -constexpr basic_string& assign(const charT* s, size_type n); -\end{itemdecl} + // \ref{string.special}, swap + template + constexpr void + swap(basic_string& lhs, + basic_string& rhs) + noexcept(noexcept(lhs.swap(rhs))); -\begin{itemdescr} -\pnum -\expects -\range{s}{s + n} is a valid range. + // \ref{string.io}, inserters and extractors + template + basic_istream& + operator>>(basic_istream& is, + basic_string& str); + template + basic_ostream& + operator<<(basic_ostream& os, + const basic_string& str); + template + basic_istream& + getline(basic_istream& is, + basic_string& str, + charT delim); + template + basic_istream& + getline(basic_istream&& is, + basic_string& str, + charT delim); + template + basic_istream& + getline(basic_istream& is, + basic_string& str); + template + basic_istream& + getline(basic_istream&& is, + basic_string& str); -\pnum -\effects -Replaces the string controlled by \tcode{*this} with -a copy of the range \range{s}{s + n}. + // \ref{string.erasure}, erasure + template + constexpr typename basic_string::size_type + erase(basic_string& c, const U& value); + template + constexpr typename basic_string::size_type + erase_if(basic_string& c, Predicate pred); -\pnum -\returns -\tcode{*this}. -\end{itemdescr} + // \tcode{basic_string} \grammarterm{typedef-name}s + using @\libglobal{string}@ = basic_string; + using @\libglobal{u8string}@ = basic_string; + using @\libglobal{u16string}@ = basic_string; + using @\libglobal{u32string}@ = basic_string; + using @\libglobal{wstring}@ = basic_string; -\indexlibrarymember{assign}{basic_string}% -\begin{itemdecl} -constexpr basic_string& assign(const charT* s); -\end{itemdecl} + // \ref{string.conversions}, numeric conversions + int stoi(const string& str, size_t* idx = nullptr, int base = 10); + long stol(const string& str, size_t* idx = nullptr, int base = 10); + unsigned long stoul(const string& str, size_t* idx = nullptr, int base = 10); + long long stoll(const string& str, size_t* idx = nullptr, int base = 10); + unsigned long long stoull(const string& str, size_t* idx = nullptr, int base = 10); + float stof(const string& str, size_t* idx = nullptr); + double stod(const string& str, size_t* idx = nullptr); + long double stold(const string& str, size_t* idx = nullptr); + string to_string(int val); + string to_string(unsigned val); + string to_string(long val); + string to_string(unsigned long val); + string to_string(long long val); + string to_string(unsigned long long val); + string to_string(float val); + string to_string(double val); + string to_string(long double val); -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return assign(s, traits::length(s));} -\end{itemdescr} + int stoi(const wstring& str, size_t* idx = nullptr, int base = 10); + long stol(const wstring& str, size_t* idx = nullptr, int base = 10); + unsigned long stoul(const wstring& str, size_t* idx = nullptr, int base = 10); + long long stoll(const wstring& str, size_t* idx = nullptr, int base = 10); + unsigned long long stoull(const wstring& str, size_t* idx = nullptr, int base = 10); + float stof(const wstring& str, size_t* idx = nullptr); + double stod(const wstring& str, size_t* idx = nullptr); + long double stold(const wstring& str, size_t* idx = nullptr); + wstring to_wstring(int val); + wstring to_wstring(unsigned val); + wstring to_wstring(long val); + wstring to_wstring(unsigned long val); + wstring to_wstring(long long val); + wstring to_wstring(unsigned long long val); + wstring to_wstring(float val); + wstring to_wstring(double val); + wstring to_wstring(long double val); -\indexlibrarymember{assign}{basic_string}% -\begin{itemdecl} -constexpr basic_string& assign(initializer_list il); -\end{itemdecl} + namespace pmr { + template> + using basic_string = std::basic_string>; -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return assign(il.begin(), il.size());} -\end{itemdescr} + using string = basic_string; + using u8string = basic_string; + using u16string = basic_string; + using u32string = basic_string; + using wstring = basic_string; + } -\indexlibrarymember{assign}{basic_string}% -\begin{itemdecl} -constexpr basic_string& assign(size_type n, charT c); -\end{itemdecl} + // \ref{basic.string.hash}, hash support + template struct hash; + template<> struct hash; + template<> struct hash; + template<> struct hash; + template<> struct hash; + template<> struct hash; + template<> struct hash; + template<> struct hash; + template<> struct hash; + template<> struct hash; + template<> struct hash; -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -clear(); -resize(n, c); -return *this; + inline namespace literals { + inline namespace string_literals { + // \ref{basic.string.literals}, suffix for \tcode{basic_string} literals + constexpr string operator""s(const char* str, size_t len); + constexpr u8string operator""s(const char8_t* str, size_t len); + constexpr u16string operator""s(const char16_t* str, size_t len); + constexpr u32string operator""s(const char32_t* str, size_t len); + constexpr wstring operator""s(const wchar_t* str, size_t len); + } + } +} \end{codeblock} -\end{itemdescr} - -\indexlibrarymember{assign}{basic_string}% -\begin{itemdecl} -template - constexpr basic_string& assign(InputIterator first, InputIterator last); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{InputIterator} is a type that qualifies as an input -iterator\iref{container.requirements.general}. -\pnum -\effects -Equivalent to: \tcode{return assign(basic_string(first, last, get_allocator()));} -\end{itemdescr} +\rSec2[basic.string]{Class template \tcode{basic_string}} -\indexlibrarymember{assign_range}{basic_string}% -\begin{itemdecl} -template<@\exposconcept{container-compatible-range}@ R> - constexpr basic_string& assign_range(R&& rg); -\end{itemdecl} +\rSec3[basic.string.general]{General} -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return assign(basic_string(from_range, std::forward(rg), get_allocator()));} -\end{itemdescr} - -\rSec4[string.insert]{\tcode{basic_string::insert}} - -\indexlibrarymember{insert}{basic_string}% -\begin{itemdecl} -constexpr basic_string& insert(size_type pos, const basic_string& str); -\end{itemdecl} +\indexlibraryglobal{basic_string}% +The +class template +\tcode{basic_string} +describes objects that can store a sequence consisting of a varying number of +arbitrary char-like objects with the first element of the sequence at position zero. +Such a sequence is also called a ``string'' if the type of the +char-like objects that it holds +is clear from context. +In the rest of \ref{basic.string}, +the type of the char-like objects held in a \tcode{basic_string} object +is designated by \tcode{charT}. -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return insert(pos, str.data(), str.size());} -\end{itemdescr} - -\indexlibrarymember{insert}{basic_string}% -\begin{itemdecl} -constexpr basic_string& insert(size_type pos1, const basic_string& str, - size_type pos2, size_type n = npos); -\end{itemdecl} +A specialization of \tcode{basic_string} is a contiguous container\iref{container.requirements.general}. -\begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -return insert(pos1, basic_string_view(str), pos2, n); -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{insert}{basic_string}% -\begin{itemdecl} -template - constexpr basic_string& insert(size_type pos, const T& t); -\end{itemdecl} +In all cases, +\crange{data()}{data() + size()} is a valid range, +\tcode{data() + size()} points at an object with value \tcode{charT()} +(a ``null terminator''\indextext{string!null terminator}), +and \tcode{size() <= capacity()} is \tcode{true}. -\begin{itemdescr} -\pnum -\constraints -\begin{itemize} -\item -\tcode{is_convertible_v>} is -\tcode{true} and -\item -\tcode{is_convertible_v} is -\tcode{false}. -\end{itemize} -\pnum -\effects -Equivalent to: +\indexlibraryglobal{basic_string}% +\indexlibrarymember{traits_type}{basic_string}% +\indexlibrarymember{value_type}{basic_string}% +\indexlibrarymember{allocator_type}{basic_string}% +\indexlibrarymember{size_type}{basic_string}% +\indexlibrarymember{difference_type}{basic_string}% +\indexlibrarymember{pointer}{basic_string}% +\indexlibrarymember{const_pointer}{basic_string}% +\indexlibrarymember{reference}{basic_string}% +\indexlibrarymember{const_reference}{basic_string}% +\indexlibrarymember{iterator}{basic_string}% +\indexlibrarymember{const_iterator}{basic_string}% +\indexlibrarymember{reverse_iterator}{basic_string}% +\indexlibrarymember{const_reverse_iterator}{basic_string}% \begin{codeblock} -basic_string_view sv = t; -return insert(pos, sv.data(), sv.size()); -\end{codeblock} -\end{itemdescr} +namespace std { + template, + class Allocator = allocator> + class basic_string { + public: + // types + using traits_type = traits; + using value_type = charT; + using allocator_type = Allocator; + using size_type = typename allocator_traits::size_type; + using difference_type = typename allocator_traits::difference_type; + using pointer = typename allocator_traits::pointer; + using const_pointer = typename allocator_traits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; -\indexlibrarymember{insert}{basic_string}% -\begin{itemdecl} -template - constexpr basic_string& insert(size_type pos1, const T& t, - size_type pos2, size_type n = npos); -\end{itemdecl} + using iterator = @\impdefx{type of \tcode{basic_string::iterator}}@; // see \ref{container.requirements} + using const_iterator = @\impdefx{type of \tcode{basic_string::const_iterator}}@; // see \ref{container.requirements} + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + static constexpr size_type npos = size_type(-1); -\begin{itemdescr} -\pnum -\constraints -\begin{itemize} -\item -\tcode{is_convertible_v>} is -\tcode{true} and -\item -\tcode{is_convertible_v} is -\tcode{false}. -\end{itemize} - -\pnum -\effects -Equivalent to: -\begin{codeblock} -basic_string_view sv = t; -return insert(pos1, sv.substr(pos2, n)); -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{insert}{basic_string}% -\begin{itemdecl} -constexpr basic_string& insert(size_type pos, const charT* s, size_type n); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\range{s}{s + n} is a valid range. - -\pnum -\effects -Inserts a copy of the range \range{s}{s + n} -immediately before the character at position \tcode{pos} if \tcode{pos < size()}, -or otherwise at the end of the string. - -\pnum -\returns -\tcode{*this}. - -\pnum -\throws -\begin{itemize} -\item \tcode{out_of_range} if \tcode{pos > size()}, -\item \tcode{length_error} if \tcode{n > max_size() - size()}, or -\item any exceptions thrown by \tcode{allocator_traits::allocate}. -\end{itemize} -\end{itemdescr} + // \ref{string.cons}, construct/copy/destroy + constexpr basic_string() noexcept(noexcept(Allocator())) : basic_string(Allocator()) { } + constexpr explicit basic_string(const Allocator& a) noexcept; + constexpr basic_string(const basic_string& str); + constexpr basic_string(basic_string&& str) noexcept; + constexpr basic_string(const basic_string& str, size_type pos, + const Allocator& a = Allocator()); + constexpr basic_string(const basic_string& str, size_type pos, size_type n, + const Allocator& a = Allocator()); + template + constexpr basic_string(const T& t, size_type pos, size_type n, + const Allocator& a = Allocator()); + template + constexpr explicit basic_string(const T& t, const Allocator& a = Allocator()); + constexpr basic_string(const charT* s, size_type n, const Allocator& a = Allocator()); + constexpr basic_string(const charT* s, const Allocator& a = Allocator()); + basic_string(nullptr_t) = delete; + constexpr basic_string(size_type n, charT c, const Allocator& a = Allocator()); + template + constexpr basic_string(InputIterator begin, InputIterator end, + const Allocator& a = Allocator()); + template<@\exposconcept{container-compatible-range}@ R> + constexpr basic_string(from_range_t, R&& rg, const Allocator& a = Allocator()); + constexpr basic_string(initializer_list, const Allocator& = Allocator()); + constexpr basic_string(const basic_string&, const Allocator&); + constexpr basic_string(basic_string&&, const Allocator&); + constexpr ~basic_string(); -\indexlibrarymember{insert}{basic_string}% -\begin{itemdecl} -constexpr basic_string& insert(size_type pos, const charT* s); -\end{itemdecl} + constexpr basic_string& operator=(const basic_string& str); + constexpr basic_string& operator=(basic_string&& str) + noexcept(allocator_traits::propagate_on_container_move_assignment::value || + allocator_traits::is_always_equal::value); + template + constexpr basic_string& operator=(const T& t); + constexpr basic_string& operator=(const charT* s); + basic_string& operator=(nullptr_t) = delete; + constexpr basic_string& operator=(charT c); + constexpr basic_string& operator=(initializer_list); -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return insert(pos, s, traits::length(s));} -\end{itemdescr} + // \ref{string.iterators}, iterators + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; -\indexlibrarymember{insert}{basic_string}% -\begin{itemdecl} -constexpr basic_string& insert(size_type pos, size_type n, charT c); -\end{itemdecl} + constexpr reverse_iterator rbegin() noexcept; + constexpr const_reverse_iterator rbegin() const noexcept; + constexpr reverse_iterator rend() noexcept; + constexpr const_reverse_iterator rend() const noexcept; -\begin{itemdescr} -\pnum -\effects -Inserts \tcode{n} copies of \tcode{c} before the character at position \tcode{pos} -if \tcode{pos < size()}, -or otherwise at the end of the string. + 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; -\pnum -\returns -\tcode{*this} + // \ref{string.capacity}, capacity + constexpr size_type size() const noexcept; + constexpr size_type length() const noexcept; + constexpr size_type max_size() const noexcept; + constexpr void resize(size_type n, charT c); + constexpr void resize(size_type n); + template constexpr void resize_and_overwrite(size_type n, Operation op); + constexpr size_type capacity() const noexcept; + constexpr void reserve(size_type res_arg); + constexpr void shrink_to_fit(); + constexpr void clear() noexcept; + [[nodiscard]] constexpr bool empty() const noexcept; -\pnum -\throws -\begin{itemize} -\item \tcode{out_of_range} if \tcode{pos > size()}, -\item \tcode{length_error} if \tcode{n > max_size() - size()}, or -\item any exceptions thrown by \tcode{allocator_traits::allocate}. -\end{itemize} -\end{itemdescr} + // \ref{string.access}, element access + constexpr const_reference operator[](size_type pos) const; + constexpr reference operator[](size_type pos); + constexpr const_reference at(size_type n) const; + constexpr reference at(size_type n); -\indexlibrarymember{insert}{basic_string}% -\begin{itemdecl} -constexpr iterator insert(const_iterator p, charT c); -\end{itemdecl} + constexpr const charT& front() const; + constexpr charT& front(); + constexpr const charT& back() const; + constexpr charT& back(); -\begin{itemdescr} -\pnum -\expects -\tcode{p} is a valid iterator on -\tcode{*this}. + // \ref{string.modifiers}, modifiers + constexpr basic_string& operator+=(const basic_string& str); + template + constexpr basic_string& operator+=(const T& t); + constexpr basic_string& operator+=(const charT* s); + constexpr basic_string& operator+=(charT c); + constexpr basic_string& operator+=(initializer_list); + constexpr basic_string& append(const basic_string& str); + constexpr basic_string& append(const basic_string& str, size_type pos, size_type n = npos); + template + constexpr basic_string& append(const T& t); + template + constexpr basic_string& append(const T& t, size_type pos, size_type n = npos); + constexpr basic_string& append(const charT* s, size_type n); + constexpr basic_string& append(const charT* s); + constexpr basic_string& append(size_type n, charT c); + template + constexpr basic_string& append(InputIterator first, InputIterator last); + template<@\exposconcept{container-compatible-range}@ R> + constexpr basic_string& append_range(R&& rg); + constexpr basic_string& append(initializer_list); -\pnum -\effects -Inserts a copy of \tcode{c} at the position \tcode{p}. + constexpr void push_back(charT c); -\pnum -\returns -An iterator which refers to the inserted character. -\end{itemdescr} + constexpr basic_string& assign(const basic_string& str); + constexpr basic_string& assign(basic_string&& str) + noexcept(allocator_traits::propagate_on_container_move_assignment::value || + allocator_traits::is_always_equal::value); + constexpr basic_string& assign(const basic_string& str, size_type pos, size_type n = npos); + template + constexpr basic_string& assign(const T& t); + template + constexpr basic_string& assign(const T& t, size_type pos, size_type n = npos); + constexpr basic_string& assign(const charT* s, size_type n); + constexpr basic_string& assign(const charT* s); + constexpr basic_string& assign(size_type n, charT c); + template + constexpr basic_string& assign(InputIterator first, InputIterator last); + template<@\exposconcept{container-compatible-range}@ R> + constexpr basic_string& assign_range(R&& rg); + constexpr basic_string& assign(initializer_list); -\indexlibrarymember{insert}{basic_string}% -\begin{itemdecl} -constexpr iterator insert(const_iterator p, size_type n, charT c); -\end{itemdecl} + constexpr basic_string& insert(size_type pos, const basic_string& str); + constexpr basic_string& insert(size_type pos1, const basic_string& str, + size_type pos2, size_type n = npos); + template + constexpr basic_string& insert(size_type pos, const T& t); + template + constexpr basic_string& insert(size_type pos1, const T& t, + size_type pos2, size_type n = npos); + constexpr basic_string& insert(size_type pos, const charT* s, size_type n); + constexpr basic_string& insert(size_type pos, const charT* s); + constexpr basic_string& insert(size_type pos, size_type n, charT c); + constexpr iterator insert(const_iterator p, charT c); + constexpr iterator insert(const_iterator p, size_type n, charT c); + template + constexpr iterator insert(const_iterator p, InputIterator first, InputIterator last); + template<@\exposconcept{container-compatible-range}@ R> + constexpr iterator insert_range(const_iterator p, R&& rg); + constexpr iterator insert(const_iterator p, initializer_list); -\begin{itemdescr} -\pnum -\expects -\tcode{p} is a valid iterator on -\tcode{*this}. + constexpr basic_string& erase(size_type pos = 0, size_type n = npos); + constexpr iterator erase(const_iterator p); + constexpr iterator erase(const_iterator first, const_iterator last); -\pnum -\effects -Inserts \tcode{n} copies of \tcode{c} at the position \tcode{p}. + constexpr void pop_back(); -\pnum -\returns -An iterator which refers to the first inserted character, or -\tcode{p} if \tcode{n == 0}. -\end{itemdescr} + constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str); + constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str, + size_type pos2, size_type n2 = npos); + template + constexpr basic_string& replace(size_type pos1, size_type n1, const T& t); + template + constexpr basic_string& replace(size_type pos1, size_type n1, const T& t, + size_type pos2, size_type n2 = npos); + constexpr basic_string& replace(size_type pos, size_type n1, const charT* s, size_type n2); + constexpr basic_string& replace(size_type pos, size_type n1, const charT* s); + constexpr basic_string& replace(size_type pos, size_type n1, size_type n2, charT c); + constexpr basic_string& replace(const_iterator i1, const_iterator i2, + const basic_string& str); + template + constexpr basic_string& replace(const_iterator i1, const_iterator i2, const T& t); + constexpr basic_string& replace(const_iterator i1, const_iterator i2, const charT* s, + size_type n); + constexpr basic_string& replace(const_iterator i1, const_iterator i2, const charT* s); + constexpr basic_string& replace(const_iterator i1, const_iterator i2, size_type n, charT c); + template + constexpr basic_string& replace(const_iterator i1, const_iterator i2, + InputIterator j1, InputIterator j2); + template<@\exposconcept{container-compatible-range}@ R> + constexpr basic_string& replace_with_range(const_iterator i1, const_iterator i2, R&& rg); + constexpr basic_string& replace(const_iterator, const_iterator, initializer_list); -\indexlibrarymember{insert}{basic_string}% -\begin{itemdecl} -template - constexpr iterator insert(const_iterator p, InputIterator first, InputIterator last); -\end{itemdecl} + constexpr size_type copy(charT* s, size_type n, size_type pos = 0) const; -\begin{itemdescr} -\pnum -\constraints -\tcode{InputIterator} is a type that qualifies as an input -iterator\iref{container.requirements.general}. + constexpr void swap(basic_string& str) + noexcept(allocator_traits::propagate_on_container_swap::value || + allocator_traits::is_always_equal::value); -\pnum -\expects -\tcode{p} is a valid iterator on -\tcode{*this}. + // \ref{string.ops}, string operations + constexpr const charT* c_str() const noexcept; + constexpr const charT* data() const noexcept; + constexpr charT* data() noexcept; + constexpr operator basic_string_view() const noexcept; + constexpr allocator_type get_allocator() const noexcept; -\pnum -\effects -Equivalent to -\tcode{insert(p - begin(), basic_string(first, last, get_allocator()))}. + template + constexpr size_type find(const T& t, size_type pos = 0) const noexcept(@\seebelow@); + constexpr size_type find(const basic_string& str, size_type pos = 0) const noexcept; + constexpr size_type find(const charT* s, size_type pos, size_type n) const; + constexpr size_type find(const charT* s, size_type pos = 0) const; + constexpr size_type find(charT c, size_type pos = 0) const noexcept; + template + constexpr size_type rfind(const T& t, size_type pos = npos) const noexcept(@\seebelow@); + constexpr size_type rfind(const basic_string& str, size_type pos = npos) const noexcept; + constexpr size_type rfind(const charT* s, size_type pos, size_type n) const; + constexpr size_type rfind(const charT* s, size_type pos = npos) const; + constexpr size_type rfind(charT c, size_type pos = npos) const noexcept; -\pnum -\returns -An iterator which refers to the first inserted character, or -\tcode{p} if \tcode{first == last}. -\end{itemdescr} + template + constexpr size_type find_first_of(const T& t, size_type pos = 0) const noexcept(@\seebelow@); + constexpr size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept; + constexpr size_type find_first_of(const charT* s, size_type pos, size_type n) const; + constexpr size_type find_first_of(const charT* s, size_type pos = 0) const; + constexpr size_type find_first_of(charT c, size_type pos = 0) const noexcept; + template + constexpr size_type find_last_of(const T& t, + size_type pos = npos) const noexcept(@\seebelow@); + constexpr size_type find_last_of(const basic_string& str, + size_type pos = npos) const noexcept; + constexpr size_type find_last_of(const charT* s, size_type pos, size_type n) const; + constexpr size_type find_last_of(const charT* s, size_type pos = npos) const; + constexpr size_type find_last_of(charT c, size_type pos = npos) const noexcept; -\indexlibrarymember{insert_range}{basic_string}% -\begin{itemdecl} -template<@\exposconcept{container-compatible-range}@ R> - constexpr iterator insert_range(const_iterator p, R&& rg); -\end{itemdecl} + template + constexpr size_type find_first_not_of(const T& t, + size_type pos = 0) const noexcept(@\seebelow@); + constexpr size_type find_first_not_of(const basic_string& str, + size_type pos = 0) const noexcept; + constexpr size_type find_first_not_of(const charT* s, size_type pos, size_type n) const; + constexpr size_type find_first_not_of(const charT* s, size_type pos = 0) const; + constexpr size_type find_first_not_of(charT c, size_type pos = 0) const noexcept; + template + constexpr size_type find_last_not_of(const T& t, + size_type pos = npos) const noexcept(@\seebelow@); + constexpr size_type find_last_not_of(const basic_string& str, + size_type pos = npos) const noexcept; + constexpr size_type find_last_not_of(const charT* s, size_type pos, size_type n) const; + constexpr size_type find_last_not_of(const charT* s, size_type pos = npos) const; + constexpr size_type find_last_not_of(charT c, size_type pos = npos) const noexcept; -\begin{itemdescr} -\pnum -\expects -\tcode{p} is a valid iterator on \tcode{*this}. + constexpr basic_string substr(size_type pos = 0, size_type n = npos) const; -\pnum -\effects -Equivalent to -\tcode{insert(p - begin(), basic_string(from_range, std::forward(rg), get_allocator()))}. + template + constexpr int compare(const T& t) const noexcept(@\seebelow@); + template + constexpr int compare(size_type pos1, size_type n1, const T& t) const; + template + constexpr int compare(size_type pos1, size_type n1, const T& t, + size_type pos2, size_type n2 = npos) const; + constexpr int compare(const basic_string& str) const noexcept; + constexpr int compare(size_type pos1, size_type n1, const basic_string& str) const; + constexpr int compare(size_type pos1, size_type n1, const basic_string& str, + size_type pos2, size_type n2 = npos) const; + constexpr int compare(const charT* s) const; + constexpr int compare(size_type pos1, size_type n1, const charT* s) const; + constexpr int compare(size_type pos1, size_type n1, const charT* s, size_type n2) const; -\pnum -\returns -An iterator which refers to the first inserted character, or -\tcode{p} if \tcode{rg} is empty. -\end{itemdescr} + constexpr bool starts_with(basic_string_view x) const noexcept; + constexpr bool starts_with(charT x) const noexcept; + constexpr bool starts_with(const charT* x) const; + constexpr bool ends_with(basic_string_view x) const noexcept; + constexpr bool ends_with(charT x) const noexcept; + constexpr bool ends_with(const charT* x) const; -\indexlibrarymember{insert}{basic_string}% -\begin{itemdecl} -constexpr iterator insert(const_iterator p, initializer_list il); -\end{itemdecl} + constexpr bool contains(basic_string_view x) const noexcept; + constexpr bool contains(charT x) const noexcept; + constexpr bool contains(const charT* x) const; + }; -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return insert(p, il.begin(), il.end());} -\end{itemdescr} + template::value_type>> + basic_string(InputIterator, InputIterator, Allocator = Allocator()) + -> basic_string::value_type, + char_traits::value_type>, + Allocator>; -\rSec4[string.erase]{\tcode{basic_string::erase}} + template>> + basic_string(from_range_t, R&&, Allocator = Allocator()) + -> basic_string, char_traits>, + Allocator>; -\indexlibrarymember{erase}{basic_string}% -\begin{itemdecl} -constexpr basic_string& erase(size_type pos = 0, size_type n = npos); -\end{itemdecl} + template> + explicit basic_string(basic_string_view, const Allocator& = Allocator()) + -> basic_string; -\begin{itemdescr} -\pnum -\effects -Determines the effective length \tcode{xlen} -of the string to be removed as the smaller of \tcode{n} and -\tcode{size() - pos}. -Removes the characters in the range \range{begin() + pos}{begin() + pos + xlen}. + template> + basic_string(basic_string_view, + typename @\seebelow@::size_type, typename @\seebelow@::size_type, + const Allocator& = Allocator()) + -> basic_string; +} +\end{codeblock} \pnum -\returns -\tcode{*this}. +A \tcode{size_type} parameter type in +a \tcode{basic_string} deduction guide +refers to the \tcode{size_type} member type of +the type deduced by the deduction guide. \pnum -\throws -\tcode{out_of_range} -if \tcode{pos} -\tcode{> size()}. -\end{itemdescr} - -\indexlibrarymember{erase}{basic_string}% -\begin{itemdecl} -constexpr iterator erase(const_iterator p); -\end{itemdecl} +The types \tcode{iterator} and \tcode{const_iterator} meet +the constexpr iterator requirements\iref{iterator.requirements.general}. -\begin{itemdescr} -\pnum -\expects -\tcode{p} is a valid dereferenceable iterator on \tcode{*this}. +\rSec3[string.require]{General requirements} \pnum -\effects -Removes the character referred to by \tcode{p}. +If any operation would cause \tcode{size()} to +exceed \tcode{max_size()}, that operation throws an +exception object of type \tcode{length_error}. \pnum -\returns -An iterator which points to the element immediately following \tcode{p} prior to -the element being erased. -If no such element exists, -\tcode{end()} -is returned. +If any member function or operator of \tcode{basic_string} throws an exception, that +function or operator has no other effect on the \tcode{basic_string} object. \pnum -\throws -Nothing. -\end{itemdescr} - -\indexlibrarymember{erase}{basic_string}% -\begin{itemdecl} -constexpr iterator erase(const_iterator first, const_iterator last); -\end{itemdecl} +In every specialization \tcode{basic_string}, +the type \tcode{allocator_traits::value_type} shall name the same type +as \tcode{charT}. Every object of type +\tcode{basic_string} uses an object of type +\tcode{Allocator} to allocate and free storage for the contained \tcode{charT} +objects as needed. The \tcode{Allocator} object used is +obtained as described in \ref{container.requirements.general}. +In every specialization \tcode{basic_string}, +the type \tcode{traits} shall meet +the character traits requirements\iref{char.traits}. +\begin{note} +Every specialization \tcode{basic_string} is +an allocator-aware container, +but does not use the allocator's \tcode{construct} and \tcode{destroy} +member functions\iref{container.requirements.general}. +\end{note} +\begin{note} +The program is ill-formed if \tcode{traits::char_type} +is not the same type as \tcode{charT}. +\end{note} -\begin{itemdescr} \pnum -\expects -\tcode{first} and \tcode{last} are valid iterators on -\tcode{*this}. \range{first}{last} is a valid range. +References, pointers, and iterators referring to the elements of a +\tcode{basic_string} sequence may be +invalidated by the following uses of that \tcode{basic_string} object: -\pnum -\effects -Removes the characters in the range -\tcode{[first, last)}. +\begin{itemize} +\item Passing as an argument to any standard library function taking a reference to non-const +\tcode{basic_string} as an argument. +\begin{footnote} +For example, as an argument to non-member +functions \tcode{swap()}\iref{string.special}, +\tcode{operator>{}>()}\iref{string.io}, and \tcode{getline()}\iref{string.io}, or as +an argument to \tcode{basic_string::swap()}. +\end{footnote} -\pnum -\returns -An iterator which points to the element pointed to by \tcode{last} prior to -the other elements being erased. -If no such element exists, -\tcode{end()} -is returned. +\item Calling non-const member functions, except +\tcode{operator[]}, +\tcode{at}, +\tcode{data}, +\tcode{front}, +\tcode{back}, +\tcode{begin}, +\tcode{rbegin}, +\tcode{end}, +and +\tcode{rend}. +\end{itemize} -\pnum -\throws -Nothing. -\end{itemdescr} +\rSec3[string.cons]{Constructors and assignment operators} -\indexlibrarymember{pop_back}{basic_string}% +\indexlibraryctor{basic_string}% \begin{itemdecl} -constexpr void pop_back(); +constexpr explicit basic_string(const Allocator& a) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\tcode{!empty()}. - -\pnum -\effects -Equivalent to \tcode{erase(end() - 1)}. \pnum -\throws -Nothing. +\ensures +\tcode{size()} is equal to \tcode{0}. \end{itemdescr} -\rSec4[string.replace]{\tcode{basic_string::replace}} - -\indexlibrarymember{replace}{basic_string}% +\indexlibraryctor{basic_string}% \begin{itemdecl} -constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str); +constexpr basic_string(const basic_string& str); +constexpr basic_string(basic_string&& str) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return replace(pos1, n1, str.data(), str.size());} +Constructs an object whose +value is that of \tcode{str} prior to this call. + +\pnum +\remarks +In the second form, \tcode{str} is left in a valid but unspecified state. \end{itemdescr} -\indexlibrarymember{replace}{basic_string}% +\indexlibraryctor{basic_string}% \begin{itemdecl} -constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str, - size_type pos2, size_type n2 = npos); +constexpr basic_string(const basic_string& str, size_type pos, + const Allocator& a = Allocator()); +constexpr basic_string(const basic_string& str, size_type pos, size_type n, + const Allocator& a = Allocator()); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: +Let \tcode{n} be \tcode{npos} for the first overload. Equivalent to: \begin{codeblock} -return replace(pos1, n1, basic_string_view(str).substr(pos2, n2)); +basic_string(basic_string_view(str).substr(pos, n), a) \end{codeblock} \end{itemdescr} -\indexlibrarymember{replace}{basic_string}% +\indexlibraryctor{basic_string}% \begin{itemdecl} template - constexpr basic_string& replace(size_type pos1, size_type n1, const T& t); + constexpr basic_string(const T& t, size_type pos, size_type n, const Allocator& a = Allocator()); \end{itemdecl} \begin{itemdescr} \pnum \constraints -\begin{itemize} -\item -\tcode{is_convertible_v>} is -\tcode{true} and -\item -\tcode{is_convertible_v} is -\tcode{false}. -\end{itemize} +\tcode{is_convertible_v>} +is \tcode{true}. \pnum \effects -Equivalent to: +Creates a variable, \tcode{sv}, +as if by \tcode{basic_string_view sv = t;} +and then behaves the same as: \begin{codeblock} -basic_string_view sv = t; -return replace(pos1, n1, sv.data(), sv.size()); +basic_string(sv.substr(pos, n), a); \end{codeblock} \end{itemdescr} -\indexlibrarymember{replace}{basic_string}% +\indexlibraryctor{basic_string}% \begin{itemdecl} template - constexpr basic_string& replace(size_type pos1, size_type n1, const T& t, - size_type pos2, size_type n2 = npos); + constexpr explicit basic_string(const T& t, const Allocator& a = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -2749,187 +2508,257 @@ \pnum \effects -Equivalent to: -\begin{codeblock} -basic_string_view sv = t; -return replace(pos1, n1, sv.substr(pos2, n2)); -\end{codeblock} +Creates a variable, \tcode{sv}, as if by +\tcode{basic_string_view sv = t;} and +then behaves the same as \tcode{basic_string(sv.data(), sv.size(), a)}. \end{itemdescr} -\indexlibrarymember{replace}{basic_string}% +\indexlibraryctor{basic_string}% \begin{itemdecl} -constexpr basic_string& replace(size_type pos1, size_type n1, const charT* s, size_type n2); +constexpr basic_string(const charT* s, size_type n, const Allocator& a = Allocator()); \end{itemdecl} \begin{itemdescr} \pnum \expects -\range{s}{s + n2} is a valid range. +\range{s}{s + n} is a valid range. \pnum \effects -Determines the effective length \tcode{xlen} of the string to be -removed as the smaller of \tcode{n1} and \tcode{size() - pos1}. If -\tcode{size() - xlen >= max_size() - n2} throws \tcode{length_error}. Otherwise, -the function replaces the characters in the range -\range{begin() + pos1}{begin() + pos1 + xlen} -with a copy of the range \range{s}{s + n2}. +Constructs an object whose initial value is the range \range{s}{s + n}. \pnum -\returns -\tcode{*this}. +\ensures +\tcode{size()} is equal to \tcode{n}, and +\tcode{traits::compare(data(), s, n)} is equal to \tcode{0}. +\end{itemdescr} + +\indexlibraryctor{basic_string}% +\begin{itemdecl} +constexpr basic_string(const charT* s, const Allocator& a = Allocator()); +\end{itemdecl} +\begin{itemdescr} \pnum -\throws -\begin{itemize} -\item \tcode{out_of_range} if \tcode{pos1 > size()}, -\item \tcode{length_error} if the length of the resulting string -would exceed \tcode{max_size()}, or -\item any exceptions thrown by \tcode{allocator_traits::allocate}. -\end{itemize} +\constraints +\tcode{Allocator} is a type +that qualifies as an allocator\iref{container.requirements.general}. +\begin{note} +This affects class template argument deduction. +\end{note} + +\pnum +\effects +Equivalent to: \tcode{basic_string(s, traits::length(s), a)}. \end{itemdescr} -\indexlibrarymember{replace}{basic_string}% +\indexlibraryctor{basic_string}% \begin{itemdecl} -constexpr basic_string& replace(size_type pos, size_type n, const charT* s); +constexpr basic_string(size_type n, charT c, const Allocator& a = Allocator()); \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +\tcode{Allocator} is a type +that qualifies as an allocator\iref{container.requirements.general}. +\begin{note} +This affects class template argument deduction. +\end{note} + \pnum \effects -Equivalent to: \tcode{return replace(pos, n, s, traits::length(s));} +Constructs an object whose value consists of \tcode{n} copies of \tcode{c}. \end{itemdescr} -\indexlibrarymember{replace}{basic_string}% +\indexlibraryctor{basic_string}% \begin{itemdecl} -constexpr basic_string& replace(size_type pos1, size_type n1, size_type n2, charT c); +template + constexpr basic_string(InputIterator begin, InputIterator end, const Allocator& a = Allocator()); \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +\tcode{InputIterator} is a type that qualifies as an input +iterator\iref{container.requirements.general}. + \pnum \effects -Determines the effective length \tcode{xlen} of the string to be -removed as the smaller of \tcode{n1} and \tcode{size() - pos1}. If -\tcode{size() - xlen >=} \tcode{max_size() - n2} throws \tcode{length_error}. Otherwise, -the function replaces the characters in the range -\range{begin() + pos1}{begin() + pos1 + xlen} -with \tcode{n2} copies of \tcode{c}. +Constructs a string from the values in the range \range{begin}{end}, +as specified in \ref{sequence.reqmts}. +\end{itemdescr} + +\indexlibraryctor{basic_string}% +\begin{itemdecl} +template<@\exposconcept{container-compatible-range}@ R> + constexpr basic_string(from_range_t, R&& rg, const Allocator& = Allocator()); +\end{itemdecl} +\begin{itemdescr} \pnum -\returns -\tcode{*this}. +\effects +Constructs a string from the values in the range \tcode{rg}, +as specified in \ref{sequence.reqmts}. +\end{itemdescr} + +\indexlibraryctor{basic_string}% +\begin{itemdecl} +constexpr basic_string(initializer_list il, const Allocator& a = Allocator()); +\end{itemdecl} +\begin{itemdescr} \pnum -\throws -\begin{itemize} -\item \tcode{out_of_range} if \tcode{pos1 > size()}, -\item \tcode{length_error} if the length of the resulting string -would exceed\tcode{max_size()}, or -\item any exceptions thrown by \tcode{allocator_traits::allocate.} -\end{itemize} +\effects +Equivalent to \tcode{basic_string(il.begin(), il.end(), a)}. \end{itemdescr} -\indexlibrarymember{replace}{basic_string}% +\indexlibraryctor{basic_string}% \begin{itemdecl} -constexpr basic_string& replace(const_iterator i1, const_iterator i2, const basic_string& str); +constexpr basic_string(const basic_string& str, const Allocator& alloc); +constexpr basic_string(basic_string&& str, const Allocator& alloc); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return replace(i1, i2, basic_string_view(str));} +Constructs an object whose value is +that of \tcode{str} prior to this call. +The stored allocator is constructed from \tcode{alloc}. +In the second form, \tcode{str} is left in a valid but unspecified state. + +\pnum +\throws +The second form throws nothing if \tcode{alloc == str.get_allocator()}. \end{itemdescr} -\indexlibrarymember{replace}{basic_string}% \begin{itemdecl} -template - constexpr basic_string& replace(const_iterator i1, const_iterator i2, const T& t); +template::value_type>> + basic_string(InputIterator, InputIterator, Allocator = Allocator()) + -> basic_string::value_type, + char_traits::value_type>, + Allocator>; \end{itemdecl} \begin{itemdescr} \pnum \constraints -\begin{itemize} -\item -\tcode{is_convertible_v>} is -\tcode{true} and -\item -\tcode{is_convertible_v} is -\tcode{false}. -\end{itemize} +\tcode{InputIterator} is a type that qualifies as an input iterator, +and \tcode{Allocator} is a type that qualifies as an allocator\iref{container.requirements.general}. +\end{itemdescr} -\pnum -\expects -\range{begin()}{i1} and \range{i1}{i2} are valid ranges. +\begin{itemdecl} +template> + explicit basic_string(basic_string_view, const Allocator& = Allocator()) + -> basic_string; + +template> + basic_string(basic_string_view, + typename @\seebelow@::size_type, typename @\seebelow@::size_type, + const Allocator& = Allocator()) + -> basic_string; +\end{itemdecl} +\begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -basic_string_view sv = t; -return replace(i1 - begin(), i2 - i1, sv.data(), sv.size()); -\end{codeblock} +\constraints +\tcode{Allocator} is a type that qualifies as +an allocator\iref{container.requirements.general}. \end{itemdescr} -\indexlibrarymember{replace}{basic_string}% +\indexlibrarymember{operator=}{basic_string}% \begin{itemdecl} -constexpr basic_string& replace(const_iterator i1, const_iterator i2, const charT* s, size_type n); +constexpr basic_string& operator=(const basic_string& str); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return replace(i1, i2, basic_string_view(s, n));} +If \tcode{*this} and \tcode{str} are the same object, has no effect. +Otherwise, replaces the value of \tcode{*this} with a copy of \tcode{str}. + +\pnum +\returns +\tcode{*this}. \end{itemdescr} -\indexlibrarymember{replace}{basic_string}% +\indexlibrarymember{operator=}{basic_string}% \begin{itemdecl} -constexpr basic_string& replace(const_iterator i1, const_iterator i2, const charT* s); +constexpr basic_string& operator=(basic_string&& str) + noexcept(allocator_traits::propagate_on_container_move_assignment::value || + allocator_traits::is_always_equal::value); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return replace(i1, i2, basic_string_view(s));} +Move assigns as a sequence container\iref{container.requirements}, +except that iterators, pointers and references may be invalidated. + +\pnum +\returns +\tcode{*this}. \end{itemdescr} -\indexlibrarymember{replace}{basic_string}% +\indexlibrarymember{operator=}{basic_string}% \begin{itemdecl} -constexpr basic_string& replace(const_iterator i1, const_iterator i2, size_type n, charT c); +template + constexpr basic_string& operator=(const T& t); \end{itemdecl} \begin{itemdescr} \pnum -\expects -\range{begin()}{i1} and \range{i1}{i2} are valid ranges. +\constraints +\begin{itemize} +\item \tcode{is_convertible_v>} +is \tcode{true} and +\item \tcode{is_convertible_v} +is \tcode{false}. +\end{itemize} \pnum \effects -Equivalent to: \tcode{return replace(i1 - begin(), i2 - i1, n, c);} +Equivalent to: +\begin{codeblock} +basic_string_view sv = t; +return assign(sv); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{replace}{basic_string}% +\indexlibrarymember{operator=}{basic_string}% \begin{itemdecl} -template - constexpr basic_string& replace(const_iterator i1, const_iterator i2, - InputIterator j1, InputIterator j2); +constexpr basic_string& operator=(const charT* s); \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{InputIterator} is a type that qualifies as an input -iterator\iref{container.requirements.general}. +\effects +Equivalent to: +\tcode{return *this = basic_string_view(s);} +\end{itemdescr} +\indexlibrarymember{operator=}{basic_string}% +\begin{itemdecl} +constexpr basic_string& operator=(charT c); +\end{itemdecl} + +\begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return replace(i1, i2, basic_string(j1, j2, get_allocator()));} +Equivalent to: +\begin{codeblock} +return *this = basic_string_view(addressof(c), 1); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{replace_with_range}{basic_string}% +\indexlibrarymember{operator=}{basic_string}% \begin{itemdecl} -template<@\exposconcept{container-compatible-range}@ R> - constexpr basic_string& replace_with_range(const_iterator i1, const_iterator i2, R&& rg); +constexpr basic_string& operator=(initializer_list il); \end{itemdecl} \begin{itemdescr} @@ -2937,428 +2766,467 @@ \effects Equivalent to: \begin{codeblock} -return replace(i1, i2, basic_string(from_range, std::forward(rg), get_allocator())); +return *this = basic_string_view(il.begin(), il.size()); \end{codeblock} \end{itemdescr} -\indexlibrarymember{replace}{basic_string}% +\rSec3[string.iterators]{Iterator support} + +\indexlibrarymember{begin}{basic_string}% +\indexlibrarymember{cbegin}{basic_string}% \begin{itemdecl} -constexpr basic_string& replace(const_iterator i1, const_iterator i2, initializer_list il); +constexpr iterator begin() noexcept; +constexpr const_iterator begin() const noexcept; +constexpr const_iterator cbegin() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return replace(i1, i2, il.begin(), il.size());} +\returns +An iterator referring to the first character in the string. \end{itemdescr} -\rSec4[string.copy]{\tcode{basic_string::copy}} - -\indexlibrarymember{copy}{basic_string}% +\indexlibrarymember{end}{basic_string}% +\indexlibrarymember{cend}{basic_string}% \begin{itemdecl} -constexpr size_type copy(charT* s, size_type n, size_type pos = 0) const; +constexpr iterator end() noexcept; +constexpr const_iterator end() const noexcept; +constexpr const_iterator cend() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\tcode{return basic_string_view(*this).copy(s, n, pos);} -\begin{note} -This does not terminate \tcode{s} with a null object. -\end{note} +\returns +An iterator which is the past-the-end value. \end{itemdescr} -\rSec4[string.swap]{\tcode{basic_string::swap}} - -\indexlibrarymember{swap}{basic_string}% +\indexlibrarymember{rbegin}{basic_string}% +\indexlibrarymember{crbegin}{basic_string}% \begin{itemdecl} -constexpr void swap(basic_string& s) - noexcept(allocator_traits::propagate_on_container_swap::value || - allocator_traits::is_always_equal::value); +constexpr reverse_iterator rbegin() noexcept; +constexpr const_reverse_iterator rbegin() const noexcept; +constexpr const_reverse_iterator crbegin() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{allocator_traits::propagate_on_container_swap::value} is \tcode{true} -or -\tcode{get_allocator() == s.get_allocator()}. - -\pnum -\ensures -\tcode{*this} -contains the same sequence of characters that was in \tcode{s}, -\tcode{s} contains the same sequence of characters that was in -\tcode{*this}. +\returns +An iterator which is semantically equivalent to +\tcode{reverse_iterator(end())}. +\end{itemdescr} -\pnum -\throws -Nothing. +\indexlibrarymember{rend}{basic_string}% +\indexlibrarymember{crend}{basic_string}% +\begin{itemdecl} +constexpr reverse_iterator rend() noexcept; +constexpr const_reverse_iterator rend() const noexcept; +constexpr const_reverse_iterator crend() const noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -\complexity -Constant time. +\returns +An iterator which is semantically equivalent to +\tcode{reverse_iterator(begin())}. \end{itemdescr} -\rSec3[string.ops]{String operations} - -\rSec4[string.accessors]{Accessors} +\rSec3[string.capacity]{Capacity} -\indexlibrarymember{c_str}{basic_string}% -\indexlibrarymember{data}{basic_string}% +\indexlibrarymember{size}{basic_string}% +\indexlibrarymember{length}{basic_string}% \begin{itemdecl} -constexpr const charT* c_str() const noexcept; -constexpr const charT* data() const noexcept; +constexpr size_type size() const noexcept; +constexpr size_type length() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -A pointer \tcode{p} such that \tcode{p + i == addressof(operator[](i))} for each -\tcode{i} in \crange{0}{size()}. +A count of the number of char-like objects currently in the string. \pnum \complexity Constant time. - -\pnum -\remarks -The program shall not modify any of the values stored in the character array; otherwise, the behavior is undefined. \end{itemdescr} -\indexlibrarymember{data}{basic_string}% +\indexlibrarymember{max_size}{basic_string}% \begin{itemdecl} -constexpr charT* data() noexcept; +constexpr size_type max_size() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -A pointer \tcode{p} such that \tcode{p + i == addressof(operator[](i))} for each -\tcode{i} in \crange{0}{size()}. +The largest possible number of char-like objects that can be stored in a +\tcode{basic_string}. \pnum \complexity Constant time. - -\pnum -\remarks -The program shall not modify the value stored at \tcode{p + size()} -to any value other than \tcode{charT()}; otherwise, the behavior is undefined. \end{itemdescr} -\indexlibrarymember{operator basic_string_view}{basic_string}% +\indexlibrarymember{resize}{basic_string}% \begin{itemdecl} -constexpr operator basic_string_view() const noexcept; +constexpr void resize(size_type n, charT c); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\tcode{return basic_string_view(data(), size());} +Alters the value of +\tcode{*this} +as follows: +\begin{itemize} +\item +If +\tcode{n <= size()}, +erases the last \tcode{size() - n} elements. +\item +If +\tcode{n > size()}, +appends \tcode{n - size()} copies of \tcode{c}. +\end{itemize} \end{itemdescr} -\indexlibrarymember{get_allocator}{basic_string}% +\indexlibrarymember{resize}{basic_string}% \begin{itemdecl} -constexpr allocator_type get_allocator() const noexcept; +constexpr void resize(size_type n); \end{itemdecl} \begin{itemdescr} \pnum -\returns -A copy of the -\tcode{Allocator} -object used to construct the string or, if that allocator has been replaced, a -copy of the most recent replacement. +\effects +Equivalent to \tcode{resize(n, charT())}. \end{itemdescr} -\rSec4[string.find]{Searching} +\indexlibrarymember{resize_and_overwrite}{basic_string}% +\begin{itemdecl} +template constexpr void resize_and_overwrite(size_type n, Operation op); +\end{itemdecl} +\begin{itemdescr} \pnum -\indexlibrarymember{find}{basic_string}% -\indexlibrarymember{rfind}{basic_string}% -\indexlibrarymember{find_first_of}{basic_string}% -\indexlibrarymember{find_last_of}{basic_string}% -\indexlibrarymember{find_first_not_of}{basic_string}% -\indexlibrarymember{find_last_not_of}{basic_string}% -Let \placeholder{F} be one of -\tcode{find}, \tcode{rfind}, \tcode{find_first_of}, \tcode{find_last_of}, -\tcode{find_first_not_of}, and \tcode{find_last_not_of}. - +Let \begin{itemize} \item -Each member function of the form -\begin{codeblock} -constexpr size_type @\placeholder{F}@(const basic_string& str, size_type pos) const noexcept; -\end{codeblock} -has effects equivalent to: -\tcode{return \placeholder{F}(basic_string_view(str), pos);} - +\tcode{o = size()} before the call to \tcode{resize_and_overwrite}. \item -Each member function of the form -\begin{codeblock} -constexpr size_type @\placeholder{F}@(const charT* s, size_type pos) const; -\end{codeblock} -has effects equivalent to: -\tcode{return \placeholder{F}(basic_string_view(s), pos);} - +\tcode{k} be \tcode{min(o, n)}. \item -Each member function of the form -\begin{codeblock} -constexpr size_type @\placeholder{F}@(const charT* s, size_type pos, size_type n) const; -\end{codeblock} -has effects equivalent to: -\tcode{return \placeholder{F}(basic_string_view(s, n), pos);} +\tcode{p} be a \tcode{charT*}, +such that the range \crange{p}{p + n} is valid and +\tcode{this->compare(0, k, p, k) == 0} is \tcode{true} before the call. +The values in the range \crange{p + k}{p + n} may be indeterminate\iref{basic.indet}. +\item +$OP$ be the expression \tcode{std::move(op)(p, n)}. +\item +\tcode{r} = $OP$. +\end{itemize} +\pnum +\mandates +$OP$ has an integer-like type\iref{iterator.concept.winc}. + +\pnum +\expects +\begin{itemize} \item -Each member function of the form -\begin{codeblock} -constexpr size_type @\placeholder{F}@(charT c, size_type pos) const noexcept; -\end{codeblock} -has effects equivalent to: -\begin{codeblock} -return @\placeholder{F}@(basic_string_view(addressof(c), 1), pos); -\end{codeblock} +$OP$ does not throw an exception or modify \tcode{p} or \tcode{n}. +\item +$\tcode{r} \geq 0$. +\item +$\tcode{r} \leq \tcode{n}$. +\item +After evaluating $OP$ +there are no indeterminate values in the range \range{p}{p + r}. \end{itemize} -\indexlibrarymember{find}{basic_string}% -\indexlibrarymember{rfind}{basic_string}% -\indexlibrarymember{find_first_of}{basic_string}% -\indexlibrarymember{find_last_of}{basic_string}% -\indexlibrarymember{find_first_not_of}{basic_string}% -\indexlibrarymember{find_last_not_of}{basic_string}% +\pnum +\effects +Evaluates $OP$, +replaces the contents of \tcode{*this} with \range{p}{p + r}, and +invalidates all pointers and references to the range \crange{p}{p + n}. + +\pnum +\recommended +Implementations should avoid unnecessary copies and allocations +by, for example, making \tcode{p} a pointer into internal storage and +by restoring \tcode{*(p + r)} to \tcode{charT()} after evaluating $OP$. +\end{itemdescr} + +\indexlibrarymember{capacity}{basic_string}% +\begin{itemdecl} +constexpr size_type capacity() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The size of the allocated storage in the string. + +\pnum +\complexity +Constant time. +\end{itemdescr} + +\indexlibrarymember{reserve}{basic_string}% +\begin{itemdecl} +constexpr void reserve(size_type res_arg); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +A directive that informs a \tcode{basic_string} of a planned change in size, +so that the storage allocation can be managed accordingly. +After +\tcode{reserve()}, +\tcode{capacity()} +is greater or equal to the argument of +\tcode{reserve} +if reallocation happens; and +equal to the previous value of +\tcode{capacity()} +otherwise. +Reallocation happens at this point if and only if +the current capacity is less than the argument of \tcode{reserve()}. + +\pnum +\throws +\tcode{length_error} +if +\tcode{res_arg > max_size()} or any exceptions thrown by +\tcode{allocator_traits} \tcode{::allocate}. +\end{itemdescr} + +\indexlibrarymember{shrink_to_fit}{basic_string}% \begin{itemdecl} -template - constexpr size_type find(const T& t, size_type pos = 0) const noexcept(@\seebelow@); -template - constexpr size_type rfind(const T& t, size_type pos = npos) const noexcept(@\seebelow@); -template - constexpr size_type find_first_of(const T& t, size_type pos = 0) const noexcept(@\seebelow@); -template - constexpr size_type find_last_of(const T& t, size_type pos = npos) const noexcept(@\seebelow@); -template - constexpr size_type find_first_not_of(const T& t, size_type pos = 0) const noexcept(@\seebelow@); -template - constexpr size_type find_last_not_of(const T& t, size_type pos = npos) const noexcept(@\seebelow@); +constexpr void shrink_to_fit(); \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\begin{itemize} -\item -\tcode{is_convertible_v>} is -\tcode{true} and -\item -\tcode{is_convertible_v} is -\tcode{false}. -\end{itemize} +\effects +\tcode{shrink_to_fit} is a non-binding request to reduce +\tcode{capacity()} to \tcode{size()}. +\begin{note} +The request is non-binding to +allow latitude for implementation-specific optimizations. +\end{note} +It does not increase \tcode{capacity()}, but may reduce \tcode{capacity()} +by causing reallocation. \pnum -\effects -Let \placeholder{G} be the name of the function. -Equivalent to: -\begin{codeblock} -basic_string_view s = *this, sv = t; -return s.@\placeholder{G}@(sv, pos); -\end{codeblock} +\complexity +If the size is not equal to the old capacity, +linear in the size of the sequence; +otherwise constant. \pnum \remarks -The exception specification is equivalent to -\tcode{is_nothrow_convertible_v>}. +Reallocation invalidates all the references, pointers, and iterators +referring to the elements in the sequence, as well as the past-the-end iterator. +\begin{note} +If no reallocation happens, they remain valid. +\end{note} \end{itemdescr} -\rSec4[string.substr]{\tcode{basic_string::substr}} - -\indexlibrarymember{substr}{basic_string}% +\indexlibrarymember{clear}{basic_string}% \begin{itemdecl} -constexpr basic_string substr(size_type pos = 0, size_type n = npos) const; +constexpr void clear() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects -Determines the effective length \tcode{rlen} of the string to copy as the smaller of \tcode{n} and -\tcode{size() - pos}. +Equivalent to: \tcode{erase(begin(), end());} +\end{itemdescr} -\pnum -\returns -\tcode{basic_string(data()+pos, rlen)}. +\indexlibrarymember{empty}{basic_string}% +\begin{itemdecl} +[[nodiscard]] constexpr bool empty() const noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -\throws -\tcode{out_of_range} -if -\tcode{pos > size()}. +\effects +Equivalent to: +\tcode{return size() == 0;} \end{itemdescr} -\rSec4[string.compare]{\tcode{basic_string::compare}} +\rSec3[string.access]{Element access} -\indexlibrarymember{compare}{basic_string}% +\indexlibrarymember{operator[]}{basic_string}% \begin{itemdecl} -template - constexpr int compare(const T& t) const noexcept(@\seebelow@); +constexpr const_reference operator[](size_type pos) const; +constexpr reference operator[](size_type pos); \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\begin{itemize} -\item -\tcode{is_convertible_v>} is -\tcode{true} and -\item -\tcode{is_convertible_v} is -\tcode{false}. -\end{itemize} +\expects +\tcode{pos <= size()}. \pnum -\effects -Equivalent to: \tcode{return basic_string_view(*this).compare(t);} +\returns +\tcode{*(begin() + pos)} if \tcode{pos < size()}. Otherwise, +returns a reference to an object of type \tcode{charT} with value +\tcode{charT()}, where modifying the object to any value other than +\tcode{charT()} leads to undefined behavior. \pnum -\remarks -The exception specification is equivalent to -\tcode{is_nothrow_convertible_v>}. +\throws +Nothing. + +\pnum +\complexity +Constant time. \end{itemdescr} -\indexlibrarymember{compare}{basic_string}% +\indexlibrarymember{at}{basic_string}% \begin{itemdecl} -template - constexpr int compare(size_type pos1, size_type n1, const T& t) const; +constexpr const_reference at(size_type pos) const; +constexpr reference at(size_type pos); \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\begin{itemize} -\item -\tcode{is_convertible_v>} is -\tcode{true} and -\item -\tcode{is_convertible_v} is -\tcode{false}. -\end{itemize} +\returns +\tcode{operator[](pos)}. \pnum -\effects -Equivalent to: -\begin{codeblock} -return basic_string_view(*this).substr(pos1, n1).compare(t); -\end{codeblock} +\throws +\tcode{out_of_range} +if +\tcode{pos >= size()}. \end{itemdescr} -\indexlibrarymember{compare}{basic_string}% +\indexlibrarymember{front}{basic_string}% \begin{itemdecl} -template - constexpr int compare(size_type pos1, size_type n1, const T& t, - size_type pos2, size_type n2 = npos) const; +constexpr const charT& front() const; +constexpr charT& front(); \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\begin{itemize} -\item -\tcode{is_convertible_v>} is -\tcode{true} and -\item -\tcode{is_convertible_v} is -\tcode{false}. -\end{itemize} +\expects +\tcode{!empty()}. \pnum \effects -Equivalent to: -\begin{codeblock} -basic_string_view s = *this, sv = t; -return s.substr(pos1, n1).compare(sv.substr(pos2, n2)); -\end{codeblock} +Equivalent to: \tcode{return operator[](0);} \end{itemdescr} -\indexlibrarymember{compare}{basic_string}% +\indexlibrarymember{back}{basic_string}% \begin{itemdecl} -constexpr int compare(const basic_string& str) const noexcept; +constexpr const charT& back() const; +constexpr charT& back(); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{!empty()}. + \pnum \effects -Equivalent to: -\tcode{return compare(basic_string_view(str));} +Equivalent to: \tcode{return operator[](size() - 1);} \end{itemdescr} -\indexlibrarymember{compare}{basic_string}% +\rSec3[string.modifiers]{Modifiers} + +\rSec4[string.op.append]{\tcode{basic_string::operator+=}} + +\indexlibrarymember{operator+=}{basic_string}% \begin{itemdecl} -constexpr int compare(size_type pos1, size_type n1, const basic_string& str) const; +constexpr basic_string& operator+=(const basic_string& str); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\tcode{return compare(pos1, n1, basic_string_view(str));} +Equivalent to: \tcode{return append(str);} + + \end{itemdescr} -\indexlibrarymember{compare}{basic_string}% +\indexlibrarymember{operator+=}{basic_string}% \begin{itemdecl} -constexpr int compare(size_type pos1, size_type n1, const basic_string& str, - size_type pos2, size_type n2 = npos) const; +template + constexpr basic_string& operator+=(const T& t); \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v>} is +\tcode{true} and +\item +\tcode{is_convertible_v} is +\tcode{false}. +\end{itemize} + \pnum \effects Equivalent to: \begin{codeblock} -return compare(pos1, n1, basic_string_view(str), pos2, n2); +basic_string_view sv = t; +return append(sv); \end{codeblock} \end{itemdescr} -\indexlibrarymember{compare}{basic_string}% +\indexlibrarymember{operator+=}{basic_string}% \begin{itemdecl} -constexpr int compare(const charT* s) const; +constexpr basic_string& operator+=(const charT* s); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\tcode{return compare(basic_string_view(s));} +Equivalent to: \tcode{return append(s);} \end{itemdescr} -\indexlibrarymember{compare}{basic_string}% +\indexlibrarymember{operator+=}{basic_string}% \begin{itemdecl} -constexpr int compare(size_type pos, size_type n1, const charT* s) const; +constexpr basic_string& operator+=(charT c); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return compare(pos, n1, basic_string_view(s));} +Equivalent to: \tcode{return append(size_type\{1\}, c);} \end{itemdescr} -\indexlibrarymember{compare}{basic_string}% +\indexlibrarymember{operator+=}{basic_string}% \begin{itemdecl} -constexpr int compare(size_type pos, size_type n1, const charT* s, size_type n2) const; +constexpr basic_string& operator+=(initializer_list il); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return compare(pos, n1, basic_string_view(s, n2));} +Equivalent to: \tcode{return append(il);} \end{itemdescr} -\rSec4[string.starts.with]{\tcode{basic_string::starts_with}} -\indexlibrarymember{starts_with}{basic_string}% +\rSec4[string.append]{\tcode{basic_string::append}} + +\indexlibrarymember{append}{basic_string}% \begin{itemdecl} -constexpr bool starts_with(basic_string_view x) const noexcept; -constexpr bool starts_with(charT x) const noexcept; -constexpr bool starts_with(const charT* x) const; +constexpr basic_string& append(const basic_string& str); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return append(str.data(), str.size());} +\end{itemdescr} + +\indexlibrarymember{append}{basic_string}% +\begin{itemdecl} +constexpr basic_string& append(const basic_string& str, size_type pos, size_type n = npos); \end{itemdecl} \begin{itemdescr} @@ -3366,457 +3234,360 @@ \effects Equivalent to: \begin{codeblock} -return basic_string_view(data(), size()).starts_with(x); +return append(basic_string_view(str).substr(pos, n)); \end{codeblock} \end{itemdescr} -\rSec4[string.ends.with]{\tcode{basic_string::ends_with}} - -\indexlibrarymember{ends_with}{basic_string}% +\indexlibrarymember{append}{basic_string}% \begin{itemdecl} -constexpr bool ends_with(basic_string_view x) const noexcept; -constexpr bool ends_with(charT x) const noexcept; -constexpr bool ends_with(const charT* x) const; +template + constexpr basic_string& append(const T& t); \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v>} is +\tcode{true} and +\item +\tcode{is_convertible_v} is +\tcode{false}. +\end{itemize} + \pnum \effects Equivalent to: \begin{codeblock} -return basic_string_view(data(), size()).ends_with(x); +basic_string_view sv = t; +return append(sv.data(), sv.size()); \end{codeblock} \end{itemdescr} -\rSec4[string.contains]{\tcode{basic_string::contains}} - -\indexlibrarymember{contains}{basic_string}% +\indexlibrarymember{append}{basic_string}% \begin{itemdecl} -constexpr bool contains(basic_string_view x) const noexcept; -constexpr bool contains(charT x) const noexcept; -constexpr bool contains(const charT* x) const; +template + constexpr basic_string& append(const T& t, size_type pos, size_type n = npos); \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v>} is +\tcode{true} and +\item +\tcode{is_convertible_v} is +\tcode{false}. +\end{itemize} + \pnum \effects Equivalent to: \begin{codeblock} -return basic_string_view(data(), size()).contains(x); +basic_string_view sv = t; +return append(sv.substr(pos, n)); \end{codeblock} \end{itemdescr} -\rSec2[string.nonmembers]{Non-member functions} - -\indexlibraryglobal{basic_string} - -\rSec3[string.op.plus]{\tcode{operator+}} - -\indexlibrarymember{operator+}{basic_string}% +\indexlibrarymember{append}{basic_string}% \begin{itemdecl} -template - constexpr basic_string - operator+(const basic_string& lhs, - const basic_string& rhs); -template - constexpr basic_string - operator+(const basic_string& lhs, const charT* rhs); +constexpr basic_string& append(const charT* s, size_type n); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\range{s}{s + n} is a valid range. + \pnum \effects -Equivalent to: -\begin{codeblock} -basic_string r = lhs; -r.append(rhs); -return r; -\end{codeblock} +Appends a copy of the range \range{s}{s + n} to the string. + +\pnum +\returns +\tcode{*this}. \end{itemdescr} -\indexlibrarymember{operator+}{basic_string}% +\indexlibrarymember{append}{basic_string}% \begin{itemdecl} -template - constexpr basic_string - operator+(basic_string&& lhs, - const basic_string& rhs); -template - constexpr basic_string - operator+(basic_string&& lhs, const charT* rhs); +constexpr basic_string& append(const charT* s); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -lhs.append(rhs); -return std::move(lhs); -\end{codeblock} +Equivalent to: \tcode{return append(s, traits::length(s));} \end{itemdescr} -\indexlibrarymember{operator+}{basic_string}% +\indexlibrarymember{append}{basic_string}% \begin{itemdecl} -template - constexpr basic_string - operator+(basic_string&& lhs, - basic_string&& rhs); +constexpr basic_string& append(size_type n, charT c); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -lhs.append(rhs); -return std::move(lhs); -\end{codeblock} -except that both \tcode{lhs} and \tcode{rhs} -are left in valid but unspecified states. -\begin{note} -If \tcode{lhs} and \tcode{rhs} have equal allocators, -the implementation can move from either. -\end{note} +Appends \tcode{n} copies of \tcode{c} to the string. + +\pnum +\returns +\tcode{*this}. \end{itemdescr} -\indexlibrarymember{operator+}{basic_string}% +\indexlibrarymember{append}{basic_string}% \begin{itemdecl} -template - constexpr basic_string - operator+(const basic_string& lhs, - basic_string&& rhs); -template - constexpr basic_string - operator+(const charT* lhs, basic_string&& rhs); +template + constexpr basic_string& append(InputIterator first, InputIterator last); \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +\tcode{InputIterator} is a type that qualifies as an input +iterator\iref{container.requirements.general}. + \pnum \effects -Equivalent to: -\begin{codeblock} -rhs.insert(0, lhs); -return std::move(rhs); -\end{codeblock} +Equivalent to: \tcode{return append(basic_string(first, last, get_allocator()));} \end{itemdescr} -\indexlibrarymember{operator+}{basic_string}% +\indexlibrarymember{append_range}{basic_string}% \begin{itemdecl} -template - constexpr basic_string - operator+(const charT* lhs, const basic_string& rhs); +template<@\exposconcept{container-compatible-range}@ R> + constexpr basic_string& append_range(R&& rg); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -basic_string r = rhs; -r.insert(0, lhs); -return r; -\end{codeblock} +Equivalent to: \tcode{return append(basic_string(from_range, std::forward(rg), get_allocator()));} \end{itemdescr} -\indexlibrarymember{operator+}{basic_string}% +\indexlibrarymember{append}{basic_string}% \begin{itemdecl} -template - constexpr basic_string - operator+(charT lhs, const basic_string& rhs); +constexpr basic_string& append(initializer_list il); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -basic_string r = rhs; -r.insert(r.begin(), lhs); -return r; -\end{codeblock} +Equivalent to: \tcode{return append(il.begin(), il.size());} \end{itemdescr} -\indexlibrarymember{operator+}{basic_string}% +\indexlibrarymember{push_back}{basic_string}% \begin{itemdecl} -template - constexpr basic_string - operator+(charT lhs, basic_string&& rhs); +constexpr void push_back(charT c); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -rhs.insert(rhs.begin(), lhs); -return std::move(rhs); -\end{codeblock} +Equivalent to +\tcode{append(size_type\{1\}, c)}. \end{itemdescr} -\indexlibrarymember{operator+}{basic_string}% +\rSec4[string.assign]{\tcode{basic_string::assign}} + +\indexlibrarymember{assign}{basic_string}% \begin{itemdecl} -template - constexpr basic_string - operator+(const basic_string& lhs, charT rhs); +constexpr basic_string& assign(const basic_string& str); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -basic_string r = lhs; -r.push_back(rhs); -return r; -\end{codeblock} +Equivalent to: \tcode{return *this = str;} \end{itemdescr} -\indexlibrarymember{operator+}{basic_string}% +\indexlibrarymember{assign}{basic_string}% \begin{itemdecl} -template - constexpr basic_string - operator+(basic_string&& lhs, charT rhs); +constexpr basic_string& assign(basic_string&& str) + noexcept(allocator_traits::propagate_on_container_move_assignment::value || + allocator_traits::is_always_equal::value); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -lhs.push_back(rhs); -return std::move(lhs); -\end{codeblock} +Equivalent to: \tcode{return *this = std::move(str);} \end{itemdescr} -\rSec3[string.cmp]{Non-member comparison operator functions} -\begin{itemdecl} -template - constexpr bool - operator==(const basic_string& lhs, - const basic_string& rhs) noexcept; -template - constexpr bool operator==(const basic_string& lhs, - const charT* rhs); -template - constexpr @\seebelow@ operator<=>(const basic_string& lhs, - @\itcorr@ const basic_string& rhs) noexcept; -template - constexpr @\seebelow@ operator<=>(const basic_string& lhs, - @\itcorr@ const charT* rhs); +\indexlibrarymember{assign}{basic_string}% +\begin{itemdecl} +constexpr basic_string& assign(const basic_string& str, size_type pos, size_type n = npos); \end{itemdecl} + \begin{itemdescr} \pnum \effects -Let \tcode{\placeholder{op}} be the operator. Equivalent to: \begin{codeblock} -return basic_string_view(lhs) @\placeholder{op}@ basic_string_view(rhs); +return assign(basic_string_view(str).substr(pos, n)); \end{codeblock} \end{itemdescr} -\rSec3[string.special]{\tcode{swap}} - -\indexlibrarymember{swap}{basic_string}% +\indexlibrarymember{assign}{basic_string}% \begin{itemdecl} -template - constexpr void - swap(basic_string& lhs, - basic_string& rhs) - noexcept(noexcept(lhs.swap(rhs))); +template + constexpr basic_string& assign(const T& t); \end{itemdecl} -\begin{itemdescr} +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v>} is +\tcode{true} and +\item +\tcode{is_convertible_v} is +\tcode{false}. +\end{itemize} + \pnum \effects -Equivalent to \tcode{lhs.swap(rhs)}. +Equivalent to: +\begin{codeblock} +basic_string_view sv = t; +return assign(sv.data(), sv.size()); +\end{codeblock} \end{itemdescr} -\rSec3[string.io]{Inserters and extractors} - -\indexlibrarymember{operator>>}{basic_string}% +\indexlibrarymember{assign}{basic_string}% \begin{itemdecl} -template - basic_istream& - operator>>(basic_istream& is, basic_string& str); +template + constexpr basic_string& assign(const T& t, size_type pos, size_type n = npos); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Behaves as a formatted input function\iref{istream.formatted.reqmts}. -After constructing a \tcode{sentry} object, -if the \tcode{sentry} object returns \tcode{true} -when converted to a value of type \tcode{bool}, -calls \tcode{str.erase()} -and then extracts characters from \tcode{is} and appends them -to \tcode{str} as if by calling -\tcode{str.append(1, c)}. -If -\tcode{is.width()} -is greater than zero, the maximum -number \tcode{n} of characters appended is -\tcode{is.width()}; -otherwise \tcode{n} is -\tcode{str.max_size()}. -Characters are extracted and appended until any of the following -occurs: +\constraints \begin{itemize} \item -\textit{n} -characters are stored; -\item -end-of-file occurs on the input sequence; +\tcode{is_convertible_v>} is +\tcode{true} and \item -\tcode{isspace(c, is.getloc())} -is \tcode{true} for the next available input character -\textit{c}. +\tcode{is_convertible_v} is +\tcode{false}. \end{itemize} \pnum -After the last character (if any) is extracted, -\tcode{is.width(0)} -is called and the -\tcode{sentry} -object is destroyed. +\effects +Equivalent to: +\begin{codeblock} +basic_string_view sv = t; +return assign(sv.substr(pos, n)); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{assign}{basic_string}% +\begin{itemdecl} +constexpr basic_string& assign(const charT* s, size_type n); +\end{itemdecl} +\begin{itemdescr} \pnum -If the function extracts no characters, it calls -\tcode{is.setstate(ios_base::failbit)}, -which may throw -\tcode{ios_base::fail\-ure}\iref{iostate.flags}. +\expects +\range{s}{s + n} is a valid range. + +\pnum +\effects +Replaces the string controlled by \tcode{*this} with +a copy of the range \range{s}{s + n}. \pnum \returns -\tcode{is}. +\tcode{*this}. \end{itemdescr} -\indexlibrarymember{operator<<}{basic_string}% +\indexlibrarymember{assign}{basic_string}% \begin{itemdecl} -template - basic_ostream& - operator<<(basic_ostream& os, - const basic_string& str); +constexpr basic_string& assign(const charT* s); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return os << basic_string_view(str);} +Equivalent to: \tcode{return assign(s, traits::length(s));} \end{itemdescr} -\indexlibrarymember{getline}{basic_string}% +\indexlibrarymember{assign}{basic_string}% \begin{itemdecl} -template - basic_istream& - getline(basic_istream& is, - basic_string& str, - charT delim); -template - basic_istream& - getline(basic_istream&& is, - basic_string& str, - charT delim); +constexpr basic_string& assign(initializer_list il); \end{itemdecl} \begin{itemdescr} \pnum \effects -Behaves as an unformatted input function\iref{istream.unformatted}, -except that it does not affect the value returned by subsequent calls to -\tcode{basic_istream<>::gcount()}. -After constructing a \tcode{sentry} object, -if the \tcode{sentry} object returns \tcode{true} -when converted to a value of type \tcode{bool}, -calls \tcode{str.erase()} -and then extracts characters from \tcode{is} and appends them -to \tcode{str} as if by calling -\tcode{str.append(1, c)} -until any of the following occurs: -\begin{itemize} -\item -end-of-file occurs on the input sequence -(in which case, the -\tcode{getline} -function calls -\tcode{is.setstate(\brk{}ios_base::eofbit)}). -\item -\tcode{traits::eq(c, delim)} -for the next available input character -\textit{c} -(in which case, -\textit{c} -is extracted but not appended)\iref{iostate.flags} -\item -\tcode{str.max_size()} -characters are stored -(in which case, -the function calls -\tcode{is.setstate(ios_base::fail\-bit))}\iref{iostate.flags} -\end{itemize} +Equivalent to: \tcode{return assign(il.begin(), il.size());} +\end{itemdescr} + +\indexlibrarymember{assign}{basic_string}% +\begin{itemdecl} +constexpr basic_string& assign(size_type n, charT c); +\end{itemdecl} +\begin{itemdescr} \pnum -The conditions are tested in the order shown. -In any case, -after the last character is extracted, the -\tcode{sentry} -object is destroyed. +\effects +Equivalent to: +\begin{codeblock} +clear(); +resize(n, c); +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{assign}{basic_string}% +\begin{itemdecl} +template + constexpr basic_string& assign(InputIterator first, InputIterator last); +\end{itemdecl} +\begin{itemdescr} \pnum -If the function extracts no characters, it calls -\tcode{is.setstate(ios_base::fail\-bit)} -which may throw -\tcode{ios_base::fail\-ure}\iref{iostate.flags}. +\constraints +\tcode{InputIterator} is a type that qualifies as an input +iterator\iref{container.requirements.general}. \pnum -\returns -\tcode{is}. +\effects +Equivalent to: \tcode{return assign(basic_string(first, last, get_allocator()));} \end{itemdescr} -\indexlibrarymember{getline}{basic_string}% +\indexlibrarymember{assign_range}{basic_string}% \begin{itemdecl} -template - basic_istream& - getline(basic_istream& is, - basic_string& str); -template - basic_istream& - getline(basic_istream&& is, - basic_string& str); +template<@\exposconcept{container-compatible-range}@ R> + constexpr basic_string& assign_range(R&& rg); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{getline(is, str, is.widen('\textbackslash n'))}. +\effects +Equivalent to: \tcode{return assign(basic_string(from_range, std::forward(rg), get_allocator()));} \end{itemdescr} -\rSec3[string.erasure]{Erasure} +\rSec4[string.insert]{\tcode{basic_string::insert}} -\indexlibrarymember{erase}{basic_string}% +\indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -template - constexpr typename basic_string::size_type - erase(basic_string& c, const U& value); +constexpr basic_string& insert(size_type pos, const basic_string& str); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: -\begin{codeblock} -auto it = remove(c.begin(), c.end(), value); -auto r = distance(it, c.end()); -c.erase(it, c.end()); -return r; -\end{codeblock} +Equivalent to: \tcode{return insert(pos, str.data(), str.size());} \end{itemdescr} -\indexlibrarymember{erase_if}{basic_string}% +\indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -template - constexpr typename basic_string::size_type - erase_if(basic_string& c, Predicate pred); +constexpr basic_string& insert(size_type pos1, const basic_string& str, + size_type pos2, size_type n = npos); \end{itemdecl} \begin{itemdescr} @@ -3824,1107 +3595,1201 @@ \effects Equivalent to: \begin{codeblock} -auto it = remove_if(c.begin(), c.end(), pred); -auto r = distance(it, c.end()); -c.erase(it, c.end()); -return r; +return insert(pos1, basic_string_view(str), pos2, n); \end{codeblock} \end{itemdescr} -\rSec2[string.conversions]{Numeric conversions} - -\indexlibraryglobal{stoi}% -\indexlibraryglobal{stol}% -\indexlibraryglobal{stoul}% -\indexlibraryglobal{stoll}% -\indexlibraryglobal{stoull}% +\indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -int stoi(const string& str, size_t* idx = nullptr, int base = 10); -long stol(const string& str, size_t* idx = nullptr, int base = 10); -unsigned long stoul(const string& str, size_t* idx = nullptr, int base = 10); -long long stoll(const string& str, size_t* idx = nullptr, int base = 10); -unsigned long long stoull(const string& str, size_t* idx = nullptr, int base = 10); +template + constexpr basic_string& insert(size_type pos, const T& t); \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v>} is +\tcode{true} and +\item +\tcode{is_convertible_v} is +\tcode{false}. +\end{itemize} + \pnum \effects -The first two functions call \tcode{strtol(str.c_str(), ptr, base)}, -and the last three functions call \tcode{strtoul(str.c_str(), ptr, base)}, -\tcode{strtoll(str.c_str(), ptr, base)}, and \tcode{strtoull(\brk{}str.c_str(), ptr, -base)}, respectively. Each function returns the converted result, if any. The -argument \tcode{ptr} designates a pointer to an object internal to the function -that is used to determine what to store at \tcode{*idx}. If the function does -not throw an exception and \tcode{idx != nullptr}, the function stores in \tcode{*idx} -the index of the first unconverted element of \tcode{str}. +Equivalent to: +\begin{codeblock} +basic_string_view sv = t; +return insert(pos, sv.data(), sv.size()); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{insert}{basic_string}% +\begin{itemdecl} +template + constexpr basic_string& insert(size_type pos1, const T& t, + size_type pos2, size_type n = npos); +\end{itemdecl} +\begin{itemdescr} \pnum -\returns -The converted result. +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v>} is +\tcode{true} and +\item +\tcode{is_convertible_v} is +\tcode{false}. +\end{itemize} \pnum -\throws -\tcode{invalid_argument} if \tcode{strtol}, \tcode{strtoul}, -\tcode{strtoll}, or \tcode{strtoull} reports that no conversion can be -performed. Throws \tcode{out_of_range} if \tcode{strtol}, \tcode{strtoul}, -\tcode{strtoll} or \tcode{strtoull} sets \tcode{errno} to \tcode{ERANGE}, -or if the converted value is outside the range of representable values -for the return type. +\effects +Equivalent to: +\begin{codeblock} +basic_string_view sv = t; +return insert(pos1, sv.substr(pos2, n)); +\end{codeblock} \end{itemdescr} -\indexlibraryglobal{stof}% -\indexlibraryglobal{stod}% -\indexlibraryglobal{stold}% +\indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -float stof(const string& str, size_t* idx = nullptr); -double stod(const string& str, size_t* idx = nullptr); -long double stold(const string& str, size_t* idx = nullptr); +constexpr basic_string& insert(size_type pos, const charT* s, size_type n); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\range{s}{s + n} is a valid range. + \pnum \effects -These functions call -\tcode{strtof(str.c_str(), ptr)}, \tcode{strtod(str.c_str(), ptr)}, and -\tcode{strtold(\brk{}str.c_str(), ptr)}, respectively. Each function returns -the converted result, if any. The argument \tcode{ptr} designates a pointer to -an object internal to the function that is used to determine what to store at -\tcode{*idx}. If the function does not throw an exception and \tcode{idx != nullptr}, -the function stores in \tcode{*idx} the index of the first unconverted element -of \tcode{str}. +Inserts a copy of the range \range{s}{s + n} +immediately before the character at position \tcode{pos} if \tcode{pos < size()}, +or otherwise at the end of the string. \pnum \returns -The converted result. +\tcode{*this}. \pnum \throws -\tcode{invalid_argument} if \tcode{strtof}, \tcode{strtod}, or -\tcode{strtold} reports that no conversion can be performed. Throws -\tcode{out_of_range} if \tcode{strtof}, \tcode{strtod}, or -\tcode{strtold} sets \tcode{errno} to \tcode{ERANGE} -or if the converted value is outside the range of representable -values for the return type. +\begin{itemize} +\item \tcode{out_of_range} if \tcode{pos > size()}, +\item \tcode{length_error} if \tcode{n > max_size() - size()}, or +\item any exceptions thrown by \tcode{allocator_traits::allocate}. +\end{itemize} \end{itemdescr} -\indexlibraryglobal{to_string}% +\indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -string to_string(int val); -string to_string(unsigned val); -string to_string(long val); -string to_string(unsigned long val); -string to_string(long long val); -string to_string(unsigned long long val); -string to_string(float val); -string to_string(double val); -string to_string(long double val); +constexpr basic_string& insert(size_type pos, const charT* s); \end{itemdecl} \begin{itemdescr} \pnum -\returns -Each function returns a \tcode{string} object holding the character -representation of the value of its argument that would be generated by calling -\tcode{sprintf(buf, fmt, val)} with a format specifier of -\tcode{"\%d"}, -\tcode{"\%u"}, -\tcode{"\%ld"}, -\tcode{"\%lu"}, -\tcode{"\%lld"}, \tcode{"\%llu"}, -\tcode{"\%f"}, -\tcode{"\%f"}, -or \tcode{"\%Lf"}, respectively, where \tcode{buf} designates an internal -character buffer of sufficient size. +\effects +Equivalent to: \tcode{return insert(pos, s, traits::length(s));} \end{itemdescr} -\indexlibraryglobal{stoi}% -\indexlibraryglobal{stol}% -\indexlibraryglobal{stoul}% -\indexlibraryglobal{stoll}% -\indexlibraryglobal{stoull}% +\indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -int stoi(const wstring& str, size_t* idx = nullptr, int base = 10); -long stol(const wstring& str, size_t* idx = nullptr, int base = 10); -unsigned long stoul(const wstring& str, size_t* idx = nullptr, int base = 10); -long long stoll(const wstring& str, size_t* idx = nullptr, int base = 10); -unsigned long long stoull(const wstring& str, size_t* idx = nullptr, int base = 10); +constexpr basic_string& insert(size_type pos, size_type n, charT c); \end{itemdecl} \begin{itemdescr} \pnum \effects -The first two functions call \tcode{wcstol(str.c_str(), ptr, base)}, -and the last three functions call \tcode{wcstoul(str.c_str(), ptr, base)}, -\tcode{wcstoll(str.c_str(), ptr, base)}, and \tcode{wcstoull(\brk{}str.c_str(), ptr, -base)}, respectively. Each function returns the converted result, if any. The -argument \tcode{ptr} designates a pointer to an object internal to the function -that is used to determine what to store at \tcode{*idx}. If the function does -not throw an exception and \tcode{idx != nullptr}, the function stores in \tcode{*idx} -the index of the first unconverted element of \tcode{str}. +Inserts \tcode{n} copies of \tcode{c} before the character at position \tcode{pos} +if \tcode{pos < size()}, +or otherwise at the end of the string. \pnum \returns -The converted result. +\tcode{*this} \pnum \throws -\tcode{invalid_argument} if \tcode{wcstol}, \tcode{wcstoul}, \tcode{wcstoll}, or -\tcode{wcstoull} reports that no conversion can be performed. Throws -\tcode{out_of_range} if the converted value is outside the range of representable values -for the return type. +\begin{itemize} +\item \tcode{out_of_range} if \tcode{pos > size()}, +\item \tcode{length_error} if \tcode{n > max_size() - size()}, or +\item any exceptions thrown by \tcode{allocator_traits::allocate}. +\end{itemize} \end{itemdescr} -\indexlibraryglobal{stof}% -\indexlibraryglobal{stod}% -\indexlibraryglobal{stold}% +\indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -float stof(const wstring& str, size_t* idx = nullptr); -double stod(const wstring& str, size_t* idx = nullptr); -long double stold(const wstring& str, size_t* idx = nullptr); +constexpr iterator insert(const_iterator p, charT c); \end{itemdecl} \begin{itemdescr} \pnum -\effects -These functions call \tcode{wcstof(str.c_str(), ptr)}, -\tcode{wcstod(str.c_str(), ptr)}, and \tcode{wcstold(\brk{}str.c_str(), ptr)}, -respectively. Each function returns the converted -result, if any. The argument \tcode{ptr} designates a pointer to an object internal to -the function that is used to determine what to store at \tcode{*idx}. If the function -does not throw an exception and \tcode{idx != nullptr}, the function stores in \tcode{*idx} -the index of the first unconverted element of \tcode{str}. +\expects +\tcode{p} is a valid iterator on +\tcode{*this}. \pnum -\returns -The converted result. +\effects +Inserts a copy of \tcode{c} at the position \tcode{p}. \pnum -\throws -\tcode{invalid_argument} if \tcode{wcstof}, \tcode{wcstod}, or \tcode{wcstold} reports that no -conversion can be performed. Throws \tcode{out_of_range} if \tcode{wcstof}, \tcode{wcstod}, or -\tcode{wcstold} sets \tcode{errno} to \tcode{ERANGE}. +\returns +An iterator which refers to the inserted character. \end{itemdescr} -\indexlibraryglobal{to_wstring}% +\indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -wstring to_wstring(int val); -wstring to_wstring(unsigned val); -wstring to_wstring(long val); -wstring to_wstring(unsigned long val); -wstring to_wstring(long long val); -wstring to_wstring(unsigned long long val); -wstring to_wstring(float val); -wstring to_wstring(double val); -wstring to_wstring(long double val); +constexpr iterator insert(const_iterator p, size_type n, charT c); \end{itemdecl} \begin{itemdescr} +\pnum +\expects +\tcode{p} is a valid iterator on +\tcode{*this}. + +\pnum +\effects +Inserts \tcode{n} copies of \tcode{c} at the position \tcode{p}. + \pnum \returns -Each function returns a \tcode{wstring} object holding the character -representation of the value of its argument that would be generated by calling -\tcode{swprintf(buf, buffsz, fmt, val)} with a format specifier of -\tcode{L"\%d"}, -\tcode{L"\%u"}, -\tcode{L"\%ld"}, -\tcode{L"\%lu"}, -\tcode{L"\%lld"}, -\tcode{L"\%llu"}, -\tcode{L"\%f"}, -\tcode{L"\%f"}, -or \tcode{L"\%Lf"}, respectively, where \tcode{buf} designates an -internal character buffer of sufficient size \tcode{buffsz}. +An iterator which refers to the first inserted character, or +\tcode{p} if \tcode{n == 0}. \end{itemdescr} -\rSec2[basic.string.hash]{Hash support} - -\indexlibrarymember{hash}{string}% -\indexlibrarymember{hash}{u16string}% -\indexlibrarymember{hash}{u32string}% -\indexlibrarymember{hash}{wstring}% -\indexlibrarymember{hash}{pmr::string}% -\indexlibrarymember{hash}{pmr::u16string}% -\indexlibrarymember{hash}{pmr::u32string}% -\indexlibrarymember{hash}{pmr::wstring}% +\indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -template<> struct hash; -template<> struct hash; -template<> struct hash; -template<> struct hash; -template<> struct hash; -template<> struct hash; -template<> struct hash; -template<> struct hash; -template<> struct hash; -template<> struct hash; +template + constexpr iterator insert(const_iterator p, InputIterator first, InputIterator last); \end{itemdecl} \begin{itemdescr} \pnum -If \tcode{S} is one of these string types, -\tcode{SV} is the corresponding string view type, and -\tcode{s} is an object of type \tcode{S}, -then \tcode{hash()(s) == hash()(SV(s))}. -\end{itemdescr} +\constraints +\tcode{InputIterator} is a type that qualifies as an input +iterator\iref{container.requirements.general}. -\rSec2[basic.string.literals]{Suffix for \tcode{basic_string} literals} +\pnum +\expects +\tcode{p} is a valid iterator on +\tcode{*this}. -\indexlibrarymember{operator""""s}{string}% -\begin{itemdecl} -constexpr string operator""s(const char* str, size_t len); -\end{itemdecl} +\pnum +\effects +Equivalent to +\tcode{insert(p - begin(), basic_string(first, last, get_allocator()))}. -\begin{itemdescr} \pnum \returns -\tcode{string\{str, len\}}. +An iterator which refers to the first inserted character, or +\tcode{p} if \tcode{first == last}. \end{itemdescr} -\indexlibrarymember{operator""""s}{u8string}% +\indexlibrarymember{insert_range}{basic_string}% \begin{itemdecl} -constexpr u8string operator""s(const char8_t* str, size_t len); +template<@\exposconcept{container-compatible-range}@ R> + constexpr iterator insert_range(const_iterator p, R&& rg); \end{itemdecl} + \begin{itemdescr} +\pnum +\expects +\tcode{p} is a valid iterator on \tcode{*this}. + +\pnum +\effects +Equivalent to +\tcode{insert(p - begin(), basic_string(from_range, std::forward(rg), get_allocator()))}. + \pnum \returns -\tcode{u8string\{str, len\}}. +An iterator which refers to the first inserted character, or +\tcode{p} if \tcode{rg} is empty. \end{itemdescr} -\indexlibrarymember{operator""""s}{u16string}% +\indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -constexpr u16string operator""s(const char16_t* str, size_t len); +constexpr iterator insert(const_iterator p, initializer_list il); \end{itemdecl} + \begin{itemdescr} \pnum -\returns -\tcode{u16string\{str, len\}}. +\effects +Equivalent to: \tcode{return insert(p, il.begin(), il.end());} \end{itemdescr} -\indexlibrarymember{operator""""s}{u32string}% +\rSec4[string.erase]{\tcode{basic_string::erase}} + +\indexlibrarymember{erase}{basic_string}% \begin{itemdecl} -constexpr u32string operator""s(const char32_t* str, size_t len); +constexpr basic_string& erase(size_type pos = 0, size_type n = npos); \end{itemdecl} + \begin{itemdescr} +\pnum +\effects +Determines the effective length \tcode{xlen} +of the string to be removed as the smaller of \tcode{n} and +\tcode{size() - pos}. +Removes the characters in the range \range{begin() + pos}{begin() + pos + xlen}. + \pnum \returns -\tcode{u32string\{str, len\}}. +\tcode{*this}. + +\pnum +\throws +\tcode{out_of_range} +if \tcode{pos} +\tcode{> size()}. \end{itemdescr} -\indexlibrarymember{operator""""s}{wstring}% +\indexlibrarymember{erase}{basic_string}% \begin{itemdecl} -constexpr wstring operator""s(const wchar_t* str, size_t len); +constexpr iterator erase(const_iterator p); \end{itemdecl} + \begin{itemdescr} \pnum -\returns -\tcode{wstring\{str, len\}}. -\end{itemdescr} +\expects +\tcode{p} is a valid dereferenceable iterator on \tcode{*this}. \pnum -\begin{note} -The same suffix \tcode{s} is used for \tcode{chrono::duration} literals denoting seconds but there is no conflict, since duration suffixes apply to numbers and string literal suffixes apply to character array literals. -\end{note} - -\rSec1[string.view]{String view classes} - -\rSec2[string.view.general]{General} +\effects +Removes the character referred to by \tcode{p}. \pnum -The class template \tcode{basic_string_view} describes an object that can refer to a constant contiguous sequence of char-like\iref{strings.general} objects with the first element of the sequence at position zero. -In the rest of \ref{string.view}, the type of the char-like objects held in a \tcode{basic_string_view} object is designated by \tcode{charT}. +\returns +An iterator which points to the element immediately following \tcode{p} prior to +the element being erased. +If no such element exists, +\tcode{end()} +is returned. \pnum -\begin{note} -The library provides implicit conversions from \tcode{const charT*} and \tcode{std::basic_string} to \tcode{std::basic_string_view} so that user code can accept just \tcode{std::basic_string_view} as a non-templated parameter wherever a sequence of characters is expected. -User-defined types can define their own implicit conversions to \tcode{std::basic_string_view} in order to interoperate with these functions. -\end{note} - -\rSec2[string.view.synop]{Header \tcode{} synopsis} - -\indexheader{string_view}% -\begin{codeblock} -#include // see \ref{compare.syn} - -namespace std { - // \ref{string.view.template}, class template \tcode{basic_string_view} - template> - class basic_string_view; - - template - inline constexpr bool ranges::enable_view> = true; - template - inline constexpr bool ranges::enable_borrowed_range> = true; - - // \ref{string.view.comparison}, non-member comparison functions - template - constexpr bool operator==(basic_string_view x, - basic_string_view y) noexcept; - template - constexpr @\seebelow@ operator<=>(basic_string_view x, - @\itcorr@ basic_string_view y) noexcept; - - // see \ref{string.view.comparison}, sufficient additional overloads of comparison functions - - // \ref{string.view.io}, inserters and extractors - template - basic_ostream& - operator<<(basic_ostream& os, - basic_string_view str); - - // \tcode{basic_string_view} \grammarterm{typedef-name}s - using string_view = basic_string_view; - using u8string_view = basic_string_view; - using u16string_view = basic_string_view; - using u32string_view = basic_string_view; - using wstring_view = basic_string_view; - - // \ref{string.view.hash}, hash support - template struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; +\throws +Nothing. +\end{itemdescr} - inline namespace literals { - inline namespace string_view_literals { - // \ref{string.view.literals}, suffix for \tcode{basic_string_view} literals - constexpr string_view operator""sv(const char* str, size_t len) noexcept; - constexpr u8string_view operator""sv(const char8_t* str, size_t len) noexcept; - constexpr u16string_view operator""sv(const char16_t* str, size_t len) noexcept; - constexpr u32string_view operator""sv(const char32_t* str, size_t len) noexcept; - constexpr wstring_view operator""sv(const wchar_t* str, size_t len) noexcept; - } - } -} -\end{codeblock} +\indexlibrarymember{erase}{basic_string}% +\begin{itemdecl} +constexpr iterator erase(const_iterator first, const_iterator last); +\end{itemdecl} +\begin{itemdescr} \pnum -The function templates defined in \ref{utility.swap} and \ref{iterator.range} -are available when \tcode{} is included. - -\rSec2[string.view.template]{Class template \tcode{basic_string_view}} - -\rSec3[string.view.template.general]{General} +\expects +\tcode{first} and \tcode{last} are valid iterators on +\tcode{*this}. \range{first}{last} is a valid range. -\indexlibraryglobal{basic_string_view}% -\indexlibrarymember{traits_type}{basic_string_view}% -\indexlibrarymember{value_type}{basic_string_view}% -\indexlibrarymember{pointer}{basic_string_view}% -\indexlibrarymember{const_pointer}{basic_string_view}% -\indexlibrarymember{reference}{basic_string_view}% -\indexlibrarymember{const_reference}{basic_string_view}% -\indexlibrarymember{const_iterator}{basic_string_view}% -\indexlibrarymember{iterator}{basic_string_view}% -\indexlibrarymember{const_reverse_iterator}{basic_string_view}% -\indexlibrarymember{reverse_iterator}{basic_string_view}% -\indexlibrarymember{size_type}{basic_string_view}% -\indexlibrarymember{difference_type}{basic_string_view}% -\begin{codeblock} -namespace std { - template> - class basic_string_view { - public: - // types - using traits_type = traits; - using value_type = charT; - using pointer = value_type*; - using const_pointer = const value_type*; - using reference = value_type&; - using const_reference = const value_type&; - using const_iterator = @\impdefx{type of \tcode{basic_string_view::const_iterator}}@; // see \ref{string.view.iterators} - using iterator = const_iterator;@ -\begin{footnote} -Because \tcode{basic_string_view} refers to a constant sequence, \tcode{iterator} and \tcode{const_iterator} are the same type. -\end{footnote}@ - using const_reverse_iterator = reverse_iterator; - using reverse_iterator = const_reverse_iterator; - using size_type = size_t; - using difference_type = ptrdiff_t; - static constexpr size_type npos = size_type(-1); +\pnum +\effects +Removes the characters in the range +\tcode{[first, last)}. - // \ref{string.view.cons}, construction and assignment - constexpr basic_string_view() noexcept; - constexpr basic_string_view(const basic_string_view&) noexcept = default; - constexpr basic_string_view& operator=(const basic_string_view&) noexcept = default; - constexpr basic_string_view(const charT* str); - basic_string_view(nullptr_t) = delete; - constexpr basic_string_view(const charT* str, size_type len); - template - constexpr basic_string_view(It begin, End end); - template - constexpr basic_string_view(R&& r); +\pnum +\returns +An iterator which points to the element pointed to by \tcode{last} prior to +the other elements being erased. +If no such element exists, +\tcode{end()} +is returned. - // \ref{string.view.iterators}, iterator support - constexpr const_iterator begin() const noexcept; - constexpr const_iterator end() const noexcept; - constexpr const_iterator cbegin() const noexcept; - constexpr const_iterator cend() const noexcept; - constexpr const_reverse_iterator rbegin() const noexcept; - constexpr const_reverse_iterator rend() const noexcept; - constexpr const_reverse_iterator crbegin() const noexcept; - constexpr const_reverse_iterator crend() const noexcept; +\pnum +\throws +Nothing. +\end{itemdescr} - // \ref{string.view.capacity}, capacity - constexpr size_type size() const noexcept; - constexpr size_type length() const noexcept; - constexpr size_type max_size() const noexcept; - [[nodiscard]] constexpr bool empty() const noexcept; +\indexlibrarymember{pop_back}{basic_string}% +\begin{itemdecl} +constexpr void pop_back(); +\end{itemdecl} - // \ref{string.view.access}, element access - constexpr const_reference operator[](size_type pos) const; - constexpr const_reference at(size_type pos) const; - constexpr const_reference front() const; - constexpr const_reference back() const; - constexpr const_pointer data() const noexcept; +\begin{itemdescr} +\pnum +\expects +\tcode{!empty()}. - // \ref{string.view.modifiers}, modifiers - constexpr void remove_prefix(size_type n); - constexpr void remove_suffix(size_type n); - constexpr void swap(basic_string_view& s) noexcept; +\pnum +\effects +Equivalent to \tcode{erase(end() - 1)}. - // \ref{string.view.ops}, string operations - constexpr size_type copy(charT* s, size_type n, size_type pos = 0) const; +\pnum +\throws +Nothing. +\end{itemdescr} - constexpr basic_string_view substr(size_type pos = 0, size_type n = npos) const; +\rSec4[string.replace]{\tcode{basic_string::replace}} - constexpr int compare(basic_string_view s) const noexcept; - constexpr int compare(size_type pos1, size_type n1, basic_string_view s) const; - constexpr int compare(size_type pos1, size_type n1, basic_string_view s, - size_type pos2, size_type n2) const; - constexpr int compare(const charT* s) const; - constexpr int compare(size_type pos1, size_type n1, const charT* s) const; - constexpr int compare(size_type pos1, size_type n1, const charT* s, size_type n2) const; +\indexlibrarymember{replace}{basic_string}% +\begin{itemdecl} +constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str); +\end{itemdecl} - constexpr bool starts_with(basic_string_view x) const noexcept; - constexpr bool starts_with(charT x) const noexcept; - constexpr bool starts_with(const charT* x) const; - constexpr bool ends_with(basic_string_view x) const noexcept; - constexpr bool ends_with(charT x) const noexcept; - constexpr bool ends_with(const charT* x) const; +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return replace(pos1, n1, str.data(), str.size());} +\end{itemdescr} - constexpr bool contains(basic_string_view x) const noexcept; - constexpr bool contains(charT x) const noexcept; - constexpr bool contains(const charT* x) const; +\indexlibrarymember{replace}{basic_string}% +\begin{itemdecl} +constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str, + size_type pos2, size_type n2 = npos); +\end{itemdecl} - // \ref{string.view.find}, searching - constexpr size_type find(basic_string_view s, size_type pos = 0) const noexcept; - constexpr size_type find(charT c, size_type pos = 0) const noexcept; - constexpr size_type find(const charT* s, size_type pos, size_type n) const; - constexpr size_type find(const charT* s, size_type pos = 0) const; - constexpr size_type rfind(basic_string_view s, size_type pos = npos) const noexcept; - constexpr size_type rfind(charT c, size_type pos = npos) const noexcept; - constexpr size_type rfind(const charT* s, size_type pos, size_type n) const; - constexpr size_type rfind(const charT* s, size_type pos = npos) const; +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return replace(pos1, n1, basic_string_view(str).substr(pos2, n2)); +\end{codeblock} +\end{itemdescr} - constexpr size_type find_first_of(basic_string_view s, size_type pos = 0) const noexcept; - constexpr size_type find_first_of(charT c, size_type pos = 0) const noexcept; - constexpr size_type find_first_of(const charT* s, size_type pos, size_type n) const; - constexpr size_type find_first_of(const charT* s, size_type pos = 0) const; - constexpr size_type find_last_of(basic_string_view s, size_type pos = npos) const noexcept; - constexpr size_type find_last_of(charT c, size_type pos = npos) const noexcept; - constexpr size_type find_last_of(const charT* s, size_type pos, size_type n) const; - constexpr size_type find_last_of(const charT* s, size_type pos = npos) const; - constexpr size_type find_first_not_of(basic_string_view s, size_type pos = 0) const noexcept; - constexpr size_type find_first_not_of(charT c, size_type pos = 0) const noexcept; - constexpr size_type find_first_not_of(const charT* s, size_type pos, - size_type n) const; - constexpr size_type find_first_not_of(const charT* s, size_type pos = 0) const; - constexpr size_type find_last_not_of(basic_string_view s, - size_type pos = npos) const noexcept; - constexpr size_type find_last_not_of(charT c, size_type pos = npos) const noexcept; - constexpr size_type find_last_not_of(const charT* s, size_type pos, - size_type n) const; - constexpr size_type find_last_not_of(const charT* s, size_type pos = npos) const; +\indexlibrarymember{replace}{basic_string}% +\begin{itemdecl} +template + constexpr basic_string& replace(size_type pos1, size_type n1, const T& t); +\end{itemdecl} - private: - const_pointer data_; // \expos - size_type size_; // \expos - }; +\begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v>} is +\tcode{true} and +\item +\tcode{is_convertible_v} is +\tcode{false}. +\end{itemize} - // \ref{string.view.deduct}, deduction guides - template - basic_string_view(It, End) -> basic_string_view>; - template - basic_string_view(R&&) -> basic_string_view>; -} +\pnum +\effects +Equivalent to: +\begin{codeblock} +basic_string_view sv = t; +return replace(pos1, n1, sv.data(), sv.size()); \end{codeblock} +\end{itemdescr} +\indexlibrarymember{replace}{basic_string}% +\begin{itemdecl} +template + constexpr basic_string& replace(size_type pos1, size_type n1, const T& t, + size_type pos2, size_type n2 = npos); +\end{itemdecl} + +\begin{itemdescr} \pnum -In every specialization \tcode{basic_string_view}, the type \tcode{traits} shall meet the character traits requirements\iref{char.traits}. -\begin{note} -The program is ill-formed if \tcode{traits::char_type} is not the same type as \tcode{charT}. -\end{note} +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v>} is +\tcode{true} and +\item +\tcode{is_convertible_v} is +\tcode{false}. +\end{itemize} \pnum -For a \tcode{basic_string_view str}, -any operation that invalidates a pointer -in the range \range{str.data()}{\brk{}str.data() + str.size()} -invalidates pointers, iterators, and references -returned from \tcode{str}'s member functions. +\effects +Equivalent to: +\begin{codeblock} +basic_string_view sv = t; +return replace(pos1, n1, sv.substr(pos2, n2)); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{replace}{basic_string}% +\begin{itemdecl} +constexpr basic_string& replace(size_type pos1, size_type n1, const charT* s, size_type n2); +\end{itemdecl} +\begin{itemdescr} \pnum -The complexity of \tcode{basic_string_view} member functions is \bigoh{1} -unless otherwise specified. +\expects +\range{s}{s + n2} is a valid range. \pnum -\tcode{basic_string_view} is -a trivially copyable type\iref{term.trivially.copyable.type}. +\effects +Determines the effective length \tcode{xlen} of the string to be +removed as the smaller of \tcode{n1} and \tcode{size() - pos1}. If +\tcode{size() - xlen >= max_size() - n2} throws \tcode{length_error}. Otherwise, +the function replaces the characters in the range +\range{begin() + pos1}{begin() + pos1 + xlen} +with a copy of the range \range{s}{s + n2}. -\rSec3[string.view.cons]{Construction and assignment} +\pnum +\returns +\tcode{*this}. -\indexlibraryctor{basic_string_view}% +\pnum +\throws +\begin{itemize} +\item \tcode{out_of_range} if \tcode{pos1 > size()}, +\item \tcode{length_error} if the length of the resulting string +would exceed \tcode{max_size()}, or +\item any exceptions thrown by \tcode{allocator_traits::allocate}. +\end{itemize} +\end{itemdescr} + +\indexlibrarymember{replace}{basic_string}% \begin{itemdecl} -constexpr basic_string_view() noexcept; +constexpr basic_string& replace(size_type pos, size_type n, const charT* s); \end{itemdecl} \begin{itemdescr} \pnum -\ensures -\tcode{size_ == 0} and \tcode{data_ == nullptr}. +\effects +Equivalent to: \tcode{return replace(pos, n, s, traits::length(s));} \end{itemdescr} -\indexlibraryctor{basic_string_view}% +\indexlibrarymember{replace}{basic_string}% \begin{itemdecl} -constexpr basic_string_view(const charT* str); +constexpr basic_string& replace(size_type pos1, size_type n1, size_type n2, charT c); \end{itemdecl} \begin{itemdescr} \pnum -\expects -\range{str}{str + traits::length(str)} is a valid range. +\effects +Determines the effective length \tcode{xlen} of the string to be +removed as the smaller of \tcode{n1} and \tcode{size() - pos1}. If +\tcode{size() - xlen >=} \tcode{max_size() - n2} throws \tcode{length_error}. Otherwise, +the function replaces the characters in the range +\range{begin() + pos1}{begin() + pos1 + xlen} +with \tcode{n2} copies of \tcode{c}. \pnum -\effects -Constructs a \tcode{basic_string_view}, initializing \tcode{data_} with \tcode{str} -and initializing \tcode{size_} with \tcode{traits::length(str)}. +\returns +\tcode{*this}. \pnum -\complexity -\bigoh{\tcode{traits::length(str)}}. +\throws +\begin{itemize} +\item \tcode{out_of_range} if \tcode{pos1 > size()}, +\item \tcode{length_error} if the length of the resulting string +would exceed\tcode{max_size()}, or +\item any exceptions thrown by \tcode{allocator_traits::allocate.} +\end{itemize} \end{itemdescr} -\indexlibraryctor{basic_string_view}% +\indexlibrarymember{replace}{basic_string}% \begin{itemdecl} -constexpr basic_string_view(const charT* str, size_type len); +constexpr basic_string& replace(const_iterator i1, const_iterator i2, const basic_string& str); \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\range{str}{str + len} is a valid range. - \pnum \effects -Constructs a \tcode{basic_string_view}, initializing \tcode{data_} with \tcode{str} -and initializing \tcode{size_} with \tcode{len}. +Equivalent to: \tcode{return replace(i1, i2, basic_string_view(str));} \end{itemdescr} -\indexlibraryctor{basic_string_view}% +\indexlibrarymember{replace}{basic_string}% \begin{itemdecl} -template - constexpr basic_string_view(It begin, End end); +template + constexpr basic_string& replace(const_iterator i1, const_iterator i2, const T& t); \end{itemdecl} \begin{itemdescr} \pnum \constraints \begin{itemize} -\item \tcode{It} satisfies \libconcept{contiguous_iterator}. -\item \tcode{End} satisfies \tcode{\libconcept{sized_sentinel_for}}. -\item \tcode{is_same_v, charT>} is \tcode{true}. -\item \tcode{is_convertible_v} is \tcode{false}. +\item +\tcode{is_convertible_v>} is +\tcode{true} and +\item +\tcode{is_convertible_v} is +\tcode{false}. \end{itemize} \pnum \expects -\begin{itemize} -\item \range{begin}{end} is a valid range. -\item \tcode{It} models \libconcept{contiguous_iterator}. -\item \tcode{End} models \tcode{\libconcept{sized_sentinel_for}}. -\end{itemize} +\range{begin()}{i1} and \range{i1}{i2} are valid ranges. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +basic_string_view sv = t; +return replace(i1 - begin(), i2 - i1, sv.data(), sv.size()); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{replace}{basic_string}% +\begin{itemdecl} +constexpr basic_string& replace(const_iterator i1, const_iterator i2, const charT* s, size_type n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return replace(i1, i2, basic_string_view(s, n));} +\end{itemdescr} + +\indexlibrarymember{replace}{basic_string}% +\begin{itemdecl} +constexpr basic_string& replace(const_iterator i1, const_iterator i2, const charT* s); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return replace(i1, i2, basic_string_view(s));} +\end{itemdescr} + +\indexlibrarymember{replace}{basic_string}% +\begin{itemdecl} +constexpr basic_string& replace(const_iterator i1, const_iterator i2, size_type n, charT c); +\end{itemdecl} +\begin{itemdescr} \pnum -\effects -Initializes \tcode{data_} with \tcode{to_address(begin)} and -initializes \tcode{size_} with \tcode{end - begin}. +\expects +\range{begin()}{i1} and \range{i1}{i2} are valid ranges. \pnum -\throws -When and what \tcode{end - begin} throws. +\effects +Equivalent to: \tcode{return replace(i1 - begin(), i2 - i1, n, c);} \end{itemdescr} -\indexlibraryctor{basic_string_view}% +\indexlibrarymember{replace}{basic_string}% \begin{itemdecl} -template - constexpr basic_string_view(R&& r); +template + constexpr basic_string& replace(const_iterator i1, const_iterator i2, + InputIterator j1, InputIterator j2); \end{itemdecl} \begin{itemdescr} -\pnum -Let \tcode{d} be an lvalue of type \tcode{remove_cvref_t}. - \pnum \constraints -\begin{itemize} -\item -\tcode{remove_cvref_t} is not the same type as \tcode{basic_string_view}, -\item -\tcode{R} models -\tcode{ranges::\libconcept{contiguous_range}} and \tcode{ranges::\libconcept{sized_range}}, -\item -\tcode{is_same_v, charT>} is \tcode{true}, -\item -\tcode{is_convertible_v} is \tcode{false}, -\item -\tcode{d.operator ::std::basic_string_view()} -is not a valid expression, and -\item -if the \grammarterm{qualified-id} \tcode{remove_reference_t::traits_type} -is valid and denotes a type, -\tcode{is_same_v::traits_type, traits>} is \tcode{true}. -\end{itemize} +\tcode{InputIterator} is a type that qualifies as an input +iterator\iref{container.requirements.general}. \pnum \effects -Initializes \tcode{data_} with \tcode{ranges::data(r)} and -\tcode{size_} with \tcode{ranges::size(r)}. - -\pnum -\throws -Any exception thrown by \tcode{ranges::data(r)} and \tcode{ranges::size(r)}. +Equivalent to: \tcode{return replace(i1, i2, basic_string(j1, j2, get_allocator()));} \end{itemdescr} -\rSec3[string.view.iterators]{Iterator support} - -\indexlibrarymember{const_iterator}{basic_string_view}% +\indexlibrarymember{replace_with_range}{basic_string}% \begin{itemdecl} -using const_iterator = @\impdefx{type of \tcode{basic_string_view::const_iterator}}@; +template<@\exposconcept{container-compatible-range}@ R> + constexpr basic_string& replace_with_range(const_iterator i1, const_iterator i2, R&& rg); \end{itemdecl} \begin{itemdescr} \pnum -A type that meets the requirements -of a constant -\oldconcept{RandomAccessIterator}\iref{random.access.iterators}, -models \libconcept{contiguous_iterator}\iref{iterator.concept.contiguous}, and -meets the constexpr iterator requirements\iref{iterator.requirements.general}, -whose \tcode{value_type} is the template parameter \tcode{charT}. - -\pnum -All requirements on container iterators\iref{container.requirements} apply to \tcode{basic_string_view::const_iterator} as well. +\effects +Equivalent to: +\begin{codeblock} +return replace(i1, i2, basic_string(from_range, std::forward(rg), get_allocator())); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{begin}{basic_string_view}% -\indexlibrarymember{cbegin}{basic_string_view}% +\indexlibrarymember{replace}{basic_string}% \begin{itemdecl} -constexpr const_iterator begin() const noexcept; -constexpr const_iterator cbegin() const noexcept; +constexpr basic_string& replace(const_iterator i1, const_iterator i2, initializer_list il); \end{itemdecl} \begin{itemdescr} \pnum -\returns -An iterator such that -\begin{itemize} -\item if \tcode{!empty()}, \tcode{addressof(*begin()) == data_}, -\item otherwise, an unspecified value such that \range{begin()}{end()} is a valid range. -\end{itemize} +\effects +Equivalent to: \tcode{return replace(i1, i2, il.begin(), il.size());} \end{itemdescr} -\indexlibrarymember{end}{basic_string_view}% -\indexlibrarymember{cend}{basic_string_view}% +\rSec4[string.copy]{\tcode{basic_string::copy}} + +\indexlibrarymember{copy}{basic_string}% \begin{itemdecl} -constexpr const_iterator end() const noexcept; -constexpr const_iterator cend() const noexcept; +constexpr size_type copy(charT* s, size_type n, size_type pos = 0) const; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{begin() + size()}. +\effects +Equivalent to: +\tcode{return basic_string_view(*this).copy(s, n, pos);} +\begin{note} +This does not terminate \tcode{s} with a null object. +\end{note} \end{itemdescr} -\indexlibrarymember{rbegin}{basic_string_view}% -\indexlibrarymember{crbegin}{basic_string_view}% +\rSec4[string.swap]{\tcode{basic_string::swap}} + +\indexlibrarymember{swap}{basic_string}% \begin{itemdecl} -constexpr const_reverse_iterator rbegin() const noexcept; -constexpr const_reverse_iterator crbegin() const noexcept; +constexpr void swap(basic_string& s) + noexcept(allocator_traits::propagate_on_container_swap::value || + allocator_traits::is_always_equal::value); \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{const_reverse_iterator(end())}. +\expects +\tcode{allocator_traits::propagate_on_container_swap::value} is \tcode{true} +or +\tcode{get_allocator() == s.get_allocator()}. + +\pnum +\ensures +\tcode{*this} +contains the same sequence of characters that was in \tcode{s}, +\tcode{s} contains the same sequence of characters that was in +\tcode{*this}. + +\pnum +\throws +Nothing. + +\pnum +\complexity +Constant time. \end{itemdescr} -\indexlibrarymember{rend}{basic_string_view}% -\indexlibrarymember{crend}{basic_string_view}% +\rSec3[string.ops]{String operations} + +\rSec4[string.accessors]{Accessors} + +\indexlibrarymember{c_str}{basic_string}% +\indexlibrarymember{data}{basic_string}% \begin{itemdecl} -constexpr const_reverse_iterator rend() const noexcept; -constexpr const_reverse_iterator crend() const noexcept; +constexpr const charT* c_str() const noexcept; +constexpr const charT* data() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{const_reverse_iterator(begin())}. -\end{itemdescr} +A pointer \tcode{p} such that \tcode{p + i == addressof(operator[](i))} for each +\tcode{i} in \crange{0}{size()}. -\rSec3[string.view.capacity]{Capacity} +\pnum +\complexity +Constant time. -\indexlibrarymember{size}{basic_string_view}% -\indexlibrarymember{length}{basic_string_view}% +\pnum +\remarks +The program shall not modify any of the values stored in the character array; otherwise, the behavior is undefined. +\end{itemdescr} + +\indexlibrarymember{data}{basic_string}% \begin{itemdecl} -constexpr size_type size() const noexcept; -constexpr size_type length() const noexcept; +constexpr charT* data() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{size_}. -\end{itemdescr} +A pointer \tcode{p} such that \tcode{p + i == addressof(operator[](i))} for each +\tcode{i} in \crange{0}{size()}. + +\pnum +\complexity +Constant time. +\pnum +\remarks +The program shall not modify the value stored at \tcode{p + size()} +to any value other than \tcode{charT()}; otherwise, the behavior is undefined. +\end{itemdescr} -\indexlibrarymember{max_size}{basic_string_view}% +\indexlibrarymember{operator basic_string_view}{basic_string}% \begin{itemdecl} -constexpr size_type max_size() const noexcept; +constexpr operator basic_string_view() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns -The largest possible number of char-like objects that can be referred to by a \tcode{basic_string_view}. +\effects +Equivalent to: +\tcode{return basic_string_view(data(), size());} \end{itemdescr} -\indexlibrarymember{empty}{basic_string_view}% +\indexlibrarymember{get_allocator}{basic_string}% \begin{itemdecl} -[[nodiscard]] constexpr bool empty() const noexcept; +constexpr allocator_type get_allocator() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{size_ == 0}. +A copy of the +\tcode{Allocator} +object used to construct the string or, if that allocator has been replaced, a +copy of the most recent replacement. \end{itemdescr} -\rSec3[string.view.access]{Element access} +\rSec4[string.find]{Searching} -\indexlibrarymember{operator[]}{basic_string_view}% +\pnum +\indexlibrarymember{find}{basic_string}% +\indexlibrarymember{rfind}{basic_string}% +\indexlibrarymember{find_first_of}{basic_string}% +\indexlibrarymember{find_last_of}{basic_string}% +\indexlibrarymember{find_first_not_of}{basic_string}% +\indexlibrarymember{find_last_not_of}{basic_string}% +Let \placeholder{F} be one of +\tcode{find}, \tcode{rfind}, \tcode{find_first_of}, \tcode{find_last_of}, +\tcode{find_first_not_of}, and \tcode{find_last_not_of}. + +\begin{itemize} +\item +Each member function of the form +\begin{codeblock} +constexpr size_type @\placeholder{F}@(const basic_string& str, size_type pos) const noexcept; +\end{codeblock} +has effects equivalent to: +\tcode{return \placeholder{F}(basic_string_view(str), pos);} + +\item +Each member function of the form +\begin{codeblock} +constexpr size_type @\placeholder{F}@(const charT* s, size_type pos) const; +\end{codeblock} +has effects equivalent to: +\tcode{return \placeholder{F}(basic_string_view(s), pos);} + +\item +Each member function of the form +\begin{codeblock} +constexpr size_type @\placeholder{F}@(const charT* s, size_type pos, size_type n) const; +\end{codeblock} +has effects equivalent to: +\tcode{return \placeholder{F}(basic_string_view(s, n), pos);} + +\item +Each member function of the form +\begin{codeblock} +constexpr size_type @\placeholder{F}@(charT c, size_type pos) const noexcept; +\end{codeblock} +has effects equivalent to: +\begin{codeblock} +return @\placeholder{F}@(basic_string_view(addressof(c), 1), pos); +\end{codeblock} +\end{itemize} + +\indexlibrarymember{find}{basic_string}% +\indexlibrarymember{rfind}{basic_string}% +\indexlibrarymember{find_first_of}{basic_string}% +\indexlibrarymember{find_last_of}{basic_string}% +\indexlibrarymember{find_first_not_of}{basic_string}% +\indexlibrarymember{find_last_not_of}{basic_string}% \begin{itemdecl} -constexpr const_reference operator[](size_type pos) const; +template + constexpr size_type find(const T& t, size_type pos = 0) const noexcept(@\seebelow@); +template + constexpr size_type rfind(const T& t, size_type pos = npos) const noexcept(@\seebelow@); +template + constexpr size_type find_first_of(const T& t, size_type pos = 0) const noexcept(@\seebelow@); +template + constexpr size_type find_last_of(const T& t, size_type pos = npos) const noexcept(@\seebelow@); +template + constexpr size_type find_first_not_of(const T& t, size_type pos = 0) const noexcept(@\seebelow@); +template + constexpr size_type find_last_not_of(const T& t, size_type pos = npos) const noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{pos < size()}. - -\pnum -\returns -\tcode{data_[pos]}. +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v>} is +\tcode{true} and +\item +\tcode{is_convertible_v} is +\tcode{false}. +\end{itemize} \pnum -\throws -Nothing. +\effects +Let \placeholder{G} be the name of the function. +Equivalent to: +\begin{codeblock} +basic_string_view s = *this, sv = t; +return s.@\placeholder{G}@(sv, pos); +\end{codeblock} \pnum -\begin{note} -Unlike \tcode{basic_string::operator[]}, -\tcode{basic_string_view::operator[](size())} has undefined behavior instead of returning \tcode{charT()}. -\end{note} +\remarks +The exception specification is equivalent to +\tcode{is_nothrow_convertible_v>}. \end{itemdescr} -\indexlibrarymember{at}{basic_string_view}% +\rSec4[string.substr]{\tcode{basic_string::substr}} + +\indexlibrarymember{substr}{basic_string}% \begin{itemdecl} -constexpr const_reference at(size_type pos) const; +constexpr basic_string substr(size_type pos = 0, size_type n = npos) const; \end{itemdecl} \begin{itemdescr} +\pnum +\effects +Determines the effective length \tcode{rlen} of the string to copy as the smaller of \tcode{n} and +\tcode{size() - pos}. + \pnum \returns -\tcode{data_[pos]}. +\tcode{basic_string(data()+pos, rlen)}. \pnum \throws -\tcode{out_of_range} if \tcode{pos >= size()}. +\tcode{out_of_range} +if +\tcode{pos > size()}. \end{itemdescr} -\indexlibrarymember{front}{basic_string_view}% +\rSec4[string.compare]{\tcode{basic_string::compare}} + +\indexlibrarymember{compare}{basic_string}% \begin{itemdecl} -constexpr const_reference front() const; +template + constexpr int compare(const T& t) const noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{!empty()}. +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v>} is +\tcode{true} and +\item +\tcode{is_convertible_v} is +\tcode{false}. +\end{itemize} \pnum -\returns -\tcode{data_[0]}. +\effects +Equivalent to: \tcode{return basic_string_view(*this).compare(t);} \pnum -\throws -Nothing. +\remarks +The exception specification is equivalent to +\tcode{is_nothrow_convertible_v>}. \end{itemdescr} -\indexlibrarymember{back}{basic_string_view}% +\indexlibrarymember{compare}{basic_string}% \begin{itemdecl} -constexpr const_reference back() const; +template + constexpr int compare(size_type pos1, size_type n1, const T& t) const; \end{itemdecl} \begin{itemdescr} \pnum -\expects -\tcode{!empty()}. - -\pnum -\returns -\tcode{data_[size() - 1]}. +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v>} is +\tcode{true} and +\item +\tcode{is_convertible_v} is +\tcode{false}. +\end{itemize} \pnum -\throws -Nothing. +\effects +Equivalent to: +\begin{codeblock} +return basic_string_view(*this).substr(pos1, n1).compare(t); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{data}{basic_string_view}% +\indexlibrarymember{compare}{basic_string}% \begin{itemdecl} -constexpr const_pointer data() const noexcept; +template + constexpr int compare(size_type pos1, size_type n1, const T& t, + size_type pos2, size_type n2 = npos) const; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{data_}. +\constraints +\begin{itemize} +\item +\tcode{is_convertible_v>} is +\tcode{true} and +\item +\tcode{is_convertible_v} is +\tcode{false}. +\end{itemize} \pnum -\begin{note} -Unlike \tcode{basic_string::data()} and \grammarterm{string-literal}s, -\tcode{data()} can return a pointer to a buffer that is not null-terminated. -Therefore it is typically a mistake to pass \tcode{data()} to a function that takes just a \tcode{const charT*} and expects a null-terminated string. -\end{note} +\effects +Equivalent to: +\begin{codeblock} +basic_string_view s = *this, sv = t; +return s.substr(pos1, n1).compare(sv.substr(pos2, n2)); +\end{codeblock} \end{itemdescr} -\rSec3[string.view.modifiers]{Modifiers} - -\indexlibrarymember{remove_prefix}{basic_string_view}% +\indexlibrarymember{compare}{basic_string}% \begin{itemdecl} -constexpr void remove_prefix(size_type n); +constexpr int compare(const basic_string& str) const noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\tcode{n <= size()}. - \pnum \effects -Equivalent to: \tcode{data_ += n; size_ -= n;} +Equivalent to: +\tcode{return compare(basic_string_view(str));} \end{itemdescr} -\indexlibrarymember{remove_suffix}{basic_string_view}% +\indexlibrarymember{compare}{basic_string}% \begin{itemdecl} -constexpr void remove_suffix(size_type n); +constexpr int compare(size_type pos1, size_type n1, const basic_string& str) const; \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\tcode{n <= size()}. - \pnum \effects -Equivalent to: \tcode{size_ -= n;} +Equivalent to: +\tcode{return compare(pos1, n1, basic_string_view(str));} \end{itemdescr} -\indexlibrarymember{swap}{basic_string_view}% +\indexlibrarymember{compare}{basic_string}% \begin{itemdecl} -constexpr void swap(basic_string_view& s) noexcept; +constexpr int compare(size_type pos1, size_type n1, const basic_string& str, + size_type pos2, size_type n2 = npos) const; \end{itemdecl} \begin{itemdescr} \pnum \effects -Exchanges the values of \tcode{*this} and \tcode{s}. +Equivalent to: +\begin{codeblock} +return compare(pos1, n1, basic_string_view(str), pos2, n2); +\end{codeblock} \end{itemdescr} -\rSec3[string.view.ops]{String operations} - -\indexlibrarymember{copy}{basic_string_view}% +\indexlibrarymember{compare}{basic_string}% \begin{itemdecl} -constexpr size_type copy(charT* s, size_type n, size_type pos = 0) const; +constexpr int compare(const charT* s) const; \end{itemdecl} \begin{itemdescr} -\pnum -Let \tcode{rlen} be the smaller of \tcode{n} and \tcode{size() - pos}. - -\pnum -\expects -\range{s}{s + rlen} is a valid range. - \pnum \effects -Equivalent to \tcode{traits::copy(s, data() + pos, rlen)}. - -\pnum -\returns -\tcode{rlen}. - -\pnum -\throws -\tcode{out_of_range} if \tcode{pos > size()}. - -\pnum -\complexity -\bigoh{\tcode{rlen}}. +Equivalent to: +\tcode{return compare(basic_string_view(s));} \end{itemdescr} -\indexlibrarymember{substr}{basic_string_view}% +\indexlibrarymember{compare}{basic_string}% \begin{itemdecl} -constexpr basic_string_view substr(size_type pos = 0, size_type n = npos) const; +constexpr int compare(size_type pos, size_type n1, const charT* s) const; \end{itemdecl} \begin{itemdescr} -\pnum -Let \tcode{rlen} be the smaller of \tcode{n} and \tcode{size() - pos}. - \pnum \effects -Determines \tcode{rlen}, the effective length of the string to reference. - -\pnum -\returns -\tcode{basic_string_view(data() + pos, rlen)}. - -\pnum -\throws -\tcode{out_of_range} if \tcode{pos > size()}. +Equivalent to: \tcode{return compare(pos, n1, basic_string_view(s));} \end{itemdescr} -\indexlibrarymember{compare}{basic_string_view}% +\indexlibrarymember{compare}{basic_string}% \begin{itemdecl} -constexpr int compare(basic_string_view str) const noexcept; +constexpr int compare(size_type pos, size_type n1, const charT* s, size_type n2) const; \end{itemdecl} \begin{itemdescr} -\pnum -Let \tcode{rlen} be the smaller of \tcode{size()} and \tcode{str.size()}. - \pnum \effects -Determines \tcode{rlen}, the effective length of the strings to compare. -The function then compares the two strings by calling \tcode{traits::compare(data(), str.data(), rlen)}. +Equivalent to: \tcode{return compare(pos, n1, basic_string_view(s, n2));} +\end{itemdescr} -\pnum -\returns -The nonzero result if the result of the comparison is nonzero. -Otherwise, returns a value as indicated in \tref{string.view.compare}. -\begin{libtab2}{\tcode{compare()} results}{string.view.compare}{cc}{Condition}{Return Value} -\tcode{size() < str.size()} & \tcode{< 0}\\ -\tcode{size() == str.size()} & \tcode{ \ 0}\\ -\tcode{size() > str.size()} & \tcode{> 0}\\ -\end{libtab2} +\rSec4[string.starts.with]{\tcode{basic_string::starts_with}} + +\indexlibrarymember{starts_with}{basic_string}% +\begin{itemdecl} +constexpr bool starts_with(basic_string_view x) const noexcept; +constexpr bool starts_with(charT x) const noexcept; +constexpr bool starts_with(const charT* x) const; +\end{itemdecl} +\begin{itemdescr} \pnum -\complexity -\bigoh{\tcode{rlen}}. +\effects +Equivalent to: +\begin{codeblock} +return basic_string_view(data(), size()).starts_with(x); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{compare}{basic_string_view}% +\rSec4[string.ends.with]{\tcode{basic_string::ends_with}} + +\indexlibrarymember{ends_with}{basic_string}% \begin{itemdecl} -constexpr int compare(size_type pos1, size_type n1, basic_string_view str) const; +constexpr bool ends_with(basic_string_view x) const noexcept; +constexpr bool ends_with(charT x) const noexcept; +constexpr bool ends_with(const charT* x) const; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return substr(pos1, n1).compare(str);} +Equivalent to: +\begin{codeblock} +return basic_string_view(data(), size()).ends_with(x); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{compare}{basic_string_view}% +\rSec4[string.contains]{\tcode{basic_string::contains}} + +\indexlibrarymember{contains}{basic_string}% \begin{itemdecl} -constexpr int compare(size_type pos1, size_type n1, basic_string_view str, - size_type pos2, size_type n2) const; +constexpr bool contains(basic_string_view x) const noexcept; +constexpr bool contains(charT x) const noexcept; +constexpr bool contains(const charT* x) const; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return substr(pos1, n1).compare(str.substr(pos2, n2));} +Equivalent to: +\begin{codeblock} +return basic_string_view(data(), size()).contains(x); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{compare}{basic_string_view}% +\rSec2[string.nonmembers]{Non-member functions} + +\indexlibraryglobal{basic_string} + +\rSec3[string.op.plus]{\tcode{operator+}} + +\indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} -constexpr int compare(const charT* s) const; +template + constexpr basic_string + operator+(const basic_string& lhs, + const basic_string& rhs); +template + constexpr basic_string + operator+(const basic_string& lhs, const charT* rhs); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return compare(basic_string_view(s));} +Equivalent to: +\begin{codeblock} +basic_string r = lhs; +r.append(rhs); +return r; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{compare}{basic_string_view}% +\indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} -constexpr int compare(size_type pos1, size_type n1, const charT* s) const; +template + constexpr basic_string + operator+(basic_string&& lhs, + const basic_string& rhs); +template + constexpr basic_string + operator+(basic_string&& lhs, const charT* rhs); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return substr(pos1, n1).compare(basic_string_view(s));} +Equivalent to: +\begin{codeblock} +lhs.append(rhs); +return std::move(lhs); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{compare}{basic_string_view}% +\indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} -constexpr int compare(size_type pos1, size_type n1, const charT* s, size_type n2) const; +template + constexpr basic_string + operator+(basic_string&& lhs, + basic_string&& rhs); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return substr(pos1, n1).compare(basic_string_view(s, n2));} +Equivalent to: +\begin{codeblock} +lhs.append(rhs); +return std::move(lhs); +\end{codeblock} +except that both \tcode{lhs} and \tcode{rhs} +are left in valid but unspecified states. +\begin{note} +If \tcode{lhs} and \tcode{rhs} have equal allocators, +the implementation can move from either. +\end{note} \end{itemdescr} -\indexlibrarymember{starts_with}{basic_string_view}% +\indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} -constexpr bool starts_with(basic_string_view x) const noexcept; +template + constexpr basic_string + operator+(const basic_string& lhs, + basic_string&& rhs); +template + constexpr basic_string + operator+(const charT* lhs, basic_string&& rhs); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return substr(0, x.size()) == x;} +Equivalent to: +\begin{codeblock} +rhs.insert(0, lhs); +return std::move(rhs); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{starts_with}{basic_string_view}% +\indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} -constexpr bool starts_with(charT x) const noexcept; +template + constexpr basic_string + operator+(const charT* lhs, const basic_string& rhs); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return !empty() \&\& traits::eq(front(), x);} +Equivalent to: +\begin{codeblock} +basic_string r = rhs; +r.insert(0, lhs); +return r; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{starts_with}{basic_string_view}% +\indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} -constexpr bool starts_with(const charT* x) const; +template + constexpr basic_string + operator+(charT lhs, const basic_string& rhs); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return starts_with(basic_string_view(x));} +Equivalent to: +\begin{codeblock} +basic_string r = rhs; +r.insert(r.begin(), lhs); +return r; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{ends_with}{basic_string_view}% +\indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} -constexpr bool ends_with(basic_string_view x) const noexcept; +template + constexpr basic_string + operator+(charT lhs, basic_string&& rhs); \end{itemdecl} \begin{itemdescr} @@ -4932,448 +4797,582 @@ \effects Equivalent to: \begin{codeblock} -return size() >= x.size() && compare(size() - x.size(), npos, x) == 0; +rhs.insert(rhs.begin(), lhs); +return std::move(rhs); \end{codeblock} \end{itemdescr} -\indexlibrarymember{ends_with}{basic_string_view}% +\indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} -constexpr bool ends_with(charT x) const noexcept; +template + constexpr basic_string + operator+(const basic_string& lhs, charT rhs); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return !empty() \&\& traits::eq(back(), x);} +Equivalent to: +\begin{codeblock} +basic_string r = lhs; +r.push_back(rhs); +return r; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{ends_with}{basic_string_view}% +\indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} -constexpr bool ends_with(const charT* x) const; +template + constexpr basic_string + operator+(basic_string&& lhs, charT rhs); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return ends_with(basic_string_view(x));} +Equivalent to: +\begin{codeblock} +lhs.push_back(rhs); +return std::move(lhs); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{contains}{basic_string_view}% +\rSec3[string.cmp]{Non-member comparison operator functions} \begin{itemdecl} -constexpr bool contains(basic_string_view x) const noexcept; -constexpr bool contains(charT x) const noexcept; -constexpr bool contains(const charT* x) const; -\end{itemdecl} +template + constexpr bool + operator==(const basic_string& lhs, + const basic_string& rhs) noexcept; +template + constexpr bool operator==(const basic_string& lhs, + const charT* rhs); +template + constexpr @\seebelow@ operator<=>(const basic_string& lhs, + @\itcorr@ const basic_string& rhs) noexcept; +template + constexpr @\seebelow@ operator<=>(const basic_string& lhs, + @\itcorr@ const charT* rhs); +\end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return find(x) != npos;} +Let \tcode{\placeholder{op}} be the operator. +Equivalent to: +\begin{codeblock} +return basic_string_view(lhs) @\placeholder{op}@ basic_string_view(rhs); +\end{codeblock} \end{itemdescr} -\rSec3[string.view.find]{Searching} +\rSec3[string.special]{\tcode{swap}} -\pnum -Member functions in this subclause have complexity \bigoh{\tcode{size() * str.size()}} at worst, -although implementations should do better. +\indexlibrarymember{swap}{basic_string}% +\begin{itemdecl} +template + constexpr void + swap(basic_string& lhs, + basic_string& rhs) + noexcept(noexcept(lhs.swap(rhs))); +\end{itemdecl} +\begin{itemdescr} \pnum -Let \placeholder{F} be one of -\tcode{find}, -\tcode{rfind}, -\tcode{find_first_of}, -\tcode{find_last_of}, -\tcode{find_first_not_of}, -and -\tcode{find_last_not_of}. -\begin{itemize} -\item -Each member function of the form -\begin{codeblock} -constexpr @\placeholder{return-type}@ @\placeholder{F}@(const charT* s, size_type pos) const; -\end{codeblock} -has effects equivalent to: \tcode{return \placeholder{F}(basic_string_view(s), pos);} - -\item -Each member function of the form -\begin{codeblock} -constexpr @\placeholder{return-type}@ @\placeholder{F}@(const charT* s, size_type pos, size_type n) const; -\end{codeblock} -has effects equivalent to: \tcode{return \placeholder{F}(basic_string_view(s, n), pos);} +\effects +Equivalent to \tcode{lhs.swap(rhs)}. +\end{itemdescr} -\item -Each member function of the form -\begin{codeblock} -constexpr @\placeholder{return-type}@ @\placeholder{F}@(charT c, size_type pos) const noexcept; -\end{codeblock} -has effects equivalent to: \tcode{return \placeholder{F}(basic_string_view(addressof(c), 1), pos);} -\end{itemize} +\rSec3[string.io]{Inserters and extractors} -\indexlibrarymember{find}{basic_string_view}% +\indexlibrarymember{operator>>}{basic_string}% \begin{itemdecl} -constexpr size_type find(basic_string_view str, size_type pos = 0) const noexcept; +template + basic_istream& + operator>>(basic_istream& is, basic_string& str); \end{itemdecl} \begin{itemdescr} \pnum -Let \tcode{xpos} be the lowest position, if possible, such that the following conditions hold: +\effects +Behaves as a formatted input function\iref{istream.formatted.reqmts}. +After constructing a \tcode{sentry} object, +if the \tcode{sentry} object returns \tcode{true} +when converted to a value of type \tcode{bool}, +calls \tcode{str.erase()} +and then extracts characters from \tcode{is} and appends them +to \tcode{str} as if by calling +\tcode{str.append(1, c)}. +If +\tcode{is.width()} +is greater than zero, the maximum +number \tcode{n} of characters appended is +\tcode{is.width()}; +otherwise \tcode{n} is +\tcode{str.max_size()}. +Characters are extracted and appended until any of the following +occurs: \begin{itemize} \item -\tcode{pos <= xpos} +\textit{n} +characters are stored; \item -\tcode{xpos + str.size() <= size()} +end-of-file occurs on the input sequence; \item -\tcode{traits::eq(at(xpos + I), str.at(I))} for all elements \tcode{I} of the string referenced by \tcode{str}. +\tcode{isspace(c, is.getloc())} +is \tcode{true} for the next available input character +\textit{c}. \end{itemize} \pnum -\effects -Determines \tcode{xpos}. +After the last character (if any) is extracted, +\tcode{is.width(0)} +is called and the +\tcode{sentry} +object is destroyed. + +\pnum +If the function extracts no characters, it calls +\tcode{is.setstate(ios_base::failbit)}, +which may throw +\tcode{ios_base::fail\-ure}\iref{iostate.flags}. \pnum \returns -\tcode{xpos} if the function can determine such a value for \tcode{xpos}. -Otherwise, returns \tcode{npos}. +\tcode{is}. \end{itemdescr} -\indexlibrarymember{rfind}{basic_string_view}% +\indexlibrarymember{operator<<}{basic_string}% \begin{itemdecl} -constexpr size_type rfind(basic_string_view str, size_type pos = npos) const noexcept; +template + basic_ostream& + operator<<(basic_ostream& os, + const basic_string& str); \end{itemdecl} \begin{itemdescr} -\pnum -Let \tcode{xpos} be the highest position, if possible, such that the following conditions hold: -\begin{itemize} -\item -\tcode{xpos <= pos} -\item -\tcode{xpos + str.size() <= size()} -\item -\tcode{traits::eq(at(xpos + I), str.at(I))} for all elements \tcode{I} of the string referenced by \tcode{str}. -\end{itemize} - \pnum \effects -Determines \tcode{xpos}. - -\pnum -\returns -\tcode{xpos} if the function can determine such a value for \tcode{xpos}. -Otherwise, returns \tcode{npos}. +Equivalent to: \tcode{return os << basic_string_view(str);} \end{itemdescr} -\indexlibrarymember{find_first_of}{basic_string_view}% +\indexlibrarymember{getline}{basic_string}% \begin{itemdecl} -constexpr size_type find_first_of(basic_string_view str, size_type pos = 0) const noexcept; +template + basic_istream& + getline(basic_istream& is, + basic_string& str, + charT delim); +template + basic_istream& + getline(basic_istream&& is, + basic_string& str, + charT delim); \end{itemdecl} \begin{itemdescr} \pnum -Let \tcode{xpos} be the lowest position, if possible, such that the following conditions hold: +\effects +Behaves as an unformatted input function\iref{istream.unformatted}, +except that it does not affect the value returned by subsequent calls to +\tcode{basic_istream<>::gcount()}. +After constructing a \tcode{sentry} object, +if the \tcode{sentry} object returns \tcode{true} +when converted to a value of type \tcode{bool}, +calls \tcode{str.erase()} +and then extracts characters from \tcode{is} and appends them +to \tcode{str} as if by calling +\tcode{str.append(1, c)} +until any of the following occurs: \begin{itemize} \item -\tcode{pos <= xpos} +end-of-file occurs on the input sequence +(in which case, the +\tcode{getline} +function calls +\tcode{is.setstate(\brk{}ios_base::eofbit)}). \item -\tcode{xpos < size()} +\tcode{traits::eq(c, delim)} +for the next available input character +\textit{c} +(in which case, +\textit{c} +is extracted but not appended)\iref{iostate.flags} \item -\tcode{traits::eq(at(xpos), str.at(I))} for some element \tcode{I} of the string referenced by \tcode{str}. +\tcode{str.max_size()} +characters are stored +(in which case, +the function calls +\tcode{is.setstate(ios_base::fail\-bit))}\iref{iostate.flags} \end{itemize} \pnum -\effects -Determines \tcode{xpos}. +The conditions are tested in the order shown. +In any case, +after the last character is extracted, the +\tcode{sentry} +object is destroyed. + +\pnum +If the function extracts no characters, it calls +\tcode{is.setstate(ios_base::fail\-bit)} +which may throw +\tcode{ios_base::fail\-ure}\iref{iostate.flags}. \pnum \returns -\tcode{xpos} if the function can determine such a value for \tcode{xpos}. -Otherwise, returns \tcode{npos}. +\tcode{is}. \end{itemdescr} -\indexlibrarymember{find_last_of}{basic_string_view}% +\indexlibrarymember{getline}{basic_string}% \begin{itemdecl} -constexpr size_type find_last_of(basic_string_view str, size_type pos = npos) const noexcept; +template + basic_istream& + getline(basic_istream& is, + basic_string& str); +template + basic_istream& + getline(basic_istream&& is, + basic_string& str); \end{itemdecl} \begin{itemdescr} \pnum -Let \tcode{xpos} be the highest position, if possible, such that the following conditions hold: -\begin{itemize} -\item -\tcode{xpos <= pos} -\item -\tcode{xpos < size()} -\item -\tcode{traits::eq(at(xpos), str.at(I))} for some element \tcode{I} of the string referenced by \tcode{str}. -\end{itemize} +\returns +\tcode{getline(is, str, is.widen('\textbackslash n'))}. +\end{itemdescr} -\pnum -\effects -Determines \tcode{xpos}. +\rSec3[string.erasure]{Erasure} +\indexlibrarymember{erase}{basic_string}% +\begin{itemdecl} +template + constexpr typename basic_string::size_type + erase(basic_string& c, const U& value); +\end{itemdecl} + +\begin{itemdescr} \pnum -\returns -\tcode{xpos} if the function can determine such a value for \tcode{xpos}. -Otherwise, returns \tcode{npos}. +\effects +Equivalent to: +\begin{codeblock} +auto it = remove(c.begin(), c.end(), value); +auto r = distance(it, c.end()); +c.erase(it, c.end()); +return r; +\end{codeblock} \end{itemdescr} -\indexlibrarymember{find_first_not_of}{basic_string_view}% +\indexlibrarymember{erase_if}{basic_string}% \begin{itemdecl} -constexpr size_type find_first_not_of(basic_string_view str, size_type pos = 0) const noexcept; +template + constexpr typename basic_string::size_type + erase_if(basic_string& c, Predicate pred); \end{itemdecl} \begin{itemdescr} \pnum -Let \tcode{xpos} be the lowest position, if possible, such that the following conditions hold: -\begin{itemize} -\item -\tcode{pos <= xpos} -\item -\tcode{xpos < size()} -\item -\tcode{traits::eq(at(xpos), str.at(I))} for no element \tcode{I} of the string referenced by \tcode{str}. -\end{itemize} +\effects +Equivalent to: +\begin{codeblock} +auto it = remove_if(c.begin(), c.end(), pred); +auto r = distance(it, c.end()); +c.erase(it, c.end()); +return r; +\end{codeblock} +\end{itemdescr} + +\rSec2[string.conversions]{Numeric conversions} + +\indexlibraryglobal{stoi}% +\indexlibraryglobal{stol}% +\indexlibraryglobal{stoul}% +\indexlibraryglobal{stoll}% +\indexlibraryglobal{stoull}% +\begin{itemdecl} +int stoi(const string& str, size_t* idx = nullptr, int base = 10); +long stol(const string& str, size_t* idx = nullptr, int base = 10); +unsigned long stoul(const string& str, size_t* idx = nullptr, int base = 10); +long long stoll(const string& str, size_t* idx = nullptr, int base = 10); +unsigned long long stoull(const string& str, size_t* idx = nullptr, int base = 10); +\end{itemdecl} +\begin{itemdescr} \pnum \effects -Determines \tcode{xpos}. +The first two functions call \tcode{strtol(str.c_str(), ptr, base)}, +and the last three functions call \tcode{strtoul(str.c_str(), ptr, base)}, +\tcode{strtoll(str.c_str(), ptr, base)}, and \tcode{strtoull(\brk{}str.c_str(), ptr, +base)}, respectively. Each function returns the converted result, if any. The +argument \tcode{ptr} designates a pointer to an object internal to the function +that is used to determine what to store at \tcode{*idx}. If the function does +not throw an exception and \tcode{idx != nullptr}, the function stores in \tcode{*idx} +the index of the first unconverted element of \tcode{str}. \pnum \returns -\tcode{xpos} if the function can determine such a value for \tcode{xpos}. Otherwise, returns \tcode{npos}. +The converted result. + +\pnum +\throws +\tcode{invalid_argument} if \tcode{strtol}, \tcode{strtoul}, +\tcode{strtoll}, or \tcode{strtoull} reports that no conversion can be +performed. Throws \tcode{out_of_range} if \tcode{strtol}, \tcode{strtoul}, +\tcode{strtoll} or \tcode{strtoull} sets \tcode{errno} to \tcode{ERANGE}, +or if the converted value is outside the range of representable values +for the return type. \end{itemdescr} -\indexlibrarymember{find_last_not_of}{basic_string_view}% +\indexlibraryglobal{stof}% +\indexlibraryglobal{stod}% +\indexlibraryglobal{stold}% \begin{itemdecl} -constexpr size_type find_last_not_of(basic_string_view str, size_type pos = npos) const noexcept; +float stof(const string& str, size_t* idx = nullptr); +double stod(const string& str, size_t* idx = nullptr); +long double stold(const string& str, size_t* idx = nullptr); \end{itemdecl} \begin{itemdescr} -\pnum -Let \tcode{xpos} be the highest position, if possible, such that the following conditions hold: -\begin{itemize} -\item -\tcode{xpos <= pos} -\item -\tcode{xpos < size()} -\item -\tcode{traits::eq(at(xpos), str.at(I))} for no element \tcode{I} of the string referenced by \tcode{str}. -\end{itemize} - \pnum \effects -Determines \tcode{xpos}. +These functions call +\tcode{strtof(str.c_str(), ptr)}, \tcode{strtod(str.c_str(), ptr)}, and +\tcode{strtold(\brk{}str.c_str(), ptr)}, respectively. Each function returns +the converted result, if any. The argument \tcode{ptr} designates a pointer to +an object internal to the function that is used to determine what to store at +\tcode{*idx}. If the function does not throw an exception and \tcode{idx != nullptr}, +the function stores in \tcode{*idx} the index of the first unconverted element +of \tcode{str}. \pnum \returns -\tcode{xpos} if the function can determine such a value for \tcode{xpos}. -Otherwise, returns \tcode{npos}. -\end{itemdescr} +The converted result. -\rSec2[string.view.deduct]{Deduction guides} +\pnum +\throws +\tcode{invalid_argument} if \tcode{strtof}, \tcode{strtod}, or +\tcode{strtold} reports that no conversion can be performed. Throws +\tcode{out_of_range} if \tcode{strtof}, \tcode{strtod}, or +\tcode{strtold} sets \tcode{errno} to \tcode{ERANGE} +or if the converted value is outside the range of representable +values for the return type. +\end{itemdescr} +\indexlibraryglobal{to_string}% \begin{itemdecl} -template - basic_string_view(It, End) -> basic_string_view>; +string to_string(int val); +string to_string(unsigned val); +string to_string(long val); +string to_string(unsigned long val); +string to_string(long long val); +string to_string(unsigned long long val); +string to_string(float val); +string to_string(double val); +string to_string(long double val); \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\begin{itemize} -\item \tcode{It} satisfies \libconcept{contiguous_iterator}. -\item \tcode{End} satisfies \tcode{\libconcept{sized_sentinel_for}}. -\end{itemize} +\returns +Each function returns a \tcode{string} object holding the character +representation of the value of its argument that would be generated by calling +\tcode{sprintf(buf, fmt, val)} with a format specifier of +\tcode{"\%d"}, +\tcode{"\%u"}, +\tcode{"\%ld"}, +\tcode{"\%lu"}, +\tcode{"\%lld"}, \tcode{"\%llu"}, +\tcode{"\%f"}, +\tcode{"\%f"}, +or \tcode{"\%Lf"}, respectively, where \tcode{buf} designates an internal +character buffer of sufficient size. \end{itemdescr} +\indexlibraryglobal{stoi}% +\indexlibraryglobal{stol}% +\indexlibraryglobal{stoul}% +\indexlibraryglobal{stoll}% +\indexlibraryglobal{stoull}% \begin{itemdecl} -template - basic_string_view(R&&) -> basic_string_view>; +int stoi(const wstring& str, size_t* idx = nullptr, int base = 10); +long stol(const wstring& str, size_t* idx = nullptr, int base = 10); +unsigned long stoul(const wstring& str, size_t* idx = nullptr, int base = 10); +long long stoll(const wstring& str, size_t* idx = nullptr, int base = 10); +unsigned long long stoull(const wstring& str, size_t* idx = nullptr, int base = 10); \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{R} satisfies \tcode{ranges::\libconcept{contiguous_range}}. -\end{itemdescr} - -\rSec2[string.view.comparison]{Non-member comparison functions} +\effects +The first two functions call \tcode{wcstol(str.c_str(), ptr, base)}, +and the last three functions call \tcode{wcstoul(str.c_str(), ptr, base)}, +\tcode{wcstoll(str.c_str(), ptr, base)}, and \tcode{wcstoull(\brk{}str.c_str(), ptr, +base)}, respectively. Each function returns the converted result, if any. The +argument \tcode{ptr} designates a pointer to an object internal to the function +that is used to determine what to store at \tcode{*idx}. If the function does +not throw an exception and \tcode{idx != nullptr}, the function stores in \tcode{*idx} +the index of the first unconverted element of \tcode{str}. \pnum -Let \tcode{S} be \tcode{basic_string_view}, and \tcode{sv} be an instance of \tcode{S}. -Implementations shall provide sufficient additional overloads marked \keyword{constexpr} and \keyword{noexcept} -so that an object \tcode{t} with an implicit conversion to \tcode{S} can be compared according to \tref{string.view.comparison.overloads}. -\begin{libtab2}{Additional \tcode{basic_string_view} comparison overloads}{string.view.comparison.overloads}{cc}{Expression}{Equivalent to} -\tcode{t == sv} & \tcode{S(t) == sv} \\ -\tcode{sv == t} & \tcode{sv == S(t)} \\ -\tcode{t != sv} & \tcode{S(t) != sv} \\ -\tcode{sv != t} & \tcode{sv != S(t)} \\ -\tcode{t < sv} & \tcode{S(t) < sv} \\ -\tcode{sv < t} & \tcode{sv < S(t)} \\ -\tcode{t > sv} & \tcode{S(t) > sv} \\ -\tcode{sv > t} & \tcode{sv > S(t)} \\ -\tcode{t <= sv} & \tcode{S(t) <= sv} \\ -\tcode{sv <= t} & \tcode{sv <= S(t)} \\ -\tcode{t >= sv} & \tcode{S(t) >= sv} \\ -\tcode{sv >= t} & \tcode{sv >= S(t)} \\ -\tcode{t <=> sv} & \tcode{S(t) <=> sv} \\ -\tcode{sv <=> t} & \tcode{sv <=> S(t)} \\ -\end{libtab2} -\begin{example} -A sample conforming implementation for \tcode{operator==} would be: -\begin{codeblock} -template - constexpr bool operator==(basic_string_view lhs, - basic_string_view rhs) noexcept { - return lhs.compare(rhs) == 0; - } -template - constexpr bool operator==(basic_string_view lhs, - type_identity_t> rhs) noexcept { - return lhs.compare(rhs) == 0; - } -\end{codeblock} -\end{example} - -\indexlibrarymember{operator==}{basic_string_view}% -\begin{itemdecl} -template - constexpr bool operator==(basic_string_view lhs, - basic_string_view rhs) noexcept; -\end{itemdecl} +\returns +The converted result. -\begin{itemdescr} \pnum -\returns -\tcode{lhs.compare(rhs) == 0}. +\throws +\tcode{invalid_argument} if \tcode{wcstol}, \tcode{wcstoul}, \tcode{wcstoll}, or +\tcode{wcstoull} reports that no conversion can be performed. Throws +\tcode{out_of_range} if the converted value is outside the range of representable values +for the return type. \end{itemdescr} -\indexlibrarymember{operator<=>}{basic_string_view}% +\indexlibraryglobal{stof}% +\indexlibraryglobal{stod}% +\indexlibraryglobal{stold}% \begin{itemdecl} -template - constexpr @\seebelow@ operator<=>(basic_string_view lhs, - @\itcorr@ basic_string_view rhs) noexcept; +float stof(const wstring& str, size_t* idx = nullptr); +double stod(const wstring& str, size_t* idx = nullptr); +long double stold(const wstring& str, size_t* idx = nullptr); \end{itemdecl} \begin{itemdescr} \pnum -Let \tcode{R} denote the type \tcode{traits::comparison_category} if -that \grammarterm{qualified-id} is valid and denotes a type\iref{temp.deduct}, -otherwise \tcode{R} is \tcode{weak_ordering}. +\effects +These functions call \tcode{wcstof(str.c_str(), ptr)}, +\tcode{wcstod(str.c_str(), ptr)}, and \tcode{wcstold(\brk{}str.c_str(), ptr)}, +respectively. Each function returns the converted +result, if any. The argument \tcode{ptr} designates a pointer to an object internal to +the function that is used to determine what to store at \tcode{*idx}. If the function +does not throw an exception and \tcode{idx != nullptr}, the function stores in \tcode{*idx} +the index of the first unconverted element of \tcode{str}. \pnum -\mandates -\tcode{R} denotes a comparison category type\iref{cmp.categories}. +\returns +The converted result. \pnum -\returns -\tcode{static_cast(lhs.compare(rhs) <=> 0)}. +\throws +\tcode{invalid_argument} if \tcode{wcstof}, \tcode{wcstod}, or \tcode{wcstold} reports that no +conversion can be performed. Throws \tcode{out_of_range} if \tcode{wcstof}, \tcode{wcstod}, or +\tcode{wcstold} sets \tcode{errno} to \tcode{ERANGE}. \end{itemdescr} -\rSec2[string.view.io]{Inserters and extractors} - -\indexlibrarymember{operator<<}{basic_string_view}% +\indexlibraryglobal{to_wstring}% \begin{itemdecl} -template - basic_ostream& - operator<<(basic_ostream& os, basic_string_view str); +wstring to_wstring(int val); +wstring to_wstring(unsigned val); +wstring to_wstring(long val); +wstring to_wstring(unsigned long val); +wstring to_wstring(long long val); +wstring to_wstring(unsigned long long val); +wstring to_wstring(float val); +wstring to_wstring(double val); +wstring to_wstring(long double val); \end{itemdecl} \begin{itemdescr} -\pnum -\effects -Behaves as a formatted output -function\iref{ostream.formatted.reqmts} of \tcode{os}. Forms a character sequence -\tcode{seq}, initially consisting of the elements defined by the range -\range{str.begin()}{str.end()}. Determines padding for \tcode{seq} -as described in~\ref{ostream.formatted.reqmts}. -Then inserts \tcode{seq} as if by calling -\tcode{os.rdbuf()->sputn(\brk{}seq, n)}, where \tcode{n} is the larger -of \tcode{os.width()} and \tcode{str.size()}; -then calls \tcode{os.\brk{}width(0)}. - \pnum \returns -\tcode{os} +Each function returns a \tcode{wstring} object holding the character +representation of the value of its argument that would be generated by calling +\tcode{swprintf(buf, buffsz, fmt, val)} with a format specifier of +\tcode{L"\%d"}, +\tcode{L"\%u"}, +\tcode{L"\%ld"}, +\tcode{L"\%lu"}, +\tcode{L"\%lld"}, +\tcode{L"\%llu"}, +\tcode{L"\%f"}, +\tcode{L"\%f"}, +or \tcode{L"\%Lf"}, respectively, where \tcode{buf} designates an +internal character buffer of sufficient size \tcode{buffsz}. \end{itemdescr} -\rSec2[string.view.hash]{Hash support} +\rSec2[basic.string.hash]{Hash support} -\indexlibrarymember{hash}{string_view}% -\indexlibrarymember{hash}{u8string_view}% -\indexlibrarymember{hash}{u16string_view}% -\indexlibrarymember{hash}{u32string_view}% -\indexlibrarymember{hash}{wstring_view}% +\indexlibrarymember{hash}{string}% +\indexlibrarymember{hash}{u16string}% +\indexlibrarymember{hash}{u32string}% +\indexlibrarymember{hash}{wstring}% +\indexlibrarymember{hash}{pmr::string}% +\indexlibrarymember{hash}{pmr::u16string}% +\indexlibrarymember{hash}{pmr::u32string}% +\indexlibrarymember{hash}{pmr::wstring}% \begin{itemdecl} -template<> struct hash; -template<> struct hash; -template<> struct hash; -template<> struct hash; -template<> struct hash; +template<> struct hash; +template<> struct hash; +template<> struct hash; +template<> struct hash; +template<> struct hash; +template<> struct hash; +template<> struct hash; +template<> struct hash; +template<> struct hash; +template<> struct hash; \end{itemdecl} \begin{itemdescr} \pnum -The specialization is enabled\iref{unord.hash}. -\begin{note} -The hash value of a string view object is equal to the hash value of -the corresponding string object\iref{basic.string.hash}. -\end{note} +If \tcode{S} is one of these string types, +\tcode{SV} is the corresponding string view type, and +\tcode{s} is an object of type \tcode{S}, +then \tcode{hash()(s) == hash()(SV(s))}. \end{itemdescr} -\rSec2[string.view.literals]{Suffix for \tcode{basic_string_view} literals} +\rSec2[basic.string.literals]{Suffix for \tcode{basic_string} literals} -\indexlibrarymember{operator""""sv}{string_view}% +\indexlibrarymember{operator""""s}{string}% \begin{itemdecl} -constexpr string_view operator""sv(const char* str, size_t len) noexcept; +constexpr string operator""s(const char* str, size_t len); \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{string_view\{str, len\}}. +\tcode{string\{str, len\}}. \end{itemdescr} -\indexlibrarymember{operator""""sv}{u8string_view}% +\indexlibrarymember{operator""""s}{u8string}% \begin{itemdecl} -constexpr u8string_view operator""sv(const char8_t* str, size_t len) noexcept; +constexpr u8string operator""s(const char8_t* str, size_t len); \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{u8string_view\{str, len\}}. +\tcode{u8string\{str, len\}}. \end{itemdescr} -\indexlibrarymember{operator""""sv}{u16string_view}% +\indexlibrarymember{operator""""s}{u16string}% \begin{itemdecl} -constexpr u16string_view operator""sv(const char16_t* str, size_t len) noexcept; +constexpr u16string operator""s(const char16_t* str, size_t len); \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{u16string_view\{str, len\}}. +\tcode{u16string\{str, len\}}. \end{itemdescr} -\indexlibrarymember{operator""""sv}{u32string_view}% +\indexlibrarymember{operator""""s}{u32string}% \begin{itemdecl} -constexpr u32string_view operator""sv(const char32_t* str, size_t len) noexcept; +constexpr u32string operator""s(const char32_t* str, size_t len); \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{u32string_view\{str, len\}}. +\tcode{u32string\{str, len\}}. \end{itemdescr} -\indexlibrarymember{operator""""sv}{wstring_view}% +\indexlibrarymember{operator""""s}{wstring}% \begin{itemdecl} -constexpr wstring_view operator""sv(const wchar_t* str, size_t len) noexcept; +constexpr wstring operator""s(const wchar_t* str, size_t len); \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{wstring_view\{str, len\}}. +\tcode{wstring\{str, len\}}. \end{itemdescr} +\pnum +\begin{note} +The same suffix \tcode{s} is used for \tcode{chrono::duration} literals denoting seconds but there is no conflict, since duration suffixes apply to numbers and string literal suffixes apply to character array literals. +\end{note} \rSec1[c.strings]{Null-terminated sequence utilities} diff --git a/source/threads.tex b/source/threads.tex index 5f8da57d2f..7b59b6c533 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -13,6 +13,8 @@ \ref{thread.req} & Requirements & \\ \rowsep \ref{thread.stoptoken}& Stop tokens & \tcode{} \\ \rowsep \ref{thread.threads} & Threads & \tcode{} \\ \rowsep +\ref{atomics} & Atomic operations & + \tcode{} \tcode{} \tcode{} \\ \rowsep \ref{thread.mutex} & Mutual exclusion & \tcode{}, \tcode{} \\ \rowsep \ref{thread.condition}& Condition variables & \tcode{} \\ \rowsep @@ -2032,6 +2034,3841 @@ Timeout-related exceptions\iref{thread.req.timing}. \end{itemdescr} +\rSec1[atomics]{Atomic operations} + +\rSec2[atomics.general]{General} + +\pnum +Subclause \ref{atomics} describes components for fine-grained atomic access. +This access is provided via operations on atomic objects. + +\rSec2[atomics.syn]{Header \tcode{} synopsis} + +\indexheader{atomic}% +\begin{codeblock} +namespace std { + // \ref{atomics.order}, order and consistency + enum class memory_order : @\unspec@; + template + T kill_dependency(T y) noexcept; +} + +// \ref{atomics.lockfree}, lock-free property +#define ATOMIC_BOOL_LOCK_FREE @\unspec@ +#define ATOMIC_CHAR_LOCK_FREE @\unspec@ +#define ATOMIC_CHAR8_T_LOCK_FREE @\unspec@ +#define ATOMIC_CHAR16_T_LOCK_FREE @\unspec@ +#define ATOMIC_CHAR32_T_LOCK_FREE @\unspec@ +#define ATOMIC_WCHAR_T_LOCK_FREE @\unspec@ +#define ATOMIC_SHORT_LOCK_FREE @\unspec@ +#define ATOMIC_INT_LOCK_FREE @\unspec@ +#define ATOMIC_LONG_LOCK_FREE @\unspec@ +#define ATOMIC_LLONG_LOCK_FREE @\unspec@ +#define ATOMIC_POINTER_LOCK_FREE @\unspec@ + +namespace std { + // \ref{atomics.ref.generic}, class template \tcode{atomic_ref} + template struct atomic_ref; + // \ref{atomics.ref.pointer}, partial specialization for pointers + template struct atomic_ref; + + // \ref{atomics.types.generic}, class template \tcode{atomic} + template struct atomic; + // \ref{atomics.types.pointer}, partial specialization for pointers + template struct atomic; + + // \ref{atomics.nonmembers}, non-member functions + template + bool atomic_is_lock_free(const volatile atomic*) noexcept; + template + bool atomic_is_lock_free(const atomic*) noexcept; + template + void atomic_store(volatile atomic*, typename atomic::value_type) noexcept; + template + void atomic_store(atomic*, typename atomic::value_type) noexcept; + template + void atomic_store_explicit(volatile atomic*, typename atomic::value_type, + memory_order) noexcept; + template + void atomic_store_explicit(atomic*, typename atomic::value_type, + memory_order) noexcept; + template + T atomic_load(const volatile atomic*) noexcept; + template + T atomic_load(const atomic*) noexcept; + template + T atomic_load_explicit(const volatile atomic*, memory_order) noexcept; + template + T atomic_load_explicit(const atomic*, memory_order) noexcept; + template + T atomic_exchange(volatile atomic*, typename atomic::value_type) noexcept; + template + T atomic_exchange(atomic*, typename atomic::value_type) noexcept; + template + T atomic_exchange_explicit(volatile atomic*, typename atomic::value_type, + memory_order) noexcept; + template + T atomic_exchange_explicit(atomic*, typename atomic::value_type, + memory_order) noexcept; + template + bool atomic_compare_exchange_weak(volatile atomic*, + typename atomic::value_type*, + typename atomic::value_type) noexcept; + template + bool atomic_compare_exchange_weak(atomic*, + typename atomic::value_type*, + typename atomic::value_type) noexcept; + template + bool atomic_compare_exchange_strong(volatile atomic*, + typename atomic::value_type*, + typename atomic::value_type) noexcept; + template + bool atomic_compare_exchange_strong(atomic*, + typename atomic::value_type*, + typename atomic::value_type) noexcept; + template + bool atomic_compare_exchange_weak_explicit(volatile atomic*, + typename atomic::value_type*, + typename atomic::value_type, + memory_order, memory_order) noexcept; + template + bool atomic_compare_exchange_weak_explicit(atomic*, + typename atomic::value_type*, + typename atomic::value_type, + memory_order, memory_order) noexcept; + template + bool atomic_compare_exchange_strong_explicit(volatile atomic*, + typename atomic::value_type*, + typename atomic::value_type, + memory_order, memory_order) noexcept; + template + bool atomic_compare_exchange_strong_explicit(atomic*, + typename atomic::value_type*, + typename atomic::value_type, + memory_order, memory_order) noexcept; + + template + T atomic_fetch_add(volatile atomic*, typename atomic::difference_type) noexcept; + template + T atomic_fetch_add(atomic*, typename atomic::difference_type) noexcept; + template + T atomic_fetch_add_explicit(volatile atomic*, typename atomic::difference_type, + memory_order) noexcept; + template + T atomic_fetch_add_explicit(atomic*, typename atomic::difference_type, + memory_order) noexcept; + template + T atomic_fetch_sub(volatile atomic*, typename atomic::difference_type) noexcept; + template + T atomic_fetch_sub(atomic*, typename atomic::difference_type) noexcept; + template + T atomic_fetch_sub_explicit(volatile atomic*, typename atomic::difference_type, + memory_order) noexcept; + template + T atomic_fetch_sub_explicit(atomic*, typename atomic::difference_type, + memory_order) noexcept; + template + T atomic_fetch_and(volatile atomic*, typename atomic::value_type) noexcept; + template + T atomic_fetch_and(atomic*, typename atomic::value_type) noexcept; + template + T atomic_fetch_and_explicit(volatile atomic*, typename atomic::value_type, + memory_order) noexcept; + template + T atomic_fetch_and_explicit(atomic*, typename atomic::value_type, + memory_order) noexcept; + template + T atomic_fetch_or(volatile atomic*, typename atomic::value_type) noexcept; + template + T atomic_fetch_or(atomic*, typename atomic::value_type) noexcept; + template + T atomic_fetch_or_explicit(volatile atomic*, typename atomic::value_type, + memory_order) noexcept; + template + T atomic_fetch_or_explicit(atomic*, typename atomic::value_type, + memory_order) noexcept; + template + T atomic_fetch_xor(volatile atomic*, typename atomic::value_type) noexcept; + template + T atomic_fetch_xor(atomic*, typename atomic::value_type) noexcept; + template + T atomic_fetch_xor_explicit(volatile atomic*, typename atomic::value_type, + memory_order) noexcept; + template + T atomic_fetch_xor_explicit(atomic*, typename atomic::value_type, + memory_order) noexcept; + + template + void atomic_wait(const volatile atomic*, typename atomic::value_type); + template + void atomic_wait(const atomic*, typename atomic::value_type); + template + void atomic_wait_explicit(const volatile atomic*, typename atomic::value_type, + memory_order); + template + void atomic_wait_explicit(const atomic*, typename atomic::value_type, + memory_order); + template + void atomic_notify_one(volatile atomic*); + template + void atomic_notify_one(atomic*); + template + void atomic_notify_all(volatile atomic*); + template + void atomic_notify_all(atomic*); + + // \ref{atomics.alias}, type aliases + using atomic_bool = atomic; + using atomic_char = atomic; + using atomic_schar = atomic; + using atomic_uchar = atomic; + using atomic_short = atomic; + using atomic_ushort = atomic; + using atomic_int = atomic; + using atomic_uint = atomic; + using atomic_long = atomic; + using atomic_ulong = atomic; + using atomic_llong = atomic; + using atomic_ullong = atomic; + using atomic_char8_t = atomic; + using atomic_char16_t = atomic; + using atomic_char32_t = atomic; + using atomic_wchar_t = atomic; + + using atomic_int8_t = atomic; + using atomic_uint8_t = atomic; + using atomic_int16_t = atomic; + using atomic_uint16_t = atomic; + using atomic_int32_t = atomic; + using atomic_uint32_t = atomic; + using atomic_int64_t = atomic; + using atomic_uint64_t = atomic; + + using atomic_int_least8_t = atomic; + using atomic_uint_least8_t = atomic; + using atomic_int_least16_t = atomic; + using atomic_uint_least16_t = atomic; + using atomic_int_least32_t = atomic; + using atomic_uint_least32_t = atomic; + using atomic_int_least64_t = atomic; + using atomic_uint_least64_t = atomic; + + using atomic_int_fast8_t = atomic; + using atomic_uint_fast8_t = atomic; + using atomic_int_fast16_t = atomic; + using atomic_uint_fast16_t = atomic; + using atomic_int_fast32_t = atomic; + using atomic_uint_fast32_t = atomic; + using atomic_int_fast64_t = atomic; + using atomic_uint_fast64_t = atomic; + + using atomic_intptr_t = atomic; + using atomic_uintptr_t = atomic; + using atomic_size_t = atomic; + using atomic_ptrdiff_t = atomic; + using atomic_intmax_t = atomic; + using atomic_uintmax_t = atomic; + + using atomic_signed_lock_free = @\seebelow@; + using atomic_unsigned_lock_free = @\seebelow@; + + // \ref{atomics.flag}, flag type and operations + struct atomic_flag; + + bool atomic_flag_test(const volatile atomic_flag*) noexcept; + bool atomic_flag_test(const atomic_flag*) noexcept; + bool atomic_flag_test_explicit(const volatile atomic_flag*, memory_order) noexcept; + bool atomic_flag_test_explicit(const atomic_flag*, memory_order) noexcept; + bool atomic_flag_test_and_set(volatile atomic_flag*) noexcept; + bool atomic_flag_test_and_set(atomic_flag*) noexcept; + bool atomic_flag_test_and_set_explicit(volatile atomic_flag*, memory_order) noexcept; + bool atomic_flag_test_and_set_explicit(atomic_flag*, memory_order) noexcept; + void atomic_flag_clear(volatile atomic_flag*) noexcept; + void atomic_flag_clear(atomic_flag*) noexcept; + void atomic_flag_clear_explicit(volatile atomic_flag*, memory_order) noexcept; + void atomic_flag_clear_explicit(atomic_flag*, memory_order) noexcept; + + void atomic_flag_wait(const volatile atomic_flag*, bool) noexcept; + void atomic_flag_wait(const atomic_flag*, bool) noexcept; + void atomic_flag_wait_explicit(const volatile atomic_flag*, + bool, memory_order) noexcept; + void atomic_flag_wait_explicit(const atomic_flag*, + bool, memory_order) noexcept; + void atomic_flag_notify_one(volatile atomic_flag*) noexcept; + void atomic_flag_notify_one(atomic_flag*) noexcept; + void atomic_flag_notify_all(volatile atomic_flag*) noexcept; + void atomic_flag_notify_all(atomic_flag*) noexcept; + + // \ref{atomics.fences}, fences + extern "C" void atomic_thread_fence(memory_order) noexcept; + extern "C" void atomic_signal_fence(memory_order) noexcept; +} +\end{codeblock} + +\rSec2[atomics.alias]{Type aliases} +\indexlibraryglobal{atomic_bool}% +\indexlibraryglobal{atomic_char}% +\indexlibraryglobal{atomic_schar}% +\indexlibraryglobal{atomic_uchar}% +\indexlibraryglobal{atomic_short}% +\indexlibraryglobal{atomic_ushort}% +\indexlibraryglobal{atomic_int}% +\indexlibraryglobal{atomic_uint}% +\indexlibraryglobal{atomic_long}% +\indexlibraryglobal{atomic_ulong}% +\indexlibraryglobal{atomic_llong}% +\indexlibraryglobal{atomic_ullong}% +\indexlibraryglobal{atomic_char8_t}% +\indexlibraryglobal{atomic_char16_t}% +\indexlibraryglobal{atomic_char32_t}% +\indexlibraryglobal{atomic_wchar_t}% +\indexlibraryglobal{atomic_int8_t}% +\indexlibraryglobal{atomic_uint8_t}% +\indexlibraryglobal{atomic_int16_t}% +\indexlibraryglobal{atomic_uint16_t}% +\indexlibraryglobal{atomic_int32_t}% +\indexlibraryglobal{atomic_uint32_t}% +\indexlibraryglobal{atomic_int64_t}% +\indexlibraryglobal{atomic_uint64_t}% +\indexlibraryglobal{atomic_int_least8_t}% +\indexlibraryglobal{atomic_uint_least8_t}% +\indexlibraryglobal{atomic_int_least16_t}% +\indexlibraryglobal{atomic_uint_least16_t}% +\indexlibraryglobal{atomic_int_least32_t}% +\indexlibraryglobal{atomic_uint_least32_t}% +\indexlibraryglobal{atomic_int_least64_t}% +\indexlibraryglobal{atomic_uint_least64_t}% +\indexlibraryglobal{atomic_int_fast8_t}% +\indexlibraryglobal{atomic_uint_fast8_t}% +\indexlibraryglobal{atomic_int_fast16_t}% +\indexlibraryglobal{atomic_uint_fast16_t}% +\indexlibraryglobal{atomic_int_fast32_t}% +\indexlibraryglobal{atomic_uint_fast32_t}% +\indexlibraryglobal{atomic_int_fast64_t}% +\indexlibraryglobal{atomic_uint_fast64_t}% +\indexlibraryglobal{atomic_intptr_t}% +\indexlibraryglobal{atomic_uintptr_t}% +\indexlibraryglobal{atomic_size_t}% +\indexlibraryglobal{atomic_ptrdiff_t}% +\indexlibraryglobal{atomic_intmax_t}% +\indexlibraryglobal{atomic_uintmax_t}% +\pnum +The type aliases \tcode{atomic_int$N$_t}, \tcode{atomic_uint$N$_t}, +\tcode{atomic_intptr_t}, and \tcode{atomic_uintptr_t} +are defined if and only if +\tcode{int$N$_t}, \tcode{uint$N$_t}, +\tcode{intptr_t}, and \tcode{uintptr_t} +are defined, respectively. + +\pnum +\indexlibraryglobal{atomic_signed_lock_free}% +\indexlibraryglobal{atomic_unsigned_lock_free}% +The type aliases +\tcode{atomic_signed_lock_free} and \tcode{atomic_unsigned_lock_free} +name specializations of \tcode{atomic} +whose template arguments are integral types, respectively signed and unsigned, +and whose \tcode{is_always_lock_free} property is \tcode{true}. +\begin{note} +\indextext{implementation!freestanding}% +These aliases are optional in freestanding implementations\iref{compliance}. +\end{note} +Implementations should choose for these aliases +the integral specializations of \tcode{atomic} +for which the atomic waiting and notifying operations\iref{atomics.wait} +are most efficient. + +\rSec2[atomics.order]{Order and consistency} +\indexlibraryglobal{memory_order}% +\indexlibrarymember{relaxed}{memory_order}% +\indexlibrarymember{consume}{memory_order}% +\indexlibrarymember{acquire}{memory_order}% +\indexlibrarymember{release}{memory_order}% +\indexlibrarymember{acq_rel}{memory_order}% +\indexlibrarymember{seq_cst}{memory_order}% +\indexlibraryglobal{memory_order_relaxed}% +\indexlibraryglobal{memory_order_consume}% +\indexlibraryglobal{memory_order_acquire}% +\indexlibraryglobal{memory_order_release}% +\indexlibraryglobal{memory_order_acq_rel}% +\indexlibraryglobal{memory_order_seq_cst}% + +\begin{codeblock} +namespace std { + enum class memory_order : @\unspec@ { + relaxed, consume, acquire, release, acq_rel, seq_cst + }; + inline constexpr memory_order memory_order_relaxed = memory_order::relaxed; + inline constexpr memory_order memory_order_consume = memory_order::consume; + inline constexpr memory_order memory_order_acquire = memory_order::acquire; + inline constexpr memory_order memory_order_release = memory_order::release; + inline constexpr memory_order memory_order_acq_rel = memory_order::acq_rel; + inline constexpr memory_order memory_order_seq_cst = memory_order::seq_cst; +} +\end{codeblock} + +\pnum +The enumeration \tcode{memory_order} specifies the detailed regular +(non-atomic) memory synchronization order as defined in +\ref{intro.multithread} and may provide for operation ordering. Its +enumerated values and their meanings are as follows: + +\begin{itemize} +\item \tcode{memory_order::relaxed}: no operation orders memory. + +\item \tcode{memory_order::release}, \tcode{memory_order::acq_rel}, and +\tcode{memory_order::seq_cst}: a store operation performs a release operation on the +affected memory location. + +\item \tcode{memory_order::consume}: a load operation performs a consume operation on the +affected memory location. +\begin{note} +Prefer \tcode{memory_order::acquire}, which provides stronger guarantees +than \tcode{memory_order::consume}. Implementations have found it infeasible +to provide performance better than that of \tcode{memory_order::acquire}. +Specification revisions are under consideration. +\end{note} + +\item \tcode{memory_order::acquire}, \tcode{memory_order::acq_rel}, and +\tcode{memory_order::seq_cst}: a load operation performs an acquire operation on the +affected memory location. +\end{itemize} + +\begin{note} +Atomic operations specifying \tcode{memory_order::relaxed} are relaxed +with respect to memory ordering. Implementations must still guarantee that any +given atomic access to a particular atomic object be indivisible with respect +to all other atomic accesses to that object. +\end{note} + +\pnum +An atomic operation $A$ that performs a release operation on an atomic +object $M$ synchronizes with an atomic operation $B$ that performs +an acquire operation on $M$ and takes its value from any side effect in the +release sequence headed by $A$. + +\pnum +An atomic operation $A$ on some atomic object $M$ is +\defn{coherence-ordered before} +another atomic operation $B$ on $M$ if +\begin{itemize} +\item $A$ is a modification, and +$B$ reads the value stored by $A$, or +\item $A$ precedes $B$ +in the modification order of $M$, or +\item $A$ and $B$ are not +the same atomic read-modify-write operation, and +there exists an atomic modification $X$ of $M$ +such that $A$ reads the value stored by $X$ and +$X$ precedes $B$ +in the modification order of $M$, or +\item there exists an atomic modification $X$ of $M$ +such that $A$ is coherence-ordered before $X$ and +$X$ is coherence-ordered before $B$. +\end{itemize} + +\pnum +There is a single total order $S$ +on all \tcode{memory_order::seq_cst} operations, including fences, +that satisfies the following constraints. +First, if $A$ and $B$ are +\tcode{memory_order::seq_cst} operations and +$A$ strongly happens before $B$, +then $A$ precedes $B$ in $S$. +Second, for every pair of atomic operations $A$ and +$B$ on an object $M$, +where $A$ is coherence-ordered before $B$, +the following four conditions are required to be satisfied by $S$: +\begin{itemize} +\item if $A$ and $B$ are both +\tcode{memory_order::seq_cst} operations, +then $A$ precedes $B$ in $S$; and +\item if $A$ is a \tcode{memory_order::seq_cst} operation and +$B$ happens before +a \tcode{memory_order::seq_cst} fence $Y$, +then $A$ precedes $Y$ in $S$; and +\item if a \tcode{memory_order::seq_cst} fence $X$ +happens before $A$ and +$B$ is a \tcode{memory_order::seq_cst} operation, +then $X$ precedes $B$ in $S$; and +\item if a \tcode{memory_order::seq_cst} fence $X$ +happens before $A$ and +$B$ happens before +a \tcode{memory_order::seq_cst} fence $Y$, +then $X$ precedes $Y$ in $S$. +\end{itemize} + +\pnum +\begin{note} +This definition ensures that $S$ is consistent with +the modification order of any atomic object $M$. +It also ensures that +a \tcode{memory_order::seq_cst} load $A$ of $M$ +gets its value either from the last modification of $M$ +that precedes $A$ in $S$ or +from some non-\tcode{memory_order::seq_cst} modification of $M$ +that does not happen before any modification of $M$ +that precedes $A$ in $S$. +\end{note} + +\pnum +\begin{note} +We do not require that $S$ be consistent with +``happens before''\iref{intro.races}. +This allows more efficient implementation +of \tcode{memory_order::acquire} and \tcode{memory_order::release} +on some machine architectures. +It can produce surprising results +when these are mixed with \tcode{memory_order::seq_cst} accesses. +\end{note} + +\pnum +\begin{note} +\tcode{memory_order::seq_cst} ensures sequential consistency only +for a program that is free of data races and +uses exclusively \tcode{memory_order::seq_cst} atomic operations. +Any use of weaker ordering will invalidate this guarantee +unless extreme care is used. +In many cases, \tcode{memory_order::seq_cst} atomic operations are reorderable +with respect to other atomic operations performed by the same thread. +\end{note} + +\pnum +Implementations should ensure that no ``out-of-thin-air'' values are computed that +circularly depend on their own computation. + +\begin{note} +For example, with \tcode{x} and \tcode{y} initially zero, +\begin{codeblock} +// Thread 1: +r1 = y.load(memory_order::relaxed); +x.store(r1, memory_order::relaxed); +\end{codeblock} + +\begin{codeblock} +// Thread 2: +r2 = x.load(memory_order::relaxed); +y.store(r2, memory_order::relaxed); +\end{codeblock} +this recommendation discourages producing \tcode{r1 == r2 == 42}, since the store of 42 to \tcode{y} is only +possible if the store to \tcode{x} stores \tcode{42}, which circularly depends on the +store to \tcode{y} storing \tcode{42}. Note that without this restriction, such an +execution is possible. +\end{note} + +\pnum +\begin{note} +The recommendation similarly disallows \tcode{r1 == r2 == 42} in the +following example, with \tcode{x} and \tcode{y} again initially zero: + +\begin{codeblock} +// Thread 1: +r1 = x.load(memory_order::relaxed); +if (r1 == 42) y.store(42, memory_order::relaxed); +\end{codeblock} + +\begin{codeblock} +// Thread 2: +r2 = y.load(memory_order::relaxed); +if (r2 == 42) x.store(42, memory_order::relaxed); +\end{codeblock} +\end{note} + +\pnum +Atomic read-modify-write operations shall always read the last value +(in the modification order) written before the write associated with +the read-modify-write operation. + +\pnum +Implementations should make atomic stores visible to atomic loads within a reasonable +amount of time. + +\indexlibraryglobal{kill_dependency}% +\begin{itemdecl} +template + T kill_dependency(T y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +The argument does not carry a dependency to the return +value\iref{intro.multithread}. + +\pnum +\returns +\tcode{y}. +\end{itemdescr} + + +\rSec2[atomics.lockfree]{Lock-free property} + +\indexlibraryglobal{ATOMIC_BOOL_LOCK_FREE}% +\indexlibraryglobal{ATOMIC_CHAR_LOCK_FREE}% +\indexlibraryglobal{ATOMIC_CHAR8_T_LOCK_FREE}% +\indexlibraryglobal{ATOMIC_CHAR16_T_LOCK_FREE}% +\indexlibraryglobal{ATOMIC_CHAR32_T_LOCK_FREE}% +\indexlibraryglobal{ATOMIC_WCHAR_T_LOCK_FREE}% +\indexlibraryglobal{ATOMIC_SHORT_LOCK_FREE}% +\indexlibraryglobal{ATOMIC_INT_LOCK_FREE}% +\indexlibraryglobal{ATOMIC_LONG_LOCK_FREE}% +\indexlibraryglobal{ATOMIC_LLONG_LOCK_FREE}% +\indexlibraryglobal{ATOMIC_POINTER_LOCK_FREE}% +\indeximpldef{values of various \tcode{ATOMIC_..._LOCK_FREE} macros} +\begin{codeblock} +#define ATOMIC_BOOL_LOCK_FREE @\unspec@ +#define ATOMIC_CHAR_LOCK_FREE @\unspec@ +#define ATOMIC_CHAR8_T_LOCK_FREE @\unspec@ +#define ATOMIC_CHAR16_T_LOCK_FREE @\unspec@ +#define ATOMIC_CHAR32_T_LOCK_FREE @\unspec@ +#define ATOMIC_WCHAR_T_LOCK_FREE @\unspec@ +#define ATOMIC_SHORT_LOCK_FREE @\unspec@ +#define ATOMIC_INT_LOCK_FREE @\unspec@ +#define ATOMIC_LONG_LOCK_FREE @\unspec@ +#define ATOMIC_LLONG_LOCK_FREE @\unspec@ +#define ATOMIC_POINTER_LOCK_FREE @\unspec@ +\end{codeblock} + +\pnum +The \tcode{ATOMIC_..._LOCK_FREE} macros indicate the lock-free property of the +corresponding atomic types, with the signed and unsigned variants grouped +together. The properties also apply to the corresponding (partial) specializations of the +\tcode{atomic} template. A value of 0 indicates that the types are never +lock-free. A value of 1 indicates that the types are sometimes lock-free. A +value of 2 indicates that the types are always lock-free. + +\pnum +At least one signed integral specialization of the \tcode{atomic} template, +along with the specialization +for the corresponding unsigned type\iref{basic.fundamental}, +is always lock-free. +\begin{note} +\indextext{implementation!freestanding}% +This requirement is optional in freestanding implementations\iref{compliance}. +\end{note} + +\pnum +The functions \tcode{atomic::is_lock_free} and +\tcode{atomic_is_lock_free}\iref{atomics.types.operations} +indicate whether the object is lock-free. In any given program execution, the +result of the lock-free query +is the same for all atomic objects of the same type. + +\pnum +Atomic operations that are not lock-free are considered to potentially +block\iref{intro.progress}. + +\pnum +\recommended +Operations that are lock-free should also be address-free. +\begin{footnote} +That is, +atomic operations on the same memory location via two different addresses will +communicate atomically. +\end{footnote} +The implementation of these operations should not depend on any per-process state. +\begin{note} +This restriction enables communication by memory that is +mapped into a process more than once and by memory that is shared between two +processes. +\end{note} + +\rSec2[atomics.wait]{Waiting and notifying} + +\pnum +\defnx{Atomic waiting operations}{atomic!waiting operation} +and \defnx{atomic notifying operations}{atomic!notifying operation} +provide a mechanism to wait for the value of an atomic object to change +more efficiently than can be achieved with polling. +An atomic waiting operation may block until it is unblocked +by an atomic notifying operation, according to each function's effects. +\begin{note} +Programs are not guaranteed to observe transient atomic values, +an issue known as the A-B-A problem, +resulting in continued blocking if a condition is only temporarily met. +\end{note} + +\pnum +\begin{note} +The following functions are atomic waiting operations: +\begin{itemize} +\item \tcode{atomic::wait}, +\item \tcode{atomic_flag::wait}, +\item \tcode{atomic_wait} and \tcode{atomic_wait_explicit}, +\item \tcode{atomic_flag_wait} and \tcode{atomic_flag_wait_explicit}, and +\item \tcode{atomic_ref::wait}. +\end{itemize} +\end{note} + +\pnum +\begin{note} +The following functions are atomic notifying operations: +\begin{itemize} +\item \tcode{atomic::notify_one} and \tcode{atomic::notify_all}, +\item \tcode{atomic_flag::notify_one} and \tcode{atomic_flag::notify_all}, +\item \tcode{atomic_notify_one} and \tcode{atomic_notify_all}, +\item \tcode{atomic_flag_notify_one} and \tcode{atomic_flag_notify_all}, and +\item \tcode{atomic_ref::notify_one} and \tcode{atomic_ref::notify_all}. +\end{itemize} +\end{note} + +\indextext{atomic!waiting operation!eligible to be unblocked}% +\pnum +A call to an atomic waiting operation on an atomic object \tcode{M} +is \defn{eligible to be unblocked} +by a call to an atomic notifying operation on \tcode{M} +if there exist side effects \tcode{X} and \tcode{Y} on \tcode{M} such that: +\begin{itemize} +\item the atomic waiting operation has blocked after observing the result of \tcode{X}, +\item \tcode{X} precedes \tcode{Y} in the modification order of \tcode{M}, and +\item \tcode{Y} happens before the call to the atomic notifying operation. +\end{itemize} + +\rSec2[atomics.ref.generic]{Class template \tcode{atomic_ref}} + +\rSec3[atomics.ref.generic.general]{General} + +\indexlibraryglobal{atomic_ref}% +\indexlibrarymember{value_type}{atomic_ref}% +\begin{codeblock} +namespace std { + template struct atomic_ref { + private: + T* ptr; // \expos + public: + using value_type = T; + static constexpr size_t required_alignment = @\impdefx{required alignment for \tcode{atomic_ref} type's operations}@; + + static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic_ref} type's operations are always lock free}@; + bool is_lock_free() const noexcept; + + explicit atomic_ref(T&); + atomic_ref(const atomic_ref&) noexcept; + atomic_ref& operator=(const atomic_ref&) = delete; + + void store(T, memory_order = memory_order::seq_cst) const noexcept; + T operator=(T) const noexcept; + T load(memory_order = memory_order::seq_cst) const noexcept; + operator T() const noexcept; + + T exchange(T, memory_order = memory_order::seq_cst) const noexcept; + bool compare_exchange_weak(T&, T, + memory_order, memory_order) const noexcept; + bool compare_exchange_strong(T&, T, + memory_order, memory_order) const noexcept; + bool compare_exchange_weak(T&, T, + memory_order = memory_order::seq_cst) const noexcept; + bool compare_exchange_strong(T&, T, + memory_order = memory_order::seq_cst) const noexcept; + + void wait(T, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() const noexcept; + void notify_all() const noexcept; + }; +} +\end{codeblock} + +\pnum +An \tcode{atomic_ref} object applies atomic operations\iref{atomics.general} to +the object referenced by \tcode{*ptr} such that, +for the lifetime\iref{basic.life} of the \tcode{atomic_ref} object, +the object referenced by \tcode{*ptr} is an atomic object\iref{intro.races}. + +\pnum +The program is ill-formed if \tcode{is_trivially_copyable_v} is \tcode{false}. + +\pnum +The lifetime\iref{basic.life} of an object referenced by \tcode{*ptr} +shall exceed the lifetime of all \tcode{atomic_ref}s that reference the object. +While any \tcode{atomic_ref} instances exist +that reference the \tcode{*ptr} object, +all accesses to that object shall exclusively occur +through those \tcode{atomic_ref} instances. +No subobject of the object referenced by \tcode{atomic_ref} +shall be concurrently referenced by any other \tcode{atomic_ref} object. + +\pnum +Atomic operations applied to an object +through a referencing \tcode{atomic_ref} are atomic with respect to +atomic operations applied through any other \tcode{atomic_ref} +referencing the same object. +\begin{note} +Atomic operations or the \tcode{atomic_ref} constructor can acquire +a shared resource, such as a lock associated with the referenced object, +to enable atomic operations to be applied to the referenced object. +\end{note} + +\rSec3[atomics.ref.ops]{Operations} + +\indexlibrarymember{required_alignment}{atomic_ref}% +\indexlibrarymember{required_alignment}{atomic_ref}% +\indexlibrarymember{required_alignment}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{required_alignment}{atomic_ref<\placeholder{floating-point}>}% +\begin{itemdecl} +static constexpr size_t required_alignment; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The alignment required for an object to be referenced by an atomic reference, +which is at least \tcode{alignof(T)}. + +\pnum +\begin{note} +Hardware could require an object +referenced by an \tcode{atomic_ref} +to have stricter alignment\iref{basic.align} +than other objects of type \tcode{T}. +Further, whether operations on an \tcode{atomic_ref} +are lock-free could depend on the alignment of the referenced object. +For example, lock-free operations on \tcode{std::complex} +could be supported only if aligned to \tcode{2*alignof(double)}. +\end{note} +\end{itemdescr} + +\indexlibrarymember{is_always_lock_free}{atomic_ref}% +\indexlibrarymember{is_always_lock_free}{atomic_ref}% +\indexlibrarymember{is_always_lock_free}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{is_always_lock_free}{atomic_ref<\placeholder{floating-point}>}% +\begin{itemdecl} +static constexpr bool is_always_lock_free; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The static data member \tcode{is_always_lock_free} is \tcode{true} +if the \tcode{atomic_ref} type's operations are always lock-free, +and \tcode{false} otherwise. +\end{itemdescr} + +\indexlibrarymember{is_lock_free}{atomic_ref}% +\indexlibrarymember{is_lock_free}{atomic_ref}% +\indexlibrarymember{is_lock_free}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{is_lock_free}{atomic_ref<\placeholder{floating-point}>}% +\begin{itemdecl} +bool is_lock_free() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if operations on all objects of the type \tcode{atomic_ref} +are lock-free, +\tcode{false} otherwise. +\end{itemdescr} + +\indexlibraryctor{atomic_ref}% +\indexlibraryctor{atomic_ref}% +\indexlibrary{\idxcode{atomic_ref<\placeholder{integral}>}!constructor}% +\indexlibrary{\idxcode{atomic_ref<\placeholder{floating-point}>}!constructor}% +\begin{itemdecl} +atomic_ref(T& obj); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +The referenced object is aligned to \tcode{required_alignment}. + +\pnum +\ensures +\tcode{*this} references \tcode{obj}. + +\pnum +\throws +Nothing. +\end{itemdescr} + +\indexlibraryctor{atomic_ref}% +\indexlibraryctor{atomic_ref}% +\indexlibrary{\idxcode{atomic_ref<\placeholder{integral}>}!constructor}% +\indexlibrary{\idxcode{atomic_ref<\placeholder{floating-point}>}!constructor}% +\begin{itemdecl} +atomic_ref(const atomic_ref& ref) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures +\tcode{*this} references the object referenced by \tcode{ref}. +\end{itemdescr} + +\indexlibrarymember{store}{atomic_ref}% +\indexlibrarymember{store}{atomic_ref}% +\indexlibrarymember{store}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{store}{atomic_ref<\placeholder{floating-point}>}% +\begin{itemdecl} +void store(T desired, memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +The \tcode{order} argument is neither +\tcode{memory_order::consume}, +\tcode{memory_order::acquire}, nor +\tcode{memory_order::acq_rel}. + +\pnum +\effects +Atomically replaces the value referenced by \tcode{*ptr} +with the value of \tcode{desired}. +Memory is affected according to the value of \tcode{order}. +\end{itemdescr} + +\indexlibrarymember{operator=}{atomic_ref}% +\indexlibrarymember{operator=}{atomic_ref}% +\indexlibrarymember{operator=}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{operator=}{atomic_ref<\placeholder{floating-point}>}% +\begin{itemdecl} +T operator=(T desired) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +store(desired); +return desired; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{load}{atomic_ref}% +\indexlibrarymember{load}{atomic_ref}% +\indexlibrarymember{load}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{load}{atomic_ref<\placeholder{floating-point}>}% +\begin{itemdecl} +T load(memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +The \tcode{order} argument is neither +\tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Memory is affected according to the value of \tcode{order}. + +\pnum +\returns +Atomically returns the value referenced by \tcode{*ptr}. +\end{itemdescr} + +\indexlibrarymember{operator \placeholder{type}}{atomic_ref}% +\indexlibrarymember{operator T*}{atomic_ref}% +\indexlibrarymember{operator \placeholder{integral}}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{operator \placeholder{floating-point}}{atomic_ref<\placeholder{floating-point}>}% +\begin{itemdecl} +operator T() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return load();} +\end{itemdescr} + +\indexlibrarymember{exchange}{atomic_ref}% +\indexlibrarymember{exchange}{atomic_ref}% +\indexlibrarymember{exchange}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{exchange}{atomic_ref<\placeholder{floating-point}>}% +\begin{itemdecl} +T exchange(T desired, memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Atomically replaces the value referenced by \tcode{*ptr} +with \tcode{desired}. +Memory is affected according to the value of \tcode{order}. +This operation is an atomic read-modify-write operation\iref{intro.multithread}. + +\pnum +\returns +Atomically returns the value referenced by \tcode{*ptr} +immediately before the effects. +\end{itemdescr} + +\indexlibrarymember{compare_exchange_weak}{atomic_ref}% +\indexlibrarymember{compare_exchange_weak}{atomic_ref}% +\indexlibrarymember{compare_exchange_weak}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{compare_exchange_weak}{atomic_ref<\placeholder{floating-point}>}% +\indexlibrarymember{compare_exchange_strong}{atomic_ref}% +\indexlibrarymember{compare_exchange_strong}{atomic_ref}% +\indexlibrarymember{compare_exchange_strong}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{compare_exchange_strong}{atomic_ref<\placeholder{floating-point}>}% +\begin{itemdecl} +bool compare_exchange_weak(T& expected, T desired, + memory_order success, memory_order failure) const noexcept; + +bool compare_exchange_strong(T& expected, T desired, + memory_order success, memory_order failure) const noexcept; + +bool compare_exchange_weak(T& expected, T desired, + memory_order order = memory_order::seq_cst) const noexcept; + +bool compare_exchange_strong(T& expected, T desired, + memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +The \tcode{failure} argument is neither +\tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Retrieves the value in \tcode{expected}. +It then atomically compares the value representation of +the value referenced by \tcode{*ptr} for equality +with that previously retrieved from \tcode{expected}, +and if \tcode{true}, replaces the value referenced by \tcode{*ptr} +with that in \tcode{desired}. +If and only if the comparison is \tcode{true}, +memory is affected according to the value of \tcode{success}, and +if the comparison is \tcode{false}, +memory is affected according to the value of \tcode{failure}. +When only one \tcode{memory_order} argument is supplied, +the value of \tcode{success} is \tcode{order}, and +the value of \tcode{failure} is \tcode{order} +except that a value of \tcode{memory_order::acq_rel} shall be replaced by +the value \tcode{memory_order::acquire} and +a value of \tcode{memory_order::release} shall be replaced by +the value \tcode{memory_order::relaxed}. +If and only if the comparison is \tcode{false} then, +after the atomic operation, +the value in \tcode{expected} is replaced by +the value read from the value referenced by \tcode{*ptr} +during the atomic comparison. +If the operation returns \tcode{true}, +these operations are atomic read-modify-write operations\iref{intro.races} +on the value referenced by \tcode{*ptr}. +Otherwise, these operations are atomic load operations on that memory. + +\pnum +\returns +The result of the comparison. + +\pnum +\remarks +A weak compare-and-exchange operation may fail spuriously. +That is, even when the contents of memory referred to +by \tcode{expected} and \tcode{ptr} are equal, +it may return \tcode{false} and +store back to \tcode{expected} the same memory contents +that were originally there. +\begin{note} +This spurious failure enables implementation of compare-and-exchange +on a broader class of machines, e.g., load-locked store-conditional machines. +A consequence of spurious failure is +that nearly all uses of weak compare-and-exchange will be in a loop. +When a compare-and-exchange is in a loop, +the weak version will yield better performance on some platforms. +When a weak compare-and-exchange would require a loop and +a strong one would not, the strong one is preferable. +\end{note} +\end{itemdescr} + +\indexlibrarymember{wait}{atomic_ref}% +\begin{itemdecl} +void wait(T old, memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{order} is +neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Repeatedly performs the following steps, in order: +\begin{itemize} +\item + Evaluates \tcode{load(order)} and + compares its value representation for equality against that of \tcode{old}. +\item + If they compare unequal, returns. +\item + Blocks until it + is unblocked by an atomic notifying operation or is unblocked spuriously. +\end{itemize} + +\pnum +\remarks +This function is an atomic waiting operation\iref{atomics.wait} +on atomic object \tcode{*ptr}. +\end{itemdescr} + +\indexlibrarymember{notify_one}{atomic_ref}% +\begin{itemdecl} +void notify_one() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of at least one atomic waiting operation on \tcode{*ptr} +that is eligible to be unblocked\iref{atomics.wait} by this call, +if any such atomic waiting operations exist. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait} +on atomic object \tcode{*ptr}. +\end{itemdescr} + +\indexlibrarymember{notify_all}{atomic_ref}% +\begin{itemdecl} +void notify_all() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of all atomic waiting operations on \tcode{*ptr} +that are eligible to be unblocked\iref{atomics.wait} by this call. + +\pnum +\remarks + This function is an atomic notifying operation\iref{atomics.wait} + on atomic object \tcode{*ptr}. +\end{itemdescr} + +\rSec3[atomics.ref.int]{Specializations for integral types} + +\pnum +\indexlibrary{\idxcode{atomic_ref<\placeholder{integral}>}}% +There are specializations of the \tcode{atomic_ref} class template +for the integral types +\tcode{char}, +\tcode{signed char}, +\tcode{unsigned char}, +\tcode{short}, +\tcode{unsigned short}, +\tcode{int}, +\tcode{unsigned int}, +\tcode{long}, +\tcode{unsigned long}, +\tcode{long long}, +\tcode{unsigned long long}, +\keyword{char8_t}, +\keyword{char16_t}, +\keyword{char32_t}, +\keyword{wchar_t}, +and any other types needed by the typedefs in the header \libheaderref{cstdint}. +For each such type \tcode{\placeholder{integral}}, +the specialization \tcode{atomic_ref<\placeholder{integral}>} provides +additional atomic operations appropriate to integral types. +\begin{note} +The specialization \tcode{atomic_ref} +uses the primary template\iref{atomics.ref.generic}. +\end{note} + +\begin{codeblock} +namespace std { + template<> struct atomic_ref<@\placeholder{integral}@> { + private: + @\placeholder{integral}@* ptr; // \expos + public: + using value_type = @\placeholder{integral}@; + using difference_type = value_type; + static constexpr size_t required_alignment = @\impdefx{required alignment for \tcode{atomic_ref} type's operations}@; + + static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic_ref} type's operations are always lock free}@; + bool is_lock_free() const noexcept; + + explicit atomic_ref(@\placeholder{integral}@&); + atomic_ref(const atomic_ref&) noexcept; + atomic_ref& operator=(const atomic_ref&) = delete; + + void store(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) const noexcept; + @\placeholdernc{integral}@ operator=(@\placeholder{integral}@) const noexcept; + @\placeholdernc{integral}@ load(memory_order = memory_order::seq_cst) const noexcept; + operator @\placeholdernc{integral}@() const noexcept; + + @\placeholdernc{integral}@ exchange(@\placeholdernc{integral}@, + memory_order = memory_order::seq_cst) const noexcept; + bool compare_exchange_weak(@\placeholder{integral}@&, @\placeholder{integral}@, + memory_order, memory_order) const noexcept; + bool compare_exchange_strong(@\placeholder{integral}@&, @\placeholder{integral}@, + memory_order, memory_order) const noexcept; + bool compare_exchange_weak(@\placeholder{integral}@&, @\placeholder{integral}@, + memory_order = memory_order::seq_cst) const noexcept; + bool compare_exchange_strong(@\placeholder{integral}@&, @\placeholder{integral}@, + memory_order = memory_order::seq_cst) const noexcept; + + @\placeholdernc{integral}@ fetch_add(@\placeholdernc{integral}@, + memory_order = memory_order::seq_cst) const noexcept; + @\placeholdernc{integral}@ fetch_sub(@\placeholdernc{integral}@, + memory_order = memory_order::seq_cst) const noexcept; + @\placeholdernc{integral}@ fetch_and(@\placeholdernc{integral}@, + memory_order = memory_order::seq_cst) const noexcept; + @\placeholdernc{integral}@ fetch_or(@\placeholdernc{integral}@, + memory_order = memory_order::seq_cst) const noexcept; + @\placeholdernc{integral}@ fetch_xor(@\placeholdernc{integral}@, + memory_order = memory_order::seq_cst) const noexcept; + + @\placeholdernc{integral}@ operator++(int) const noexcept; + @\placeholdernc{integral}@ operator--(int) const noexcept; + @\placeholdernc{integral}@ operator++() const noexcept; + @\placeholdernc{integral}@ operator--() const noexcept; + @\placeholdernc{integral}@ operator+=(@\placeholdernc{integral}@) const noexcept; + @\placeholdernc{integral}@ operator-=(@\placeholdernc{integral}@) const noexcept; + @\placeholdernc{integral}@ operator&=(@\placeholdernc{integral}@) const noexcept; + @\placeholdernc{integral}@ operator|=(@\placeholdernc{integral}@) const noexcept; + @\placeholdernc{integral}@ operator^=(@\placeholdernc{integral}@) const noexcept; + + void wait(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() const noexcept; + void notify_all() const noexcept; + }; +} +\end{codeblock} + +\pnum +Descriptions are provided below only for members +that differ from the primary template. + +\pnum +The following operations perform arithmetic computations. +The correspondence among key, operator, and computation is specified +in \tref{atomic.types.int.comp}. + +\indexlibrarymember{fetch_add}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{fetch_and}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{fetch_or}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{fetch_sub}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{fetch_xor}{atomic_ref<\placeholder{integral}>}% +\begin{itemdecl} +@\placeholdernc{integral}@ fetch_@\placeholdernc{key}@(@\placeholdernc{integral}@ operand, memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Atomically replaces the value referenced by \tcode{*ptr} with +the result of the computation applied to the value referenced by \tcode{*ptr} +and the given operand. +Memory is affected according to the value of \tcode{order}. +These operations are atomic read-modify-write operations\iref{intro.races}. + +\pnum +\returns +Atomically, the value referenced by \tcode{*ptr} +immediately before the effects. + +\pnum +\indextext{signed integer representation!two's complement}% +\remarks +For signed integer types, +the result is as if the object value and parameters +were converted to their corresponding unsigned types, +the computation performed on those types, and +the result converted back to the signed type. +\begin{note} +There are no undefined results arising from the computation. +\end{note} +\end{itemdescr} + +\indexlibrarymember{operator+=}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{operator-=}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{operator\&=}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{operator"|=}{atomic_ref<\placeholder{integral}>}% +\indexlibrarymember{operator\caret=}{atomic_ref<\placeholder{integral}>}% +\begin{itemdecl} +@\placeholdernc{integral}@ operator @\placeholder{op}@=(@\placeholdernc{integral}@ operand) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return fetch_\placeholdernc{key}(operand) \placeholder{op} operand;} +\end{itemdescr} + +\rSec3[atomics.ref.float]{Specializations for floating-point types} + +\pnum +\indexlibrary{\idxcode{atomic_ref<\placeholder{floating-point}>}}% +There are specializations of the \tcode{atomic_ref} class template +for the floating-point types +\tcode{float}, +\tcode{double}, and +\tcode{long double}. +For each such type \tcode{\placeholder{floating-point}}, +the specialization \tcode{atomic_ref<\placeholder{floating-\-point}>} provides +additional atomic operations appropriate to floating-point types. + +\begin{codeblock} +namespace std { + template<> struct atomic_ref<@\placeholder{floating-point}@> { + private: + @\placeholder{floating-point}@* ptr; // \expos + public: + using value_type = @\placeholder{floating-point}@; + using difference_type = value_type; + static constexpr size_t required_alignment = @\impdefx{required alignment for \tcode{atomic_ref} type's operations}@; + + static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic_ref} type's operations are always lock free}@; + bool is_lock_free() const noexcept; + + explicit atomic_ref(@\placeholder{floating-point}@&); + atomic_ref(const atomic_ref&) noexcept; + atomic_ref& operator=(const atomic_ref&) = delete; + + void store(@\placeholdernc{floating-point}@, memory_order = memory_order::seq_cst) const noexcept; + @\placeholder{floating-point}@ operator=(@\placeholder{floating-point}@) const noexcept; + @\placeholder{floating-point}@ load(memory_order = memory_order::seq_cst) const noexcept; + operator @\placeholdernc{floating-point}@() const noexcept; + + @\placeholder{floating-point}@ exchange(@\placeholdernc{floating-point}@, + memory_order = memory_order::seq_cst) const noexcept; + bool compare_exchange_weak(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, + memory_order, memory_order) const noexcept; + bool compare_exchange_strong(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, + memory_order, memory_order) const noexcept; + bool compare_exchange_weak(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, + memory_order = memory_order::seq_cst) const noexcept; + bool compare_exchange_strong(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, + memory_order = memory_order::seq_cst) const noexcept; + + @\placeholder{floating-point}@ fetch_add(@\placeholdernc{floating-point}@, + memory_order = memory_order::seq_cst) const noexcept; + @\placeholder{floating-point}@ fetch_sub(@\placeholdernc{floating-point}@, + memory_order = memory_order::seq_cst) const noexcept; + + @\placeholder{floating-point}@ operator+=(@\placeholder{floating-point}@) const noexcept; + @\placeholder{floating-point}@ operator-=(@\placeholder{floating-point}@) const noexcept; + + void wait(@\placeholdernc{floating-point}@, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() const noexcept; + void notify_all() const noexcept; + }; +} +\end{codeblock} + +\pnum +Descriptions are provided below only for members +that differ from the primary template. + +\pnum +The following operations perform arithmetic computations. +The correspondence among key, operator, and computation is specified +in \tref{atomic.types.int.comp}. + +\indexlibrarymember{fetch_add}{atomic_ref<\placeholder{floating-point}>}% +\indexlibrarymember{fetch_sub}{atomic_ref<\placeholder{floating-point}>}% +\begin{itemdecl} +@\placeholder{floating-point}@ fetch_@\placeholdernc{key}@(@\placeholder{floating-point}@ operand, + memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Atomically replaces the value referenced by \tcode{*ptr} with +the result of the computation applied to the value referenced by \tcode{*ptr} +and the given operand. +Memory is affected according to the value of \tcode{order}. +These operations are atomic read-modify-write operations\iref{intro.races}. + +\pnum +\returns +Atomically, the value referenced by \tcode{*ptr} +immediately before the effects. + +\pnum +\remarks +If the result is not a representable value for its type\iref{expr.pre}, +the result is unspecified, +but the operations otherwise have no undefined behavior. +Atomic arithmetic operations on \tcode{\placeholder{floating-point}} should conform to +the \tcode{std::numeric_limits<\placeholder{floating-point}>} traits +associated with the floating-point type\iref{limits.syn}. +The floating-point environment\iref{cfenv} +for atomic arithmetic operations on \tcode{\placeholder{floating-point}} +may be different than the calling thread's floating-point environment. +\end{itemdescr} + +\indexlibrarymember{operator+=}{atomic_ref<\placeholder{floating-point}>}% +\indexlibrarymember{operator-=}{atomic_ref<\placeholder{floating-point}>}% +\begin{itemdecl} +@\placeholder{floating-point}@ operator @\placeholder{op}@=(@\placeholder{floating-point}@ operand) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return fetch_\placeholder{key}(operand) \placeholdernc{op} operand;} +\end{itemdescr} + +\rSec3[atomics.ref.pointer]{Partial specialization for pointers} +\indexlibraryglobal{atomic_ref}% + +\begin{codeblock} +namespace std { + template struct atomic_ref { + private: + T** ptr; // \expos + public: + using value_type = T*; + using difference_type = ptrdiff_t; + static constexpr size_t required_alignment = @\impdefx{required alignment for \tcode{atomic_ref} type's operations}@; + + static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic_ref} type's operations are always lock free}@; + bool is_lock_free() const noexcept; + + explicit atomic_ref(T*&); + atomic_ref(const atomic_ref&) noexcept; + atomic_ref& operator=(const atomic_ref&) = delete; + + void store(T*, memory_order = memory_order::seq_cst) const noexcept; + T* operator=(T*) const noexcept; + T* load(memory_order = memory_order::seq_cst) const noexcept; + operator T*() const noexcept; + + T* exchange(T*, memory_order = memory_order::seq_cst) const noexcept; + bool compare_exchange_weak(T*&, T*, + memory_order, memory_order) const noexcept; + bool compare_exchange_strong(T*&, T*, + memory_order, memory_order) const noexcept; + bool compare_exchange_weak(T*&, T*, + memory_order = memory_order::seq_cst) const noexcept; + bool compare_exchange_strong(T*&, T*, + memory_order = memory_order::seq_cst) const noexcept; + + T* fetch_add(difference_type, memory_order = memory_order::seq_cst) const noexcept; + T* fetch_sub(difference_type, memory_order = memory_order::seq_cst) const noexcept; + + T* operator++(int) const noexcept; + T* operator--(int) const noexcept; + T* operator++() const noexcept; + T* operator--() const noexcept; + T* operator+=(difference_type) const noexcept; + T* operator-=(difference_type) const noexcept; + + void wait(T*, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() const noexcept; + void notify_all() const noexcept; + }; +} +\end{codeblock} + +\pnum +Descriptions are provided below only for members +that differ from the primary template. + +\pnum +The following operations perform arithmetic computations. +The correspondence among key, operator, and computation is specified +in \tref{atomic.types.pointer.comp}. + +\indexlibrarymember{fetch_add}{atomic_ref}% +\indexlibrarymember{fetch_sub}{atomic_ref}% +\begin{itemdecl} +T* fetch_@\placeholdernc{key}@(difference_type operand, memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{T} is a complete object type. + +\pnum +\effects +Atomically replaces the value referenced by \tcode{*ptr} with +the result of the computation applied to the value referenced by \tcode{*ptr} +and the given operand. +Memory is affected according to the value of \tcode{order}. +These operations are atomic read-modify-write operations\iref{intro.races}. + +\pnum +\returns +Atomically, the value referenced by \tcode{*ptr} +immediately before the effects. + +\pnum +\remarks +The result may be an undefined address, +but the operations otherwise have no undefined behavior. +\end{itemdescr} + +\indexlibrarymember{operator+=}{atomic_ref}% +\indexlibrarymember{operator-=}{atomic_ref}% +\begin{itemdecl} +T* operator @\placeholder{op}@=(difference_type operand) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return fetch_\placeholder{key}(operand) \placeholdernc{op} operand;} +\end{itemdescr} + +\rSec3[atomics.ref.memop]{Member operators + common to integers and pointers to objects} + +\indexlibrarymember{operator++}{atomic_ref}% +\indexlibrarymember{operator++}{atomic_ref<\placeholder{integral}>}% +\begin{itemdecl} +value_type operator++(int) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return fetch_add(1);} +\end{itemdescr} + +\indexlibrarymember{operator--}{atomic_ref}% +\indexlibrarymember{operator--}{atomic_ref<\placeholder{integral}>}% +\begin{itemdecl} +value_type operator--(int) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return fetch_sub(1);} +\end{itemdescr} + +\indexlibrarymember{operator++}{atomic_ref}% +\indexlibrarymember{operator++}{atomic_ref<\placeholder{integral}>}% +\begin{itemdecl} +value_type operator++() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return fetch_add(1) + 1;} +\end{itemdescr} + +\indexlibrarymember{operator--}{atomic_ref}% +\indexlibrarymember{operator--}{atomic_ref<\placeholder{integral}>}% +\begin{itemdecl} +value_type operator--() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return fetch_sub(1) - 1;} +\end{itemdescr} + +\rSec2[atomics.types.generic]{Class template \tcode{atomic}} + +\rSec3[atomics.types.generic.general]{General} + +\indexlibraryglobal{atomic}% +\indexlibrarymember{value_type}{atomic}% +\begin{codeblock} +namespace std { + template struct atomic { + using value_type = T; + + static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; + bool is_lock_free() const volatile noexcept; + bool is_lock_free() const noexcept; + + // \ref{atomics.types.operations}, operations on atomic types + constexpr atomic() noexcept(is_nothrow_default_constructible_v); + constexpr atomic(T) noexcept; + atomic(const atomic&) = delete; + atomic& operator=(const atomic&) = delete; + atomic& operator=(const atomic&) volatile = delete; + + T load(memory_order = memory_order::seq_cst) const volatile noexcept; + T load(memory_order = memory_order::seq_cst) const noexcept; + operator T() const volatile noexcept; + operator T() const noexcept; + void store(T, memory_order = memory_order::seq_cst) volatile noexcept; + void store(T, memory_order = memory_order::seq_cst) noexcept; + T operator=(T) volatile noexcept; + T operator=(T) noexcept; + + T exchange(T, memory_order = memory_order::seq_cst) volatile noexcept; + T exchange(T, memory_order = memory_order::seq_cst) noexcept; + bool compare_exchange_weak(T&, T, memory_order, memory_order) volatile noexcept; + bool compare_exchange_weak(T&, T, memory_order, memory_order) noexcept; + bool compare_exchange_strong(T&, T, memory_order, memory_order) volatile noexcept; + bool compare_exchange_strong(T&, T, memory_order, memory_order) noexcept; + bool compare_exchange_weak(T&, T, memory_order = memory_order::seq_cst) volatile noexcept; + bool compare_exchange_weak(T&, T, memory_order = memory_order::seq_cst) noexcept; + bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) volatile noexcept; + bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) noexcept; + + void wait(T, memory_order = memory_order::seq_cst) const volatile noexcept; + void wait(T, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() volatile noexcept; + void notify_one() noexcept; + void notify_all() volatile noexcept; + void notify_all() noexcept; + }; +} +\end{codeblock} + +\indexlibraryglobal{atomic}% +\pnum +The template argument for \tcode{T} shall meet the +\oldconcept{CopyConstructible} and \oldconcept{CopyAssignable} requirements. +The program is ill-formed if any of +\begin{itemize} +\item \tcode{is_trivially_copyable_v}, +\item \tcode{is_copy_constructible_v}, +\item \tcode{is_move_constructible_v}, +\item \tcode{is_copy_assignable_v}, or +\item \tcode{is_move_assignable_v} +\end{itemize} +is \tcode{false}. +\begin{note} +Type arguments that are +not also statically initializable can be difficult to use. +\end{note} + +\pnum +The specialization \tcode{atomic} is a standard-layout struct. + +\pnum +\begin{note} +The representation of an atomic specialization +need not have the same size and alignment requirement as +its corresponding argument type. +\end{note} + +\rSec3[atomics.types.operations]{Operations on atomic types} + +\indexlibraryctor{atomic}% +\indexlibraryctor{atomic}% +\indexlibrary{\idxcode{atomic<\placeholder{integral}>}!constructor}% +\indexlibrary{\idxcode{atomic<\placeholder{floating-point}>}!constructor}% +\begin{itemdecl} +constexpr atomic() noexcept(is_nothrow_default_constructible_v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{is_default_constructible_v} is \tcode{true}. + +\pnum +\effects +Initializes the atomic object with the value of \tcode{T()}. +Initialization is not an atomic operation\iref{intro.multithread}. +\end{itemdescr} + +\indexlibraryctor{atomic}% +\indexlibraryctor{atomic}% +\indexlibrary{\idxcode{atomic<\placeholder{integral}>}!constructor}% +\indexlibrary{\idxcode{atomic<\placeholder{floating-point}>}!constructor}% +\begin{itemdecl} +constexpr atomic(T desired) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the object with the value \tcode{desired}. +Initialization is not an atomic operation\iref{intro.multithread}. +\begin{note} +It is possible to have an access to an atomic object \tcode{A} +race with its construction, for example by communicating the address of the +just-constructed object \tcode{A} to another thread via +\tcode{memory_order::relaxed} operations on a suitable atomic pointer +variable, and then immediately accessing \tcode{A} in the receiving thread. +This results in undefined behavior. +\end{note} +\end{itemdescr} + +\indexlibrarymember{is_always_lock_free}{atomic}% +\indexlibrarymember{is_always_lock_free}{atomic}% +\indexlibrarymember{is_always_lock_free}{atomic<\placeholder{integral}>}% +\indexlibrarymember{is_always_lock_free}{atomic<\placeholder{floating-point}>}% +\indexlibrarymember{is_always_lock_free}{atomic>}% +\indexlibrarymember{is_always_lock_free}{atomic>}% +\begin{itemdecl} +static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The \keyword{static} data member \tcode{is_always_lock_free} is \tcode{true} +if the atomic type's operations are always lock-free, and \tcode{false} otherwise. +\begin{note} +The value of \tcode{is_always_lock_free} is consistent with the value of +the corresponding \tcode{ATOMIC_..._LOCK_FREE} macro, if defined. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{atomic_is_lock_free}% +\indexlibrarymember{is_lock_free}{atomic}% +\indexlibrarymember{is_lock_free}{atomic}% +\indexlibrarymember{is_lock_free}{atomic<\placeholder{integral}>}% +\indexlibrarymember{is_lock_free}{atomic<\placeholder{floating-point}>}% +\indexlibrarymember{is_lock_free}{atomic>}% +\indexlibrarymember{is_lock_free}{atomic>}% +\begin{itemdecl} +bool is_lock_free() const volatile noexcept; +bool is_lock_free() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if the object's operations are lock-free, \tcode{false} otherwise. +\begin{note} +The return value of the \tcode{is_lock_free} member function +is consistent with the value of \tcode{is_always_lock_free} for the same type. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{atomic_store}% +\indexlibraryglobal{atomic_store_explicit}% +\indexlibrarymember{store}{atomic}% +\indexlibrarymember{store}{atomic}% +\indexlibrarymember{store}{atomic<\placeholder{integral}>}% +\indexlibrarymember{store}{atomic<\placeholder{floating-point}>}% +\begin{itemdecl} +void store(T desired, memory_order order = memory_order::seq_cst) volatile noexcept; +void store(T desired, memory_order order = memory_order::seq_cst) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the \tcode{volatile} overload of this function, +\tcode{is_always_lock_free} is \tcode{true}. + +\pnum +\expects +The \tcode{order} argument is neither \tcode{memory_order::consume}, +\tcode{memory_order::acquire}, nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Atomically replaces the value pointed to by \keyword{this} +with the value of \tcode{desired}. Memory is affected according to the value of +\tcode{order}. +\end{itemdescr} + +\indexlibrarymember{operator=}{atomic}% +\indexlibrarymember{operator=}{atomic}% +\indexlibrarymember{operator=}{atomic<\placeholder{integral}>}% +\indexlibrarymember{operator=}{atomic<\placeholder{floating-point}>}% +\begin{itemdecl} +T operator=(T desired) volatile noexcept; +T operator=(T desired) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the \tcode{volatile} overload of this function, +\tcode{is_always_lock_free} is \tcode{true}. + +\pnum +\effects +Equivalent to \tcode{store(desired)}. + +\pnum +\returns +\tcode{desired}. +\end{itemdescr} + +\indexlibraryglobal{atomic_load}% +\indexlibraryglobal{atomic_load_explicit}% +\indexlibrarymember{load}{atomic}% +\indexlibrarymember{load}{atomic}% +\indexlibrarymember{load}{atomic<\placeholder{integral}>}% +\indexlibrarymember{load}{atomic<\placeholder{floating-point}>}% +\begin{itemdecl} +T load(memory_order order = memory_order::seq_cst) const volatile noexcept; +T load(memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the \tcode{volatile} overload of this function, +\tcode{is_always_lock_free} is \tcode{true}. + +\pnum +\expects +The \tcode{order} argument is neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Memory is affected according to the value of \tcode{order}. + +\pnum +\returns +Atomically returns the value pointed to by \keyword{this}. +\end{itemdescr} + +\indexlibrarymember{operator \placeholder{type}}{atomic}% +\indexlibrarymember{operator T*}{atomic}% +\indexlibrarymember{operator \placeholder{integral}}{atomic<\placeholder{integral}>}% +\indexlibrarymember{operator \placeholder{floating-point}}{atomic<\placeholder{floating-point}>}% +\begin{itemdecl} +operator T() const volatile noexcept; +operator T() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the \tcode{volatile} overload of this function, +\tcode{is_always_lock_free} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return load();} +\end{itemdescr} + + +\indexlibraryglobal{atomic_exchange}% +\indexlibraryglobal{atomic_exchange_explicit}% +\indexlibrarymember{exchange}{atomic}% +\indexlibrarymember{exchange}{atomic}% +\indexlibrarymember{exchange}{atomic<\placeholder{integral}>}% +\indexlibrarymember{exchange}{atomic<\placeholder{floating-point}>}% +\begin{itemdecl} +T exchange(T desired, memory_order order = memory_order::seq_cst) volatile noexcept; +T exchange(T desired, memory_order order = memory_order::seq_cst) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the \tcode{volatile} overload of this function, +\tcode{is_always_lock_free} is \tcode{true}. + +\pnum +\effects +Atomically replaces the value pointed to by \keyword{this} +with \tcode{desired}. +Memory is affected according to the value of \tcode{order}. +These operations are atomic read-modify-write operations\iref{intro.multithread}. + +\pnum +\returns +Atomically returns the value pointed to by \keyword{this} immediately before the effects. +\end{itemdescr} + +\indexlibraryglobal{atomic_compare_exchange_weak}% +\indexlibraryglobal{atomic_compare_exchange_strong}% +\indexlibraryglobal{atomic_compare_exchange_weak_explicit}% +\indexlibraryglobal{atomic_compare_exchange_strong_explicit}% +\indexlibrarymember{compare_exchange_weak}{atomic}% +\indexlibrarymember{compare_exchange_weak}{atomic}% +\indexlibrarymember{compare_exchange_weak}{atomic<\placeholder{integral}>}% +\indexlibrarymember{compare_exchange_weak}{atomic<\placeholder{floating-point}>}% +\indexlibrarymember{compare_exchange_strong}{atomic}% +\indexlibrarymember{compare_exchange_strong}{atomic}% +\indexlibrarymember{compare_exchange_strong}{atomic<\placeholder{integral}>}% +\indexlibrarymember{compare_exchange_strong}{atomic<\placeholder{floating-point}>}% +\begin{itemdecl} +bool compare_exchange_weak(T& expected, T desired, + memory_order success, memory_order failure) volatile noexcept; +bool compare_exchange_weak(T& expected, T desired, + memory_order success, memory_order failure) noexcept; +bool compare_exchange_strong(T& expected, T desired, + memory_order success, memory_order failure) volatile noexcept; +bool compare_exchange_strong(T& expected, T desired, + memory_order success, memory_order failure) noexcept; +bool compare_exchange_weak(T& expected, T desired, + memory_order order = memory_order::seq_cst) volatile noexcept; +bool compare_exchange_weak(T& expected, T desired, + memory_order order = memory_order::seq_cst) noexcept; +bool compare_exchange_strong(T& expected, T desired, + memory_order order = memory_order::seq_cst) volatile noexcept; +bool compare_exchange_strong(T& expected, T desired, + memory_order order = memory_order::seq_cst) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the \tcode{volatile} overload of this function, +\tcode{is_always_lock_free} is \tcode{true}. + +\pnum +\expects +The \tcode{failure} argument is neither \tcode{memory_order::release} nor +\tcode{memory_order::acq_rel}. + +\pnum +\effects +Retrieves the value in \tcode{expected}. It then atomically +compares the value representation of the value pointed to by \keyword{this} +for equality with that previously retrieved from \tcode{expected}, +and if true, replaces the value pointed to +by \keyword{this} with that in \tcode{desired}. +If and only if the comparison is \tcode{true}, memory is affected according to the +value of \tcode{success}, and if the comparison is false, memory is affected according +to the value of \tcode{failure}. When only one \tcode{memory_order} argument is +supplied, the value of \tcode{success} is \tcode{order}, and the value of +\tcode{failure} is \tcode{order} except that a value of \tcode{memory_order::acq_rel} +shall be replaced by the value \tcode{memory_order::acquire} and a value of +\tcode{memory_order::release} shall be replaced by the value +\tcode{memory_order::relaxed}. +If and only if the comparison is false then, after the atomic operation, +the value in \tcode{expected} is replaced by the value +pointed to by \keyword{this} during the atomic comparison. +If the operation returns \tcode{true}, these +operations are atomic read-modify-write +operations\iref{intro.multithread} on the memory +pointed to by \keyword{this}. +Otherwise, these operations are atomic load operations on that memory. + +\pnum +\returns +The result of the comparison. + +\pnum +\begin{note} +For example, the effect of +\tcode{compare_exchange_strong} +on objects without padding bits\iref{term.padding.bits} is +\begin{codeblock} +if (memcmp(this, &expected, sizeof(*this)) == 0) + memcpy(this, &desired, sizeof(*this)); +else + memcpy(&expected, this, sizeof(*this)); +\end{codeblock} +\end{note} +\begin{example} +The expected use of the compare-and-exchange operations is as follows. The +compare-and-exchange operations will update \tcode{expected} when another iteration of +the loop is needed. +\begin{codeblock} +expected = current.load(); +do { + desired = function(expected); +} while (!current.compare_exchange_weak(expected, desired)); +\end{codeblock} +\end{example} +\begin{example} +Because the expected value is updated only on failure, +code releasing the memory containing the \tcode{expected} value on success will work. +For example, list head insertion will act atomically and would not introduce a +data race in the following code: +\begin{codeblock} +do { + p->next = head; // make new list node point to the current head +} while (!head.compare_exchange_weak(p->next, p)); // try to insert +\end{codeblock} +\end{example} + +\pnum +Implementations should ensure that weak compare-and-exchange operations do not +consistently return \tcode{false} unless either the atomic object has value +different from \tcode{expected} or there are concurrent modifications to the +atomic object. + +\pnum +\remarks +A weak compare-and-exchange operation may fail spuriously. That is, even when +the contents of memory referred to by \tcode{expected} and \keyword{this} are +equal, it may return \tcode{false} and store back to \tcode{expected} the same memory +contents that were originally there. +\begin{note} +This +spurious failure enables implementation of compare-and-exchange on a broader class of +machines, e.g., load-locked store-conditional machines. A +consequence of spurious failure is that nearly all uses of weak compare-and-exchange +will be in a loop. +When a compare-and-exchange is in a loop, the weak version will yield better performance +on some platforms. When a weak compare-and-exchange would require a loop and a strong one +would not, the strong one is preferable. +\end{note} + +\pnum +\begin{note} +Under cases where the \tcode{memcpy} and \tcode{memcmp} semantics of the compare-and-exchange +operations apply, the comparisons can fail for values that compare equal with +\tcode{operator==} if the value representation has trap bits or alternate +representations of the same value. Notably, on implementations conforming to +ISO/IEC/IEEE 60559, floating-point \tcode{-0.0} and \tcode{+0.0} +will not compare equal with \tcode{memcmp} but will compare equal with \tcode{operator==}, +and NaNs with the same payload will compare equal with \tcode{memcmp} but will not +compare equal with \tcode{operator==}. +\end{note} +\begin{note} +Because compare-and-exchange acts on an object's value representation, +padding bits that never participate in the object's value representation +are ignored. As a consequence, the following code is guaranteed to avoid +spurious failure: +\begin{codeblock} +struct padded { + char clank = 0x42; + // Padding here. + unsigned biff = 0xC0DEFEFE; +}; +atomic pad = {}; + +bool zap() { + padded expected, desired{0, 0}; + return pad.compare_exchange_strong(expected, desired); +} +\end{codeblock} +\end{note} +\begin{note} +For a union with bits that participate in the value representation +of some members but not others, compare-and-exchange might always fail. +This is because such padding bits have an indeterminate value when they +do not participate in the value representation of the active member. +As a consequence, the following code is not guaranteed to ever succeed: +\begin{codeblock} +union pony { + double celestia = 0.; + short luna; // padded +}; +atomic princesses = {}; + +bool party(pony desired) { + pony expected; + return princesses.compare_exchange_strong(expected, desired); +} +\end{codeblock} +\end{note} +\end{itemdescr} + +\indexlibrarymember{wait}{atomic}% +\indexlibrarymember{wait}{atomic}% +\indexlibrarymember{wait}{atomic<\placeholder{integral}>}% +\indexlibrarymember{wait}{atomic<\placeholder{floating-point}>}% +\begin{itemdecl} +void wait(T old, memory_order order = memory_order::seq_cst) const volatile noexcept; +void wait(T old, memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{order} is neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Repeatedly performs the following steps, in order: +\begin{itemize} +\item + Evaluates \tcode{load(order)} and + compares its value representation for equality against that of \tcode{old}. +\item + If they compare unequal, returns. +\item + Blocks until it + is unblocked by an atomic notifying operation or is unblocked spuriously. +\end{itemize} + +\pnum +\remarks +This function is an atomic waiting operation\iref{atomics.wait}. +\end{itemdescr} + +\indexlibrarymember{notify_one}{atomic}% +\indexlibrarymember{notify_one}{atomic}% +\indexlibrarymember{notify_one}{atomic<\placeholder{integral}>}% +\indexlibrarymember{notify_one}{atomic<\placeholder{floating-point}>}% +\begin{itemdecl} +void notify_one() volatile noexcept; +void notify_one() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of at least one atomic waiting operation +that is eligible to be unblocked\iref{atomics.wait} by this call, +if any such atomic waiting operations exist. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait}. +\end{itemdescr} + +\indexlibrarymember{notify_all}{atomic}% +\indexlibrarymember{notify_all}{atomic}% +\indexlibrarymember{notify_all}{atomic<\placeholder{integral}>}% +\indexlibrarymember{notify_all}{atomic<\placeholder{floating-point}>}% +\begin{itemdecl} +void notify_all() volatile noexcept; +void notify_all() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of all atomic waiting operations +that are eligible to be unblocked\iref{atomics.wait} by this call. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait}. +\end{itemdescr} + +\rSec3[atomics.types.int]{Specializations for integers} + +\indexlibrary{\idxcode{atomic<\placeholder{integral}>}}% +\pnum +There are specializations of the \tcode{atomic} +class template for the integral types +\tcode{char}, +\tcode{signed char}, +\tcode{unsigned char}, +\tcode{short}, +\tcode{unsigned short}, +\tcode{int}, +\tcode{unsigned int}, +\tcode{long}, +\tcode{unsigned long}, +\tcode{long long}, +\tcode{unsigned long long}, +\keyword{char8_t}, +\keyword{char16_t}, +\keyword{char32_t}, +\keyword{wchar_t}, +and any other types needed by the typedefs in the header \libheaderref{cstdint}. +For each such type \tcode{\placeholder{integral}}, the specialization +\tcode{atomic<\placeholder{integral}>} provides additional atomic operations appropriate to integral types. +\begin{note} +The specialization \tcode{atomic} +uses the primary template\iref{atomics.types.generic}. +\end{note} + +\begin{codeblock} +namespace std { + template<> struct atomic<@\placeholder{integral}@> { + using value_type = @\placeholder{integral}@; + using difference_type = value_type; + + static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; + bool is_lock_free() const volatile noexcept; + bool is_lock_free() const noexcept; + + constexpr atomic() noexcept; + constexpr atomic(@\placeholdernc{integral}@) noexcept; + atomic(const atomic&) = delete; + atomic& operator=(const atomic&) = delete; + atomic& operator=(const atomic&) volatile = delete; + + void store(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) volatile noexcept; + void store(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) noexcept; + @\placeholdernc{integral}@ operator=(@\placeholdernc{integral}@) volatile noexcept; + @\placeholdernc{integral}@ operator=(@\placeholdernc{integral}@) noexcept; + @\placeholdernc{integral}@ load(memory_order = memory_order::seq_cst) const volatile noexcept; + @\placeholdernc{integral}@ load(memory_order = memory_order::seq_cst) const noexcept; + operator @\placeholdernc{integral}@() const volatile noexcept; + operator @\placeholdernc{integral}@() const noexcept; + + @\placeholdernc{integral}@ exchange(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) volatile noexcept; + @\placeholdernc{integral}@ exchange(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) noexcept; + bool compare_exchange_weak(@\placeholder{integral}@&, @\placeholdernc{integral}@, + memory_order, memory_order) volatile noexcept; + bool compare_exchange_weak(@\placeholder{integral}@&, @\placeholdernc{integral}@, + memory_order, memory_order) noexcept; + bool compare_exchange_strong(@\placeholder{integral}@&, @\placeholdernc{integral}@, + memory_order, memory_order) volatile noexcept; + bool compare_exchange_strong(@\placeholder{integral}@&, @\placeholdernc{integral}@, + memory_order, memory_order) noexcept; + bool compare_exchange_weak(@\placeholder{integral}@&, @\placeholdernc{integral}@, + memory_order = memory_order::seq_cst) volatile noexcept; + bool compare_exchange_weak(@\placeholder{integral}@&, @\placeholdernc{integral}@, + memory_order = memory_order::seq_cst) noexcept; + bool compare_exchange_strong(@\placeholder{integral}@&, @\placeholdernc{integral}@, + memory_order = memory_order::seq_cst) volatile noexcept; + bool compare_exchange_strong(@\placeholder{integral}@&, @\placeholdernc{integral}@, + memory_order = memory_order::seq_cst) noexcept; + + @\placeholdernc{integral}@ fetch_add(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) volatile noexcept; + @\placeholdernc{integral}@ fetch_add(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) noexcept; + @\placeholdernc{integral}@ fetch_sub(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) volatile noexcept; + @\placeholdernc{integral}@ fetch_sub(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) noexcept; + @\placeholdernc{integral}@ fetch_and(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) volatile noexcept; + @\placeholdernc{integral}@ fetch_and(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) noexcept; + @\placeholdernc{integral}@ fetch_or(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) volatile noexcept; + @\placeholdernc{integral}@ fetch_or(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) noexcept; + @\placeholdernc{integral}@ fetch_xor(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) volatile noexcept; + @\placeholdernc{integral}@ fetch_xor(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) noexcept; + + @\placeholdernc{integral}@ operator++(int) volatile noexcept; + @\placeholdernc{integral}@ operator++(int) noexcept; + @\placeholdernc{integral}@ operator--(int) volatile noexcept; + @\placeholdernc{integral}@ operator--(int) noexcept; + @\placeholdernc{integral}@ operator++() volatile noexcept; + @\placeholdernc{integral}@ operator++() noexcept; + @\placeholdernc{integral}@ operator--() volatile noexcept; + @\placeholdernc{integral}@ operator--() noexcept; + @\placeholdernc{integral}@ operator+=(@\placeholdernc{integral}@) volatile noexcept; + @\placeholdernc{integral}@ operator+=(@\placeholdernc{integral}@) noexcept; + @\placeholdernc{integral}@ operator-=(@\placeholdernc{integral}@) volatile noexcept; + @\placeholdernc{integral}@ operator-=(@\placeholdernc{integral}@) noexcept; + @\placeholdernc{integral}@ operator&=(@\placeholdernc{integral}@) volatile noexcept; + @\placeholdernc{integral}@ operator&=(@\placeholdernc{integral}@) noexcept; + @\placeholdernc{integral}@ operator|=(@\placeholdernc{integral}@) volatile noexcept; + @\placeholdernc{integral}@ operator|=(@\placeholdernc{integral}@) noexcept; + @\placeholdernc{integral}@ operator^=(@\placeholdernc{integral}@) volatile noexcept; + @\placeholdernc{integral}@ operator^=(@\placeholdernc{integral}@) noexcept; + + void wait(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) const volatile noexcept; + void wait(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() volatile noexcept; + void notify_one() noexcept; + void notify_all() volatile noexcept; + void notify_all() noexcept; + }; +} +\end{codeblock} + +\pnum +The atomic integral specializations +are standard-layout structs. +They each have +a trivial destructor. + +\pnum +Descriptions are provided below only for members that differ from the primary template. + +\pnum +The following operations perform arithmetic computations. +The correspondence among key, operator, and computation is specified +in \tref{atomic.types.int.comp}. + +\begin{floattable} +{Atomic arithmetic computations}{atomic.types.int.comp}{lll|lll} +\hline +\hdstyle{\tcode{\placeholder{key}}} & + \hdstyle{Op} & + \hdstyle{Computation} & +\hdstyle{\tcode{\placeholder{key}}} & + \hdstyle{Op} & + \hdstyle{Computation} \\ \hline +\tcode{add} & + \tcode{+} & + addition & +\tcode{sub} & + \tcode{-} & + subtraction \\ +\tcode{or} & + \tcode{|} & + bitwise inclusive or & +\tcode{xor} & + \tcode{\caret} & + bitwise exclusive or \\ +\tcode{and} & + \tcode{\&} & + bitwise and &&&\\ +\end{floattable} + +\indexlibraryglobal{atomic_fetch_add}% +\indexlibraryglobal{atomic_fetch_and}% +\indexlibraryglobal{atomic_fetch_or}% +\indexlibraryglobal{atomic_fetch_sub}% +\indexlibraryglobal{atomic_fetch_xor}% +\indexlibraryglobal{atomic_fetch_add_explicit}% +\indexlibraryglobal{atomic_fetch_and_explicit}% +\indexlibraryglobal{atomic_fetch_or_explicit}% +\indexlibraryglobal{atomic_fetch_sub_explicit}% +\indexlibraryglobal{atomic_fetch_xor_explicit}% +\indexlibrarymember{fetch_add}{atomic<\placeholder{integral}>}% +\indexlibrarymember{fetch_and}{atomic<\placeholder{integral}>}% +\indexlibrarymember{fetch_or}{atomic<\placeholder{integral}>}% +\indexlibrarymember{fetch_sub}{atomic<\placeholder{integral}>}% +\indexlibrarymember{fetch_xor}{atomic<\placeholder{integral}>}% +\begin{itemdecl} +T fetch_@\placeholdernc{key}@(T operand, memory_order order = memory_order::seq_cst) volatile noexcept; +T fetch_@\placeholdernc{key}@(T operand, memory_order order = memory_order::seq_cst) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the \tcode{volatile} overload of this function, +\tcode{is_always_lock_free} is \tcode{true}. + +\pnum +\effects +Atomically replaces the value pointed to by +\keyword{this} with the result of the computation applied to the +value pointed to by \keyword{this} and the given \tcode{operand}. +Memory is affected according to the value of \tcode{order}. +These operations are atomic read-modify-write operations\iref{intro.multithread}. + +\pnum +\returns +Atomically, the value pointed to by \keyword{this} immediately before the effects. + +\pnum +\indextext{signed integer representation!two's complement}% +\remarks +For signed integer types, +the result is as if the object value and parameters +were converted to their corresponding unsigned types, +the computation performed on those types, and +the result converted back to the signed type. +\begin{note} +There are no undefined results arising from the computation. +\end{note} + +\end{itemdescr} + +\indexlibrarymember{operator+=}{atomic}% +\indexlibrarymember{operator-=}{atomic}% +\indexlibrarymember{operator+=}{atomic<\placeholder{integral}>}% +\indexlibrarymember{operator-=}{atomic<\placeholder{integral}>}% +\indexlibrarymember{operator\&=}{atomic<\placeholder{integral}>}% +\indexlibrarymember{operator"|=}{atomic<\placeholder{integral}>}% +\indexlibrarymember{operator\caret=}{atomic<\placeholder{integral}>}% +\begin{itemdecl} +T operator @\placeholder{op}@=(T operand) volatile noexcept; +T operator @\placeholder{op}@=(T operand) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the \tcode{volatile} overload of this function, +\tcode{is_always_lock_free} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return fetch_\placeholder{key}(operand) \placeholder{op} operand;} +\end{itemdescr} + +\rSec3[atomics.types.float]{Specializations for floating-point types} + +\indexlibrary{\idxcode{atomic<\placeholder{floating-point}>}}% +\pnum +There are specializations of the \tcode{atomic} +class template for the floating-point types +\tcode{float}, +\tcode{double}, and +\tcode{long double}. +For each such type \tcode{\placeholdernc{floating-point}}, +the specialization \tcode{atomic<\placeholder{floating-point}>} +provides additional atomic operations appropriate to floating-point types. + +\begin{codeblock} +namespace std { + template<> struct atomic<@\placeholder{floating-point}@> { + using value_type = @\placeholdernc{floating-point}@; + using difference_type = value_type; + + static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; + bool is_lock_free() const volatile noexcept; + bool is_lock_free() const noexcept; + + constexpr atomic() noexcept; + constexpr atomic(@\placeholder{floating-point}@) noexcept; + atomic(const atomic&) = delete; + atomic& operator=(const atomic&) = delete; + atomic& operator=(const atomic&) volatile = delete; + + void store(@\placeholdernc{floating-point}@, memory_order = memory_order::seq_cst) volatile noexcept; + void store(@\placeholdernc{floating-point}@, memory_order = memory_order::seq_cst) noexcept; + @\placeholdernc{floating-point}@ operator=(@\placeholder{floating-point}@) volatile noexcept; + @\placeholdernc{floating-point}@ operator=(@\placeholder{floating-point}@) noexcept; + @\placeholdernc{floating-point}@ load(memory_order = memory_order::seq_cst) volatile noexcept; + @\placeholdernc{floating-point}@ load(memory_order = memory_order::seq_cst) noexcept; + operator @\placeholdernc{floating-point}@() volatile noexcept; + operator @\placeholdernc{floating-point}@() noexcept; + + @\placeholdernc{floating-point}@ exchange(@\placeholdernc{floating-point}@, + memory_order = memory_order::seq_cst) volatile noexcept; + @\placeholdernc{floating-point}@ exchange(@\placeholdernc{floating-point}@, + memory_order = memory_order::seq_cst) noexcept; + bool compare_exchange_weak(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, + memory_order, memory_order) volatile noexcept; + bool compare_exchange_weak(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, + memory_order, memory_order) noexcept; + bool compare_exchange_strong(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, + memory_order, memory_order) volatile noexcept; + bool compare_exchange_strong(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, + memory_order, memory_order) noexcept; + bool compare_exchange_weak(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, + memory_order = memory_order::seq_cst) volatile noexcept; + bool compare_exchange_weak(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, + memory_order = memory_order::seq_cst) noexcept; + bool compare_exchange_strong(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, + memory_order = memory_order::seq_cst) volatile noexcept; + bool compare_exchange_strong(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, + memory_order = memory_order::seq_cst) noexcept; + + @\placeholdernc{floating-point}@ fetch_add(@\placeholdernc{floating-point}@, + memory_order = memory_order::seq_cst) volatile noexcept; + @\placeholdernc{floating-point}@ fetch_add(@\placeholdernc{floating-point}@, + memory_order = memory_order::seq_cst) noexcept; + @\placeholdernc{floating-point}@ fetch_sub(@\placeholdernc{floating-point}@, + memory_order = memory_order::seq_cst) volatile noexcept; + @\placeholdernc{floating-point}@ fetch_sub(@\placeholdernc{floating-point}@, + memory_order = memory_order::seq_cst) noexcept; + + @\placeholdernc{floating-point}@ operator+=(@\placeholder{floating-point}@) volatile noexcept; + @\placeholdernc{floating-point}@ operator+=(@\placeholder{floating-point}@) noexcept; + @\placeholdernc{floating-point}@ operator-=(@\placeholder{floating-point}@) volatile noexcept; + @\placeholdernc{floating-point}@ operator-=(@\placeholder{floating-point}@) noexcept; + + void wait(@\placeholdernc{floating-point}@, memory_order = memory_order::seq_cst) const volatile noexcept; + void wait(@\placeholdernc{floating-point}@, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() volatile noexcept; + void notify_one() noexcept; + void notify_all() volatile noexcept; + void notify_all() noexcept; + }; +} +\end{codeblock} + +\pnum +The atomic floating-point specializations +are standard-layout structs. +They each have +a trivial destructor. + +\pnum +Descriptions are provided below only for members that differ from the primary template. + +\pnum +The following operations perform arithmetic addition and subtraction computations. +The correspondence among key, operator, and computation is specified +in \tref{atomic.types.int.comp}. + +\indexlibraryglobal{atomic_fetch_add}% +\indexlibraryglobal{atomic_fetch_sub}% +\indexlibraryglobal{atomic_fetch_add_explicit}% +\indexlibraryglobal{atomic_fetch_sub_explicit}% +\indexlibrarymember{fetch_add}{atomic<\placeholder{floating-point}>}% +\indexlibrarymember{fetch_sub}{atomic<\placeholder{floating-point}>}% +\begin{itemdecl} +T fetch_@\placeholdernc{key}@(T operand, memory_order order = memory_order::seq_cst) volatile noexcept; +T fetch_@\placeholdernc{key}@(T operand, memory_order order = memory_order::seq_cst) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the \tcode{volatile} overload of this function, +\tcode{is_always_lock_free} is \tcode{true}. + +\pnum +\effects +Atomically replaces the value pointed to by \keyword{this} +with the result of the computation applied to the value pointed +to by \keyword{this} and the given \tcode{operand}. +Memory is affected according to the value of \tcode{order}. +These operations are atomic read-modify-write operations\iref{intro.multithread}. + +\pnum +\returns +Atomically, the value pointed to by \keyword{this} immediately before the effects. + +\pnum +\remarks +If the result is not a representable value for its type\iref{expr.pre} +the result is unspecified, but the operations otherwise have no undefined +behavior. Atomic arithmetic operations on \tcode{\placeholder{floating-point}} +should conform to the \tcode{std::numeric_limits<\placeholder{floating-point}>} +traits associated with the floating-point type\iref{limits.syn}. +The floating-point environment\iref{cfenv} for atomic arithmetic operations +on \tcode{\placeholder{floating-point}} may be different than the +calling thread's floating-point environment. +\end{itemdescr} + +\indexlibrarymember{operator+=}{atomic}% +\indexlibrarymember{operator-=}{atomic}% +\indexlibrarymember{operator+=}{atomic<\placeholder{floating-point}>}% +\indexlibrarymember{operator-=}{atomic<\placeholder{floating-point}>}% +\begin{itemdecl} +T operator @\placeholder{op}@=(T operand) volatile noexcept; +T operator @\placeholder{op}@=(T operand) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the \tcode{volatile} overload of this function, +\tcode{is_always_lock_free} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return fetch_\placeholder{key}(operand) \placeholder{op} operand;} + +\pnum +\remarks +If the result is not a representable value for its type\iref{expr.pre} +the result is unspecified, but the operations otherwise have no undefined +behavior. Atomic arithmetic operations on \tcode{\placeholder{floating-point}} +should conform to the \tcode{std::numeric_limits<\placeholder{floating-point}>} +traits associated with the floating-point type\iref{limits.syn}. +The floating-point environment\iref{cfenv} for atomic arithmetic operations +on \tcode{\placeholder{floating-point}} may be different than the +calling thread's floating-point environment. +\end{itemdescr} + +\rSec3[atomics.types.pointer]{Partial specialization for pointers} +\indexlibraryglobal{atomic}% + +\begin{codeblock} +namespace std { + template struct atomic { + using value_type = T*; + using difference_type = ptrdiff_t; + + static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; + bool is_lock_free() const volatile noexcept; + bool is_lock_free() const noexcept; + + constexpr atomic() noexcept; + constexpr atomic(T*) noexcept; + atomic(const atomic&) = delete; + atomic& operator=(const atomic&) = delete; + atomic& operator=(const atomic&) volatile = delete; + + void store(T*, memory_order = memory_order::seq_cst) volatile noexcept; + void store(T*, memory_order = memory_order::seq_cst) noexcept; + T* operator=(T*) volatile noexcept; + T* operator=(T*) noexcept; + T* load(memory_order = memory_order::seq_cst) const volatile noexcept; + T* load(memory_order = memory_order::seq_cst) const noexcept; + operator T*() const volatile noexcept; + operator T*() const noexcept; + + T* exchange(T*, memory_order = memory_order::seq_cst) volatile noexcept; + T* exchange(T*, memory_order = memory_order::seq_cst) noexcept; + bool compare_exchange_weak(T*&, T*, memory_order, memory_order) volatile noexcept; + bool compare_exchange_weak(T*&, T*, memory_order, memory_order) noexcept; + bool compare_exchange_strong(T*&, T*, memory_order, memory_order) volatile noexcept; + bool compare_exchange_strong(T*&, T*, memory_order, memory_order) noexcept; + bool compare_exchange_weak(T*&, T*, + memory_order = memory_order::seq_cst) volatile noexcept; + bool compare_exchange_weak(T*&, T*, + memory_order = memory_order::seq_cst) noexcept; + bool compare_exchange_strong(T*&, T*, + memory_order = memory_order::seq_cst) volatile noexcept; + bool compare_exchange_strong(T*&, T*, + memory_order = memory_order::seq_cst) noexcept; + + T* fetch_add(ptrdiff_t, memory_order = memory_order::seq_cst) volatile noexcept; + T* fetch_add(ptrdiff_t, memory_order = memory_order::seq_cst) noexcept; + T* fetch_sub(ptrdiff_t, memory_order = memory_order::seq_cst) volatile noexcept; + T* fetch_sub(ptrdiff_t, memory_order = memory_order::seq_cst) noexcept; + + T* operator++(int) volatile noexcept; + T* operator++(int) noexcept; + T* operator--(int) volatile noexcept; + T* operator--(int) noexcept; + T* operator++() volatile noexcept; + T* operator++() noexcept; + T* operator--() volatile noexcept; + T* operator--() noexcept; + T* operator+=(ptrdiff_t) volatile noexcept; + T* operator+=(ptrdiff_t) noexcept; + T* operator-=(ptrdiff_t) volatile noexcept; + T* operator-=(ptrdiff_t) noexcept; + + void wait(T*, memory_order = memory_order::seq_cst) const volatile noexcept; + void wait(T*, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() volatile noexcept; + void notify_one() noexcept; + void notify_all() volatile noexcept; + void notify_all() noexcept; + }; +} +\end{codeblock} + +\indexlibraryglobal{atomic}% +\pnum +There is a partial specialization of the \tcode{atomic} class template for pointers. +Specializations of this partial specialization are standard-layout structs. +They each have a trivial destructor. + +\pnum +Descriptions are provided below only for members that differ from the primary template. + +\pnum +The following operations perform pointer arithmetic. +The correspondence among key, operator, and computation is specified +in \tref{atomic.types.pointer.comp}. + +\begin{floattable} +{Atomic pointer computations}{atomic.types.pointer.comp}{lll|lll} +\hline +\hdstyle{\tcode{\placeholder{key}}} & + \hdstyle{Op} & + \hdstyle{Computation} & +\hdstyle{\tcode{\placeholder{key}}} & + \hdstyle{Op} & + \hdstyle{Computation} \\ \hline +\tcode{add} & + \tcode{+} & + addition & +\tcode{sub} & + \tcode{-} & + subtraction \\ +\end{floattable} + +\indexlibraryglobal{atomic_fetch_add}% +\indexlibraryglobal{atomic_fetch_sub}% +\indexlibraryglobal{atomic_fetch_add_explicit}% +\indexlibraryglobal{atomic_fetch_sub_explicit}% +\indexlibrarymember{fetch_add}{atomic}% +\indexlibrarymember{fetch_sub}{atomic}% +\begin{itemdecl} +T* fetch_@\placeholdernc{key}@(ptrdiff_t operand, memory_order order = memory_order::seq_cst) volatile noexcept; +T* fetch_@\placeholdernc{key}@(ptrdiff_t operand, memory_order order = memory_order::seq_cst) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the \tcode{volatile} overload of this function, +\tcode{is_always_lock_free} is \tcode{true}. + +\pnum +\mandates +\tcode{T} is a complete object type. +\begin{note} +Pointer arithmetic on \tcode{void*} or function pointers is ill-formed. +\end{note} + +\pnum +\effects +Atomically replaces the value pointed to by +\keyword{this} with the result of the computation applied to the +value pointed to by \keyword{this} and the given \tcode{operand}. +Memory is affected according to the value of \tcode{order}. +These operations are atomic read-modify-write operations\iref{intro.multithread}. + +\pnum +\returns +Atomically, the value pointed to by \keyword{this} immediately before the effects. + +\pnum +\remarks +The result may be an undefined address, +but the operations otherwise have no undefined behavior. +\end{itemdescr} + +\indexlibrarymember{operator+=}{atomic}% +\indexlibrarymember{operator-=}{atomic}% +\begin{itemdecl} +T* operator @\placeholder{op}@=(ptrdiff_t operand) volatile noexcept; +T* operator @\placeholder{op}@=(ptrdiff_t operand) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the \tcode{volatile} overload of this function, +\tcode{is_always_lock_free} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return fetch_\placeholder{key}(operand) \placeholder{op} operand;} +\end{itemdescr} + +\rSec3[atomics.types.memop]{Member operators common to integers and pointers to objects} + +\indexlibrarymember{operator++}{atomic}% +\indexlibrarymember{operator++}{atomic<\placeholder{integral}>}% +\begin{itemdecl} +value_type operator++(int) volatile noexcept; +value_type operator++(int) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the \tcode{volatile} overload of this function, +\tcode{is_always_lock_free} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return fetch_add(1);} +\end{itemdescr} + +\indexlibrarymember{operator--}{atomic}% +\indexlibrarymember{operator--}{atomic<\placeholder{integral}>}% +\begin{itemdecl} +value_type operator--(int) volatile noexcept; +value_type operator--(int) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the \tcode{volatile} overload of this function, +\tcode{is_always_lock_free} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return fetch_sub(1);} +\end{itemdescr} + +\indexlibrarymember{operator++}{atomic}% +\indexlibrarymember{operator++}{atomic<\placeholder{integral}>}% +\begin{itemdecl} +value_type operator++() volatile noexcept; +value_type operator++() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the \tcode{volatile} overload of this function, +\tcode{is_always_lock_free} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return fetch_add(1) + 1;} +\end{itemdescr} + +\indexlibrarymember{operator--}{atomic}% +\indexlibrarymember{operator--}{atomic<\placeholder{integral}>}% +\begin{itemdecl} +value_type operator--() volatile noexcept; +value_type operator--() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +For the \tcode{volatile} overload of this function, +\tcode{is_always_lock_free} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return fetch_sub(1) - 1;} +\end{itemdescr} + +\rSec3[util.smartptr.atomic]{Partial specializations for smart pointers}% +\indextext{atomic!smart pointers|(}% + +\rSec4[util.smartptr.atomic.general]{General} + +\pnum +The library provides partial specializations of the \tcode{atomic} template +for shared-ownership smart pointers\iref{util.sharedptr}. +\begin{note} +The partial specializations are declared in header \libheaderref{memory}. +\end{note} +The behavior of all operations is as specified in \ref{atomics.types.generic}, +unless specified otherwise. +The template parameter \tcode{T} of these partial specializations +may be an incomplete type. + +\pnum +All changes to an atomic smart pointer in \ref{util.smartptr.atomic}, and +all associated \tcode{use_count} increments, +are guaranteed to be performed atomically. +Associated \tcode{use_count} decrements +are sequenced after the atomic operation, +but are not required to be part of it. +Any associated deletion and deallocation +are sequenced after the atomic update step and +are not part of the atomic operation. +\begin{note} +If the atomic operation uses locks, +locks acquired by the implementation +will be held when any \tcode{use_count} adjustments are performed, and +will not be held when any destruction or deallocation +resulting from this is performed. +\end{note} + +\pnum +\begin{example} +\begin{codeblock} +template class atomic_list { + struct node { + T t; + shared_ptr next; + }; + atomic> head; + +public: + auto find(T t) const { + auto p = head.load(); + while (p && p->t != t) + p = p->next; + + return shared_ptr(move(p)); + } + + void push_front(T t) { + auto p = make_shared(); + p->t = t; + p->next = head; + while (!head.compare_exchange_weak(p->next, p)) {} + } +}; +\end{codeblock} +\end{example} + +\rSec4[util.smartptr.atomic.shared]{Partial specialization for \tcode{shared_ptr}} +\indexlibraryglobal{atomic>}% +\begin{codeblock} +namespace std { + template struct atomic> { + using value_type = shared_ptr; + + static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; + bool is_lock_free() const noexcept; + + constexpr atomic() noexcept; + constexpr atomic(nullptr_t) noexcept : atomic() { } + atomic(shared_ptr desired) noexcept; + atomic(const atomic&) = delete; + void operator=(const atomic&) = delete; + + shared_ptr load(memory_order order = memory_order::seq_cst) const noexcept; + operator shared_ptr() const noexcept; + void store(shared_ptr desired, memory_order order = memory_order::seq_cst) noexcept; + void operator=(shared_ptr desired) noexcept; + + shared_ptr exchange(shared_ptr desired, + memory_order order = memory_order::seq_cst) noexcept; + bool compare_exchange_weak(shared_ptr& expected, shared_ptr desired, + memory_order success, memory_order failure) noexcept; + bool compare_exchange_strong(shared_ptr& expected, shared_ptr desired, + memory_order success, memory_order failure) noexcept; + bool compare_exchange_weak(shared_ptr& expected, shared_ptr desired, + memory_order order = memory_order::seq_cst) noexcept; + bool compare_exchange_strong(shared_ptr& expected, shared_ptr desired, + memory_order order = memory_order::seq_cst) noexcept; + + void wait(shared_ptr old, memory_order order = memory_order::seq_cst) const noexcept; + void notify_one() noexcept; + void notify_all() noexcept; + + private: + shared_ptr p; // \expos + }; +} +\end{codeblock} + +\indexlibraryctor{atomic>}% +\begin{itemdecl} +constexpr atomic() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{p\{\}}. +\end{itemdescr} + +\indexlibraryctor{atomic>}% +\begin{itemdecl} +atomic(shared_ptr desired) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the object with the value \tcode{desired}. +Initialization is not an atomic operation\iref{intro.multithread}. +\begin{note} +It is possible to have an access to +an atomic object \tcode{A} race with its construction, +for example, +by communicating the address of the just-constructed object \tcode{A} +to another thread via \tcode{memory_order::relaxed} operations +on a suitable atomic pointer variable, and +then immediately accessing \tcode{A} in the receiving thread. +This results in undefined behavior. +\end{note} +\end{itemdescr} + +\indexlibrarymember{store}{atomic>}% +\begin{itemdecl} +void store(shared_ptr desired, memory_order order = memory_order::seq_cst) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{order} is neither +\tcode{memory_order::consume}, +\tcode{memory_order::acquire}, nor +\tcode{memory_order::acq_rel}. + +\pnum +\effects +Atomically replaces the value pointed to by \keyword{this} with +the value of \tcode{desired} as if by \tcode{p.swap(desired)}. +Memory is affected according to the value of \tcode{order}. +\end{itemdescr} + +\indexlibrarymember{operator=}{atomic>}% +\begin{itemdecl} +void operator=(shared_ptr desired) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{store(desired)}. +\end{itemdescr} + +\indexlibrarymember{load}{atomic>}% +\begin{itemdecl} +shared_ptr load(memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{order} is neither +\tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Memory is affected according to the value of \tcode{order}. + +\pnum +\returns +Atomically returns \tcode{p}. +\end{itemdescr} + +\indexlibrarymember{operator shared_ptr}{atomic>}% +\begin{itemdecl} +operator shared_ptr() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return load();} +\end{itemdescr} + +\indexlibrarymember{exchange}{atomic>}% +\begin{itemdecl} +shared_ptr exchange(shared_ptr desired, memory_order order = memory_order::seq_cst) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Atomically replaces \tcode{p} with \tcode{desired} +as if by \tcode{p.swap(desired)}. +Memory is affected according to the value of \tcode{order}. +This is an atomic read-modify-write operation\iref{intro.races}. + +\pnum +\returns +Atomically returns the value of \tcode{p} immediately before the effects. +\end{itemdescr} + +\indexlibrarymember{compare_exchange_weak}{atomic>}% +\indexlibrarymember{compare_exchange_strong}{atomic>}% +\begin{itemdecl} +bool compare_exchange_weak(shared_ptr& expected, shared_ptr desired, + memory_order success, memory_order failure) noexcept; +bool compare_exchange_strong(shared_ptr& expected, shared_ptr desired, + memory_order success, memory_order failure) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{failure} is neither +\tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +If \tcode{p} is equivalent to \tcode{expected}, +assigns \tcode{desired} to \tcode{p} and +has synchronization semantics corresponding to the value of \tcode{success}, +otherwise assigns \tcode{p} to \tcode{expected} and +has synchronization semantics corresponding to the value of \tcode{failure}. + +\pnum +\returns +\tcode{true} if \tcode{p} was equivalent to \tcode{expected}, +\tcode{false} otherwise. + +\pnum +\remarks +Two \tcode{shared_ptr} objects are equivalent if +they store the same pointer value and +either share ownership or are both empty. +The weak form may fail spuriously. See \ref{atomics.types.operations}. + +\pnum +If the operation returns \tcode{true}, +\tcode{expected} is not accessed after the atomic update and +the operation is an atomic read-modify-write operation\iref{intro.multithread} +on the memory pointed to by \keyword{this}. +Otherwise, the operation is an atomic load operation on that memory, and +\tcode{expected} is updated with the existing value +read from the atomic object in the attempted atomic update. +The \tcode{use_count} update corresponding to the write to \tcode{expected} +is part of the atomic operation. +The write to \tcode{expected} itself +is not required to be part of the atomic operation. +\end{itemdescr} + +\indexlibrarymember{compare_exchange_weak}{atomic>}% +\begin{itemdecl} +bool compare_exchange_weak(shared_ptr& expected, shared_ptr desired, + memory_order order = memory_order::seq_cst) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return compare_exchange_weak(expected, desired, order, fail_order); +\end{codeblock} +where \tcode{fail_order} is the same as \tcode{order} +except that a value of \tcode{memory_order::acq_rel} +shall be replaced by the value \tcode{memory_order::acquire} and +a value of \tcode{memory_order::release} +shall be replaced by the value \tcode{memory_order::relaxed}. +\end{itemdescr} + +\indexlibrarymember{compare_exchange_strong}{atomic>}% +\begin{itemdecl} +bool compare_exchange_strong(shared_ptr& expected, shared_ptr desired, + memory_order order = memory_order::seq_cst) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return compare_exchange_strong(expected, desired, order, fail_order); +\end{codeblock} +where \tcode{fail_order} is the same as \tcode{order} +except that a value of \tcode{memory_order::acq_rel} +shall be replaced by the value \tcode{memory_order::acquire} and +a value of \tcode{memory_order::release} +shall be replaced by the value \tcode{memory_order::relaxed}. +\end{itemdescr} + +\indexlibrarymember{wait}{atomic>}% +\begin{itemdecl} +void wait(shared_ptr old, memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{order} is +neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Repeatedly performs the following steps, in order: +\begin{itemize} +\item + Evaluates \tcode{load(order)} and compares it to \tcode{old}. +\item + If the two are not equivalent, returns. +\item + Blocks until it + is unblocked by an atomic notifying operation or is unblocked spuriously. +\end{itemize} + +\pnum +\remarks +Two \tcode{shared_ptr} objects are equivalent +if they store the same pointer and either share ownership or are both empty. +This function is an atomic waiting operation\iref{atomics.wait}. +\end{itemdescr} + +\indexlibrarymember{notify_one}{atomic>}% +\begin{itemdecl} +void notify_one() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of at least one atomic waiting operation +that is eligible to be unblocked\iref{atomics.wait} by this call, +if any such atomic waiting operations exist. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait}. +\end{itemdescr} + +\indexlibrarymember{notify_all}{atomic>}% +\begin{itemdecl} +void notify_all() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of all atomic waiting operations +that are eligible to be unblocked\iref{atomics.wait} by this call. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait}. +\end{itemdescr} + +\rSec4[util.smartptr.atomic.weak]{Partial specialization for \tcode{weak_ptr}} + +\indexlibraryglobal{atomic>}% +\begin{codeblock} +namespace std { + template struct atomic> { + using value_type = weak_ptr; + + static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; + bool is_lock_free() const noexcept; + + constexpr atomic() noexcept; + atomic(weak_ptr desired) noexcept; + atomic(const atomic&) = delete; + void operator=(const atomic&) = delete; + + weak_ptr load(memory_order order = memory_order::seq_cst) const noexcept; + operator weak_ptr() const noexcept; + void store(weak_ptr desired, memory_order order = memory_order::seq_cst) noexcept; + void operator=(weak_ptr desired) noexcept; + + weak_ptr exchange(weak_ptr desired, + memory_order order = memory_order::seq_cst) noexcept; + bool compare_exchange_weak(weak_ptr& expected, weak_ptr desired, + memory_order success, memory_order failure) noexcept; + bool compare_exchange_strong(weak_ptr& expected, weak_ptr desired, + memory_order success, memory_order failure) noexcept; + bool compare_exchange_weak(weak_ptr& expected, weak_ptr desired, + memory_order order = memory_order::seq_cst) noexcept; + bool compare_exchange_strong(weak_ptr& expected, weak_ptr desired, + memory_order order = memory_order::seq_cst) noexcept; + + void wait(weak_ptr old, memory_order order = memory_order::seq_cst) const noexcept; + void notify_one() noexcept; + void notify_all() noexcept; + + private: + weak_ptr p; // \expos + }; +} +\end{codeblock} + +\indexlibraryctor{atomic>}% +\begin{itemdecl} +constexpr atomic() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{p\{\}}. +\end{itemdescr} + +\indexlibraryctor{atomic>}% +\begin{itemdecl} +atomic(weak_ptr desired) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the object with the value \tcode{desired}. +Initialization is not an atomic operation\iref{intro.multithread}. +\begin{note} +It is possible to have an access to +an atomic object \tcode{A} race with its construction, +for example, +by communicating the address of the just-constructed object \tcode{A} +to another thread via \tcode{memory_order::relaxed} operations +on a suitable atomic pointer variable, and +then immediately accessing \tcode{A} in the receiving thread. +This results in undefined behavior. +\end{note} +\end{itemdescr} + +\indexlibrarymember{store}{atomic>}% +\begin{itemdecl} +void store(weak_ptr desired, memory_order order = memory_order::seq_cst) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{order} is neither +\tcode{memory_order::consume}, +\tcode{memory_order::acquire}, nor +\tcode{memory_order::acq_rel}. + +\pnum +\effects +Atomically replaces the value pointed to by \keyword{this} with +the value of \tcode{desired} as if by \tcode{p.swap(desired)}. +Memory is affected according to the value of \tcode{order}. +\end{itemdescr} + +\indexlibrarymember{operator=}{atomic>}% +\begin{itemdecl} +void operator=(weak_ptr desired) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{store(desired)}. +\end{itemdescr} + +\indexlibrarymember{load}{atomic>}% +\begin{itemdecl} +weak_ptr load(memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{order} is neither +\tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Memory is affected according to the value of \tcode{order}. + +\pnum +\returns +Atomically returns \tcode{p}. +\end{itemdescr} + +\indexlibrarymember{operator weak_ptr}{atomic>}% +\begin{itemdecl} +operator weak_ptr() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return load();} +\end{itemdescr} + +\indexlibrarymember{exchange}{atomic>}% +\begin{itemdecl} +weak_ptr exchange(weak_ptr desired, memory_order order = memory_order::seq_cst) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Atomically replaces \tcode{p} with \tcode{desired} +as if by \tcode{p.swap(desired)}. +Memory is affected according to the value of \tcode{order}. +This is an atomic read-modify-write operation\iref{intro.races}. + +\pnum +\returns +Atomically returns the value of \tcode{p} immediately before the effects. +\end{itemdescr} + +\indexlibrarymember{compare_exchange_weak}{atomic>}% +\begin{itemdecl} +bool compare_exchange_weak(weak_ptr& expected, weak_ptr desired, + memory_order success, memory_order failure) noexcept; +bool compare_exchange_strong(weak_ptr& expected, weak_ptr desired, + memory_order success, memory_order failure) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{failure} is neither +\tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +If \tcode{p} is equivalent to \tcode{expected}, +assigns \tcode{desired} to \tcode{p} and +has synchronization semantics corresponding to the value of \tcode{success}, +otherwise assigns \tcode{p} to \tcode{expected} and +has synchronization semantics corresponding to the value of \tcode{failure}. + +\pnum +\returns +\tcode{true} if \tcode{p} was equivalent to \tcode{expected}, +\tcode{false} otherwise. + +\pnum +\remarks +Two \tcode{weak_ptr} objects are equivalent if +they store the same pointer value and +either share ownership or are both empty. +The weak form may fail spuriously. See \ref{atomics.types.operations}. + +\pnum +If the operation returns \tcode{true}, +\tcode{expected} is not accessed after the atomic update and +the operation is an atomic read-modify-write operation\iref{intro.multithread} +on the memory pointed to by \keyword{this}. +Otherwise, the operation is an atomic load operation on that memory, and +\tcode{expected} is updated with the existing value +read from the atomic object in the attempted atomic update. +The \tcode{use_count} update corresponding to the write to \tcode{expected} +is part of the atomic operation. +The write to \tcode{expected} itself +is not required to be part of the atomic operation. +\end{itemdescr} + +\indexlibrarymember{compare_exchange_weak}{atomic>}% +\begin{itemdecl} +bool compare_exchange_weak(weak_ptr& expected, weak_ptr desired, + memory_order order = memory_order::seq_cst) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return compare_exchange_weak(expected, desired, order, fail_order); +\end{codeblock} +where \tcode{fail_order} is the same as \tcode{order} +except that a value of \tcode{memory_order::acq_rel} +shall be replaced by the value \tcode{memory_order::acquire} and +a value of \tcode{memory_order::release} +shall be replaced by the value \tcode{memory_order::relaxed}. +\end{itemdescr} + +\indexlibrarymember{compare_exchange_strong}{atomic>}% +\begin{itemdecl} +bool compare_exchange_strong(weak_ptr& expected, weak_ptr desired, + memory_order order = memory_order::seq_cst) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return compare_exchange_strong(expected, desired, order, fail_order); +\end{codeblock} +where \tcode{fail_order} is the same as \tcode{order} +except that a value of \tcode{memory_order::acq_rel} +shall be replaced by the value \tcode{memory_order::acquire} and +a value of \tcode{memory_order::release} +shall be replaced by the value \tcode{memory_order::relaxed}. +\end{itemdescr} + +\indexlibrarymember{wait}{atomic>}% +\begin{itemdecl} +void wait(weak_ptr old, memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{order} is +neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Repeatedly performs the following steps, in order: +\begin{itemize} +\item + Evaluates \tcode{load(order)} and compares it to \tcode{old}. +\item + If the two are not equivalent, returns. +\item + Blocks until it + is unblocked by an atomic notifying operation or is unblocked spuriously. +\end{itemize} + +\pnum +\remarks +Two \tcode{weak_ptr} objects are equivalent +if they store the same pointer and either share ownership or are both empty. +This function is an atomic waiting operation\iref{atomics.wait}. +\end{itemdescr} + + +\indexlibrarymember{notify_one}{atomic>}% +\begin{itemdecl} +void notify_one() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of at least one atomic waiting operation +that is eligible to be unblocked\iref{atomics.wait} by this call, +if any such atomic waiting operations exist. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait}. +\end{itemdescr} + +\indexlibrarymember{notify_all}{atomic>}% +\begin{itemdecl} +void notify_all() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of all atomic waiting operations +that are eligible to be unblocked\iref{atomics.wait} by this call. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait}. +\end{itemdescr} +\indextext{atomic!smart pointers|)} + +\rSec2[atomics.nonmembers]{Non-member functions} + +\pnum +A non-member function template whose name matches the pattern +\tcode{atomic_\placeholder{f}} or the pattern \tcode{atomic_\placeholder{f}_explicit} +invokes the member function \tcode{\placeholder{f}}, with the value of the +first parameter as the object expression and the values of the remaining parameters +(if any) as the arguments of the member function call, in order. An argument +for a parameter of type \tcode{atomic::value_type*} is dereferenced when +passed to the member function call. +If no such member function exists, the program is ill-formed. + +\pnum +\begin{note} +The non-member functions enable programmers to write code that can be +compiled as either C or \Cpp{}, for example in a shared header file. +\end{note} + +\rSec2[atomics.flag]{Flag type and operations} + +\begin{codeblock} +namespace std { + struct atomic_flag { + constexpr atomic_flag() noexcept; + atomic_flag(const atomic_flag&) = delete; + atomic_flag& operator=(const atomic_flag&) = delete; + atomic_flag& operator=(const atomic_flag&) volatile = delete; + + bool test(memory_order = memory_order::seq_cst) const volatile noexcept; + bool test(memory_order = memory_order::seq_cst) const noexcept; + bool test_and_set(memory_order = memory_order::seq_cst) volatile noexcept; + bool test_and_set(memory_order = memory_order::seq_cst) noexcept; + void clear(memory_order = memory_order::seq_cst) volatile noexcept; + void clear(memory_order = memory_order::seq_cst) noexcept; + + void wait(bool, memory_order = memory_order::seq_cst) const volatile noexcept; + void wait(bool, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() volatile noexcept; + void notify_one() noexcept; + void notify_all() volatile noexcept; + void notify_all() noexcept; + }; +} +\end{codeblock} + +\pnum +The \tcode{atomic_flag} type provides the classic test-and-set functionality. It has two states, set and clear. + +\pnum +Operations on an object of type \tcode{atomic_flag} shall be lock-free. +The operations should also be address-free. + +\pnum +The \tcode{atomic_flag} type is a standard-layout struct. +It has a trivial destructor. + +\indexlibraryctor{atomic_flag}% +\begin{itemdecl} +constexpr atomic_flag::atomic_flag() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{*this} to the clear state. +\end{itemdescr} + +\indexlibraryglobal{atomic_flag_test}% +\indexlibraryglobal{atomic_flag_test_explicit}% +\indexlibrarymember{test}{atomic_flag}% +\begin{itemdecl} +bool atomic_flag_test(const volatile atomic_flag* object) noexcept; +bool atomic_flag_test(const atomic_flag* object) noexcept; +bool atomic_flag_test_explicit(const volatile atomic_flag* object, + memory_order order) noexcept; +bool atomic_flag_test_explicit(const atomic_flag* object, + memory_order order) noexcept; +bool atomic_flag::test(memory_order order = memory_order::seq_cst) const volatile noexcept; +bool atomic_flag::test(memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +For \tcode{atomic_flag_test}, let \tcode{order} be \tcode{memory_order::seq_cst}. + +\pnum +\expects +\tcode{order} is +neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Memory is affected according to the value of \tcode{order}. + +\pnum +\returns +Atomically returns the value pointed to by \tcode{object} or \keyword{this}. +\end{itemdescr} + +\indexlibraryglobal{atomic_flag_test_and_set}% +\indexlibraryglobal{atomic_flag_test_and_set_explicit}% +\indexlibrarymember{test_and_set}{atomic_flag}% +\begin{itemdecl} +bool atomic_flag_test_and_set(volatile atomic_flag* object) noexcept; +bool atomic_flag_test_and_set(atomic_flag* object) noexcept; +bool atomic_flag_test_and_set_explicit(volatile atomic_flag* object, memory_order order) noexcept; +bool atomic_flag_test_and_set_explicit(atomic_flag* object, memory_order order) noexcept; +bool atomic_flag::test_and_set(memory_order order = memory_order::seq_cst) volatile noexcept; +bool atomic_flag::test_and_set(memory_order order = memory_order::seq_cst) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Atomically sets the value pointed to by \tcode{object} or by \keyword{this} to \tcode{true}. Memory is affected according to the value of +\tcode{order}. These operations are atomic read-modify-write operations\iref{intro.multithread}. + +\pnum +\returns +Atomically, the value of the object immediately before the effects. +\end{itemdescr} + +\indexlibraryglobal{atomic_flag_clear}% +\indexlibraryglobal{atomic_flag_clear_explicit}% +\indexlibrarymember{clear}{atomic_flag}% +\begin{itemdecl} +void atomic_flag_clear(volatile atomic_flag* object) noexcept; +void atomic_flag_clear(atomic_flag* object) noexcept; +void atomic_flag_clear_explicit(volatile atomic_flag* object, memory_order order) noexcept; +void atomic_flag_clear_explicit(atomic_flag* object, memory_order order) noexcept; +void atomic_flag::clear(memory_order order = memory_order::seq_cst) volatile noexcept; +void atomic_flag::clear(memory_order order = memory_order::seq_cst) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +The \tcode{order} argument is neither \tcode{memory_order::consume}, +\tcode{memory_order::acquire}, nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Atomically sets the value pointed to by \tcode{object} or by \keyword{this} to +\tcode{false}. Memory is affected according to the value of \tcode{order}. +\end{itemdescr} + +\indexlibraryglobal{atomic_flag_wait}% +\indexlibraryglobal{atomic_flag_wait_explicit}% +\indexlibrarymember{wait}{atomic_flag}% +\begin{itemdecl} +void atomic_flag_wait(const volatile atomic_flag* object, bool old) noexcept; +void atomic_flag_wait(const atomic_flag* object, bool old) noexcept; +void atomic_flag_wait_explicit(const volatile atomic_flag* object, + bool old, memory_order order) noexcept; +void atomic_flag_wait_explicit(const atomic_flag* object, + bool old, memory_order order) noexcept; +void atomic_flag::wait(bool old, memory_order order = + memory_order::seq_cst) const volatile noexcept; +void atomic_flag::wait(bool old, memory_order order = + memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +For \tcode{atomic_flag_wait}, +let \tcode{order} be \tcode{memory_order::seq_cst}. +Let \tcode{flag} be \tcode{object} for the non-member functions and +\keyword{this} for the member functions. + +\pnum +\expects +\tcode{order} is +neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Repeatedly performs the following steps, in order: +\begin{itemize} +\item + Evaluates \tcode{flag->test(order) != old}. +\item + If the result of that evaluation is \tcode{true}, returns. +\item + Blocks until it + is unblocked by an atomic notifying operation or is unblocked spuriously. +\end{itemize} + +\pnum +\remarks +This function is an atomic waiting operation\iref{atomics.wait}. +\end{itemdescr} + +\begin{itemdecl} +void atomic_flag_notify_one(volatile atomic_flag* object) noexcept; +void atomic_flag_notify_one(atomic_flag* object) noexcept; +void atomic_flag::notify_one() volatile noexcept; +void atomic_flag::notify_one() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of at least one atomic waiting operation +that is eligible to be unblocked\iref{atomics.wait} by this call, +if any such atomic waiting operations exist. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait}. +\end{itemdescr} + +\begin{itemdecl} +void atomic_flag_notify_all(volatile atomic_flag* object) noexcept; +void atomic_flag_notify_all(atomic_flag* object) noexcept; +void atomic_flag::notify_all() volatile noexcept; +void atomic_flag::notify_all() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of all atomic waiting operations +that are eligible to be unblocked\iref{atomics.wait} by this call. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait}. +\end{itemdescr} + +\rSec2[atomics.fences]{Fences} + +\pnum +This subclause introduces synchronization primitives called \term{fences}. Fences can have +acquire semantics, release semantics, or both. A fence with acquire semantics is called +an \term{acquire fence}. A fence with release semantics is called a \term{release +fence}. + +\pnum +A release fence $A$ synchronizes with an acquire fence $B$ if there exist +atomic operations $X$ and $Y$, both operating on some atomic object +$M$, such that $A$ is sequenced before $X$, $X$ modifies +$M$, $Y$ is sequenced before $B$, and $Y$ reads the value +written by $X$ or a value written by any side effect in the hypothetical release +sequence $X$ would head if it were a release operation. + +\pnum +A release fence $A$ synchronizes with an atomic operation $B$ that +performs an acquire operation on an atomic object $M$ if there exists an atomic +operation $X$ such that $A$ is sequenced before $X$, $X$ +modifies $M$, and $B$ reads the value written by $X$ or a value +written by any side effect in the hypothetical release sequence $X$ would head if +it were a release operation. + +\pnum +An atomic operation $A$ that is a release operation on an atomic object +$M$ synchronizes with an acquire fence $B$ if there exists some atomic +operation $X$ on $M$ such that $X$ is sequenced before $B$ +and reads the value written by $A$ or a value written by any side effect in the +release sequence headed by $A$. + +\indexlibraryglobal{atomic_thread_fence}% +\begin{itemdecl} +extern "C" void atomic_thread_fence(memory_order order) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Depending on the value of \tcode{order}, this operation: +\begin{itemize} +\item has no effects, if \tcode{order == memory_order::relaxed}; + +\item is an acquire fence, if \tcode{order == memory_order::acquire} or \tcode{order == memory_order::consume}; + +\item is a release fence, if \tcode{order == memory_order::release}; + +\item is both an acquire fence and a release fence, if \tcode{order == memory_order::acq_rel}; + +\item is a sequentially consistent acquire and release fence, if \tcode{order == memory_order::seq_cst}. +\end{itemize} +\end{itemdescr} + +\indexlibraryglobal{atomic_signal_fence}% +\begin{itemdecl} +extern "C" void atomic_signal_fence(memory_order order) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{atomic_thread_fence(order)}, except that +the resulting ordering constraints are established only between a thread and a +signal handler executed in the same thread. + +\pnum +\begin{note} +\tcode{atomic_signal_fence} can be used to specify the order in which actions +performed by the thread become visible to the signal handler. +Compiler optimizations and reorderings of loads and stores are inhibited in +the same way as with \tcode{atomic_thread_fence}, but the hardware fence instructions +that \tcode{atomic_thread_fence} would have inserted are not emitted. +\end{note} +\end{itemdescr} + +\rSec2[stdatomic.h.syn]{C compatibility} + +The header \libheaderdef{stdatomic.h} provides the following definitions: + +\begin{codeblock} +template + using @\exposid{std-atomic}@ = std::atomic; // \expos + +#define _Atomic(T) @\exposid{std-atomic}@ + +#define ATOMIC_BOOL_LOCK_FREE @\seebelow@ +#define ATOMIC_CHAR_LOCK_FREE @\seebelow@ +#define ATOMIC_CHAR16_T_LOCK_FREE @\seebelow@ +#define ATOMIC_CHAR32_T_LOCK_FREE @\seebelow@ +#define ATOMIC_WCHAR_T_LOCK_FREE @\seebelow@ +#define ATOMIC_SHORT_LOCK_FREE @\seebelow@ +#define ATOMIC_INT_LOCK_FREE @\seebelow@ +#define ATOMIC_LONG_LOCK_FREE @\seebelow@ +#define ATOMIC_LLONG_LOCK_FREE @\seebelow@ +#define ATOMIC_POINTER_LOCK_FREE @\seebelow@ + +using std::@\libglobal{memory_order}@; // \seebelow +using std::@\libglobal{memory_order_relaxed}@; // \seebelow +using std::@\libglobal{memory_order_consume}@; // \seebelow +using std::@\libglobal{memory_order_acquire}@; // \seebelow +using std::@\libglobal{memory_order_release}@; // \seebelow +using std::@\libglobal{memory_order_acq_rel}@; // \seebelow +using std::@\libglobal{memory_order_seq_cst}@; // \seebelow + +using std::@\libglobal{atomic_flag}@; // \seebelow + +using std::@\libglobal{atomic_bool}@; // \seebelow +using std::@\libglobal{atomic_char}@; // \seebelow +using std::@\libglobal{atomic_schar}@; // \seebelow +using std::@\libglobal{atomic_uchar}@; // \seebelow +using std::@\libglobal{atomic_short}@; // \seebelow +using std::@\libglobal{atomic_ushort}@; // \seebelow +using std::@\libglobal{atomic_int}@; // \seebelow +using std::@\libglobal{atomic_uint}@; // \seebelow +using std::@\libglobal{atomic_long}@; // \seebelow +using std::@\libglobal{atomic_ulong}@; // \seebelow +using std::@\libglobal{atomic_llong}@; // \seebelow +using std::@\libglobal{atomic_ullong}@; // \seebelow +using std::@\libglobal{atomic_char8_t}@; // \seebelow +using std::@\libglobal{atomic_char16_t}@; // \seebelow +using std::@\libglobal{atomic_char32_t}@; // \seebelow +using std::@\libglobal{atomic_wchar_t}@; // \seebelow +using std::@\libglobal{atomic_int8_t}@; // \seebelow +using std::@\libglobal{atomic_uint8_t}@; // \seebelow +using std::@\libglobal{atomic_int16_t}@; // \seebelow +using std::@\libglobal{atomic_uint16_t}@; // \seebelow +using std::@\libglobal{atomic_int32_t}@; // \seebelow +using std::@\libglobal{atomic_uint32_t}@; // \seebelow +using std::@\libglobal{atomic_int64_t}@; // \seebelow +using std::@\libglobal{atomic_uint64_t}@; // \seebelow +using std::@\libglobal{atomic_int_least8_t}@; // \seebelow +using std::@\libglobal{atomic_uint_least8_t}@; // \seebelow +using std::@\libglobal{atomic_int_least16_t}@; // \seebelow +using std::@\libglobal{atomic_uint_least16_t}@; // \seebelow +using std::@\libglobal{atomic_int_least32_t}@; // \seebelow +using std::@\libglobal{atomic_uint_least32_t}@; // \seebelow +using std::@\libglobal{atomic_int_least64_t}@; // \seebelow +using std::@\libglobal{atomic_uint_least64_t}@; // \seebelow +using std::@\libglobal{atomic_int_fast8_t}@; // \seebelow +using std::@\libglobal{atomic_uint_fast8_t}@; // \seebelow +using std::@\libglobal{atomic_int_fast16_t}@; // \seebelow +using std::@\libglobal{atomic_uint_fast16_t}@; // \seebelow +using std::@\libglobal{atomic_int_fast32_t}@; // \seebelow +using std::@\libglobal{atomic_uint_fast32_t}@; // \seebelow +using std::@\libglobal{atomic_int_fast64_t}@; // \seebelow +using std::@\libglobal{atomic_uint_fast64_t}@; // \seebelow +using std::@\libglobal{atomic_intptr_t}@; // \seebelow +using std::@\libglobal{atomic_uintptr_t}@; // \seebelow +using std::@\libglobal{atomic_size_t}@; // \seebelow +using std::@\libglobal{atomic_ptrdiff_t}@; // \seebelow +using std::@\libglobal{atomic_intmax_t}@; // \seebelow +using std::@\libglobal{atomic_uintmax_t}@; // \seebelow + +using std::@\libglobal{atomic_is_lock_free}@; // \seebelow +using std::@\libglobal{atomic_load}@; // \seebelow +using std::@\libglobal{atomic_load_explicit}@; // \seebelow +using std::@\libglobal{atomic_store}@; // \seebelow +using std::@\libglobal{atomic_store_explicit}@; // \seebelow +using std::@\libglobal{atomic_exchange}@; // \seebelow +using std::@\libglobal{atomic_exchange_explicit}@; // \seebelow +using std::@\libglobal{atomic_compare_exchange_strong}@; // \seebelow +using std::@\libglobal{atomic_compare_exchange_strong_explicit}@; // \seebelow +using std::@\libglobal{atomic_compare_exchange_weak}@; // \seebelow +using std::@\libglobal{atomic_compare_exchange_weak_explicit}@; // \seebelow +using std::@\libglobal{atomic_fetch_add}@; // \seebelow +using std::@\libglobal{atomic_fetch_add_explicit}@; // \seebelow +using std::@\libglobal{atomic_fetch_sub}@; // \seebelow +using std::@\libglobal{atomic_fetch_sub_explicit}@; // \seebelow +using std::@\libglobal{atomic_fetch_or}@; // \seebelow +using std::@\libglobal{atomic_fetch_or_explicit}@; // \seebelow +using std::@\libglobal{atomic_fetch_and}@; // \seebelow +using std::@\libglobal{atomic_fetch_and_explicit}@; // \seebelow +using std::@\libglobal{atomic_flag_test_and_set}@; // \seebelow +using std::@\libglobal{atomic_flag_test_and_set_explicit}@; // \seebelow +using std::@\libglobal{atomic_flag_clear}@; // \seebelow +using std::@\libglobal{atomic_flag_clear_explicit}@; // \seebelow + +using std::@\libglobal{atomic_thread_fence}@; // \seebelow +using std::@\libglobal{atomic_signal_fence}@; // \seebelow +\end{codeblock} + +\pnum +Each \grammarterm{using-declaration} for some name $A$ in the synopsis above +makes available the same entity as \tcode{std::$A$} +declared in \libheaderrefx{atomic}{atomics.syn}. +Each macro listed above other than \tcode{_Atomic(T)} +is defined as in \libheader{atomic}. +It is unspecified whether \libheader{stdatomic.h} makes available +any declarations in namespace \tcode{std}. + +\pnum +Each of the \grammarterm{using-declaration}s for +\tcode{int$N$_t}, \tcode{uint$N$_t}, \tcode{intptr_t}, and \tcode{uintptr_t} +listed above is defined if and only if the implementation defines +the corresponding \grammarterm{typedef-name} in \ref{atomics.syn}. + +\pnum +Neither the \tcode{_Atomic} macro, +nor any of the non-macro global namespace declarations, +are provided by any \Cpp{} standard library header +other than \libheader{stdatomic.h}. + +\pnum +\recommended +Implementations should ensure +that C and \Cpp{} representations of atomic objects are compatible, +so that the same object can be accessed as both an \tcode{_Atomic(T)} +from C code and an \tcode{atomic} from \Cpp{} code. +The representations should be the same, and +the mechanisms used to ensure atomicity and memory ordering +should be compatible. + \rSec1[thread.mutex]{Mutual exclusion} \rSec2[thread.mutex.general]{General} diff --git a/source/utilities.tex b/source/utilities.tex index a18164278f..f2c3b14f78 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -10,7 +10,6 @@ \begin{libsumtab}{General utilities library summary}{utilities.summary} \ref{utility} & Utility components & \tcode{} \\ -\ref{intseq} & Compile-time integer sequences & \\ \ref{pairs} & Pairs & \\ \rowsep \ref{tuple} & Tuples & \tcode{} \\ \rowsep \ref{optional} & Optional objects & \tcode{} \\ \rowsep @@ -18,17 +17,12 @@ \ref{any} & Storage for any type & \tcode{} \\ \rowsep \ref{expected} & Expected objects & \tcode{} \\ \rowsep \ref{bitset} & Fixed-size sequences of bits & \tcode{} \\ \rowsep -\ref{memory} & Memory & \tcode{}, \tcode{} \\ \rowsep -\ref{smartptr} & Smart pointers & \tcode{} \\ \rowsep -\ref{mem.res} & Memory resources & \tcode{} \\ \rowsep -\ref{allocator.adaptor} & Scoped allocators & \tcode{} \\ \rowsep \ref{function.objects} & Function objects & \tcode{} \\ \rowsep -\ref{meta} & Type traits & \tcode{} \\ \rowsep -\ref{ratio} & Compile-time rational arithmetic & \tcode{} \\ \rowsep \ref{type.index} & Type indexes & \tcode{} \\ \rowsep \ref{execpol} & Execution policies & \tcode{} \\ \rowsep \ref{charconv} & Primitive numeric conversions & \tcode{} \\ \rowsep -\ref{format} & Formatting & \tcode{} \\ +\ref{format} & Formatting & \tcode{} \\ \rowsep +\ref{bit} & Bit manipulation & \tcode{} \\ \end{libsumtab} \rSec1[utility]{Utility components} @@ -648,61 +642,6 @@ \end{example} \end{itemdescr} -\rSec1[intseq]{Compile-time integer sequences} - -\rSec2[intseq.general]{In general} - -\pnum -The library provides a class template that can represent an integer sequence. -When used as an argument to a function template the template parameter pack defining the -sequence can be deduced and used in a pack expansion. -\begin{note} -The \tcode{index_sequence} alias template is provided for the common case of -an integer sequence of type \tcode{size_t}; see also \ref{tuple.apply}. -\end{note} - -\rSec2[intseq.intseq]{Class template \tcode{integer_sequence}} - -\indexlibraryglobal{integer_sequence}% -\indexlibrarymember{value_type}{integer_sequence}% -\begin{codeblock} -namespace std { - template struct integer_sequence { - using value_type = T; - static constexpr size_t size() noexcept { return sizeof...(I); } - }; -} -\end{codeblock} - -\pnum -\mandates -\tcode{T} is an integer type. - -\rSec2[intseq.make]{Alias template \tcode{make_integer_sequence}} - -\indexlibraryglobal{make_integer_sequence}% -\begin{itemdecl} -template - using make_integer_sequence = integer_sequence; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\mandates -$\tcode{N} \geq 0$. - -\pnum -The alias template -\tcode{make_integer_sequence} denotes a specialization of -\tcode{integer_sequence} with \tcode{N} non-type template arguments. -The type \tcode{make_integer_sequence} is an alias for the type -\tcode{integer_sequence}. -\begin{note} -\tcode{make_integer_sequence} is an alias for the type -\tcode{integer_sequence}. -\end{note} -\end{itemdescr} - \rSec1[pairs]{Pairs} \rSec2[pairs.general]{In general} @@ -9421,12580 +9360,3293 @@ (see~\ref{ostream.formatted}). \end{itemdescr} -\rSec1[memory]{Memory} +\rSec1[function.objects]{Function objects} -\rSec2[memory.general]{In general} +\rSec2[function.objects.general]{General} \pnum -Subclause~\ref{memory} describes the contents of the header -\libheaderref{memory} and some -of the contents of the header \libheaderref{cstdlib}. +A \defnx{function object type}{function object!type} is an object +type\iref{term.object.type} that can be the type of the +\grammarterm{postfix-expression} +in a function call\iref{expr.call,over.match.call}. +\begin{footnote} +Such a type is a function +pointer or a class type which has a member \tcode{operator()} or a class type +which has a conversion to a pointer to function. +\end{footnote} +A \defn{function object} is an +object of a function object type. In the places where one would expect to pass a +pointer to a function to an algorithmic template\iref{algorithms}, the +interface is specified to accept a function object. This not only makes +algorithmic templates work with pointers to functions, but also enables them to +work with arbitrary function objects. -\rSec2[memory.syn]{Header \tcode{} synopsis} +\rSec2[functional.syn]{Header \tcode{} synopsis} -\pnum -The header \libheaderdef{memory} defines several types and function templates that -describe properties of pointers and pointer-like types, manage memory -for containers and other template types, destroy objects, and -construct objects in -uninitialized memory -buffers~(\ref{pointer.traits}--\ref{specialized.addressof} and \ref{specialized.algorithms}). -The header also defines the templates -\tcode{unique_ptr}, \tcode{shared_ptr}, \tcode{weak_ptr}, -\tcode{out_ptr_t}, \tcode{inout_ptr_t}, and various function -templates that operate on objects of these types\iref{smartptr}. +\indexheader{functional}% +\indexlibraryglobal{unwrap_ref_decay}% +\indexlibraryglobal{unwrap_ref_decay_t}% +\begin{codeblock} +namespace std { + // \ref{func.invoke}, invoke + template + constexpr invoke_result_t invoke(F&& f, Args&&... args) + noexcept(is_nothrow_invocable_v); -\pnum -Let \tcode{\exposid{POINTER_OF}(T)} denote a type that is -\begin{itemize} -\item -\tcode{T::pointer} if the \grammarterm{qualified-id} \tcode{T::pointer} -is valid and denotes a type, -\item -otherwise, \tcode{T::element_type*} -if the \grammarterm{qualified-id} \tcode{T::element_type} -is valid and denotes a type, -\item -otherwise, \tcode{pointer_traits::element_type*}. -\end{itemize} + template + constexpr R invoke_r(F&& f, Args&&... args) + noexcept(is_nothrow_invocable_r_v); -\pnum -Let \tcode{\exposid{POINTER_OF_OR}(T, U)} denote a type that is: -\begin{itemize} -\item -\tcode{\exposid{POINTER_OF}(T)} -if \tcode{\exposid{POINTER_OF}(T)} is valid and denotes a type, -\item -otherwise, \tcode{U}. -\end{itemize} + // \ref{refwrap}, \tcode{reference_wrapper} + template class reference_wrapper; -\begin{codeblock} -#include // see \ref{compare.syn} + template constexpr reference_wrapper ref(T&) noexcept; + template constexpr reference_wrapper cref(const T&) noexcept; + template void ref(const T&&) = delete; + template void cref(const T&&) = delete; -namespace std { - // \ref{pointer.traits}, pointer traits - template struct pointer_traits; - template struct pointer_traits; + template constexpr reference_wrapper ref(reference_wrapper) noexcept; + template constexpr reference_wrapper cref(reference_wrapper) noexcept; - // \ref{pointer.conversion}, pointer conversion - template - constexpr T* to_address(T* p) noexcept; - template - constexpr auto to_address(const Ptr& p) noexcept; - - // \ref{ptr.align}, pointer alignment - void* align(size_t alignment, size_t size, void*& ptr, size_t& space); - template - [[nodiscard]] constexpr T* assume_aligned(T* ptr); - - // \ref{allocator.tag}, allocator argument tag - struct allocator_arg_t { explicit allocator_arg_t() = default; }; - inline constexpr allocator_arg_t allocator_arg{}; - - // \ref{allocator.uses}, \tcode{uses_allocator} - template struct uses_allocator; - - // \ref{allocator.uses.trait}, \tcode{uses_allocator} - template - inline constexpr bool @\libglobal{uses_allocator_v}@ = uses_allocator::value; - - // \ref{allocator.uses.construction}, uses-allocator construction - template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, - Args&&... args) noexcept; - template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, - Tuple1&& x, Tuple2&& y) noexcept; - template - constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept; - template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, - U&& u, V&& v) noexcept; - template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, - pair& pr) noexcept; - template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, - const pair& pr) noexcept; - template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, - pair&& pr) noexcept; - template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, - const pair&& pr) noexcept; - template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, U&& u) noexcept; - template - constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args); - template - constexpr T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, - Args&&... args); - - // \ref{allocator.traits}, allocator traits - template struct allocator_traits; - - template - struct allocation_result { - Pointer ptr; - size_t count; - }; + // \ref{arithmetic.operations}, arithmetic operations + template struct plus; + template struct minus; + template struct multiplies; + template struct divides; + template struct modulus; + template struct negate; + template<> struct plus; + template<> struct minus; + template<> struct multiplies; + template<> struct divides; + template<> struct modulus; + template<> struct negate; - template - [[nodiscard] constexpr allocation_result::pointer> - allocate_at_least(Allocator& a, size_t n); + // \ref{comparisons}, comparisons + template struct equal_to; + template struct not_equal_to; + template struct greater; + template struct less; + template struct greater_equal; + template struct less_equal; + template<> struct equal_to; + template<> struct not_equal_to; + template<> struct greater; + template<> struct less; + template<> struct greater_equal; + template<> struct less_equal; - // \ref{default.allocator}, the default allocator - template class allocator; - template - constexpr bool operator==(const allocator&, const allocator&) noexcept; + // \ref{comparisons.three.way}, class \tcode{compare_three_way} + struct compare_three_way; + + // \ref{logical.operations}, logical operations + template struct logical_and; + template struct logical_or; + template struct logical_not; + template<> struct logical_and; + template<> struct logical_or; + template<> struct logical_not; + + // \ref{bitwise.operations}, bitwise operations + template struct bit_and; + template struct bit_or; + template struct bit_xor; + template struct bit_not; + template<> struct bit_and; + template<> struct bit_or; + template<> struct bit_xor; + template<> struct bit_not; + + // \ref{func.identity}, identity + struct identity; + + // \ref{func.not.fn}, function template \tcode{not_fn} + template constexpr @\unspec@ not_fn(F&& f); + + // \ref{func.bind.partial}, function templates \tcode{bind_front} and \tcode{bind_back} + template constexpr @\unspec@ bind_front(F&&, Args&&...); + template constexpr @\unspec@ bind_back(F&&, Args&&...); - // \ref{specialized.addressof}, addressof + // \ref{func.bind}, bind + template struct is_bind_expression; template - constexpr T* addressof(T& r) noexcept; + inline constexpr bool @\libglobal{is_bind_expression_v}@ = is_bind_expression::value; + template struct is_placeholder; template - const T* addressof(const T&&) = delete; - - // \ref{specialized.algorithms}, specialized algorithms - // \ref{special.mem.concepts}, special memory concepts - template - concept @\exposconcept{nothrow-input-iterator}@ = @\seebelow@; // \expos - template - concept @\exposconcept{nothrow-forward-iterator}@ = @\seebelow@; // \expos - template - concept @\exposconcept{nothrow-sentinel-for}@ = @\seebelow@; // \expos - template - concept @\exposconcept{nothrow-input-range}@ = @\seebelow@; // \expos - template - concept @\exposconcept{nothrow-forward-range}@ = @\seebelow@; // \expos - - template - void uninitialized_default_construct(NoThrowForwardIterator first, - NoThrowForwardIterator last); - template - void uninitialized_default_construct(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - NoThrowForwardIterator first, - NoThrowForwardIterator last); - template - NoThrowForwardIterator - uninitialized_default_construct_n(NoThrowForwardIterator first, Size n); - template - NoThrowForwardIterator - uninitialized_default_construct_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - NoThrowForwardIterator first, Size n); - - namespace ranges { - template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S> - requires @\libconcept{default_initializable}@> - I uninitialized_default_construct(I first, S last); - template<@\exposconcept{nothrow-forward-range}@ R> - requires @\libconcept{default_initializable}@> - borrowed_iterator_t uninitialized_default_construct(R&& r); - - template<@\exposconcept{nothrow-forward-iterator}@ I> - requires @\libconcept{default_initializable}@> - I uninitialized_default_construct_n(I first, iter_difference_t n); - } + inline constexpr int @\libglobal{is_placeholder_v}@ = is_placeholder::value; - template - void uninitialized_value_construct(NoThrowForwardIterator first, - NoThrowForwardIterator last); - template - void uninitialized_value_construct(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - NoThrowForwardIterator first, - NoThrowForwardIterator last); - template - NoThrowForwardIterator - uninitialized_value_construct_n(NoThrowForwardIterator first, Size n); - template - NoThrowForwardIterator - uninitialized_value_construct_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - NoThrowForwardIterator first, Size n); + template + constexpr @\unspec@ bind(F&&, BoundArgs&&...); + template + constexpr @\unspec@ bind(F&&, BoundArgs&&...); - namespace ranges { - template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S> - requires @\libconcept{default_initializable}@> - I uninitialized_value_construct(I first, S last); - template<@\exposconcept{nothrow-forward-range}@ R> - requires @\libconcept{default_initializable}@> - borrowed_iterator_t uninitialized_value_construct(R&& r); - - template<@\exposconcept{nothrow-forward-iterator}@ I> - requires @\libconcept{default_initializable}@> - I uninitialized_value_construct_n(I first, iter_difference_t n); + namespace placeholders { + // \tcode{\placeholder{M}} is the \impldef{number of placeholders for bind expressions} number of placeholders + @\seebelownc@ _1; + @\seebelownc@ _2; + . + . + . + @\seebelownc@ _@\placeholdernc{M}@; } - template - NoThrowForwardIterator uninitialized_copy(InputIterator first, InputIterator last, - NoThrowForwardIterator result); - template - NoThrowForwardIterator uninitialized_copy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - ForwardIterator first, ForwardIterator last, - NoThrowForwardIterator result); - template - NoThrowForwardIterator uninitialized_copy_n(InputIterator first, Size n, - NoThrowForwardIterator result); - template - NoThrowForwardIterator uninitialized_copy_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - ForwardIterator first, Size n, - NoThrowForwardIterator result); + // \ref{func.memfn}, member function adaptors + template + constexpr @\unspec@ mem_fn(R T::*) noexcept; - namespace ranges { - template - using uninitialized_copy_result = in_out_result; - template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S1, - @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S2> - requires @\libconcept{constructible_from}@, iter_reference_t> - uninitialized_copy_result - uninitialized_copy(I ifirst, S1 ilast, O ofirst, S2 olast); - template<@\libconcept{input_range}@ IR, @\exposconcept{nothrow-forward-range}@ OR> - requires @\libconcept{constructible_from}@, range_reference_t> - uninitialized_copy_result, borrowed_iterator_t> - uninitialized_copy(IR&& in_range, OR&& out_range); - - template - using uninitialized_copy_n_result = in_out_result; - template<@\libconcept{input_iterator}@ I, @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S> - requires @\libconcept{constructible_from}@, iter_reference_t> - uninitialized_copy_n_result - uninitialized_copy_n(I ifirst, iter_difference_t n, O ofirst, S olast); - } + // \ref{func.wrap}, polymorphic function wrappers + class bad_function_call; - template - NoThrowForwardIterator uninitialized_move(InputIterator first, InputIterator last, - NoThrowForwardIterator result); - template - NoThrowForwardIterator uninitialized_move(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - ForwardIterator first, ForwardIterator last, - NoThrowForwardIterator result); - template - pair - uninitialized_move_n(InputIterator first, Size n, NoThrowForwardIterator result); - template - pair - uninitialized_move_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - ForwardIterator first, Size n, NoThrowForwardIterator result); + template class function; // \notdef + template class function; - namespace ranges { - template - using uninitialized_move_result = in_out_result; - template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S1, - @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S2> - requires @\libconcept{constructible_from}@, iter_rvalue_reference_t> - uninitialized_move_result - uninitialized_move(I ifirst, S1 ilast, O ofirst, S2 olast); - template<@\libconcept{input_range}@ IR, @\exposconcept{nothrow-forward-range}@ OR> - requires @\libconcept{constructible_from}@, range_rvalue_reference_t> - uninitialized_move_result, borrowed_iterator_t> - uninitialized_move(IR&& in_range, OR&& out_range); - - template - using uninitialized_move_n_result = in_out_result; - template<@\libconcept{input_iterator}@ I, - @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S> - requires @\libconcept{constructible_from}@, iter_rvalue_reference_t> - uninitialized_move_n_result - uninitialized_move_n(I ifirst, iter_difference_t n, O ofirst, S olast); - } + // \ref{func.wrap.func.alg}, specialized algorithms + template + void swap(function&, function&) noexcept; - template - void uninitialized_fill(NoThrowForwardIterator first, NoThrowForwardIterator last, - const T& x); - template - void uninitialized_fill(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - NoThrowForwardIterator first, NoThrowForwardIterator last, - const T& x); - template - NoThrowForwardIterator - uninitialized_fill_n(NoThrowForwardIterator first, Size n, const T& x); - template - NoThrowForwardIterator - uninitialized_fill_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - NoThrowForwardIterator first, Size n, const T& x); + // \ref{func.wrap.func.nullptr}, null pointer comparison operator functions + template + bool operator==(const function&, nullptr_t) noexcept; - namespace ranges { - template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S, class T> - requires @\libconcept{constructible_from}@, const T&> - I uninitialized_fill(I first, S last, const T& x); - template<@\exposconcept{nothrow-forward-range}@ R, class T> - requires @\libconcept{constructible_from}@, const T&> - borrowed_iterator_t uninitialized_fill(R&& r, const T& x); - - template<@\exposconcept{nothrow-forward-iterator}@ I, class T> - requires @\libconcept{constructible_from}@, const T&> - I uninitialized_fill_n(I first, iter_difference_t n, const T& x); - } + // \ref{func.wrap.move}, move only wrapper + template class move_only_function; // \notdef + template + class move_only_function; // \seebelow - // \ref{specialized.construct}, \tcode{construct_at} - template - constexpr T* construct_at(T* location, Args&&... args); + // \ref{func.search}, searchers + template> + class default_searcher; - namespace ranges { - template - constexpr T* construct_at(T* location, Args&&... args); - } + template::value_type>, + class BinaryPredicate = equal_to<>> + class boyer_moore_searcher; + + template::value_type>, + class BinaryPredicate = equal_to<>> + class boyer_moore_horspool_searcher; - // \ref{specialized.destroy}, \tcode{destroy} + // \ref{unord.hash}, class template hash template - constexpr void destroy_at(T* location); - template - constexpr void destroy(NoThrowForwardIterator first, NoThrowForwardIterator last); - template - void destroy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - NoThrowForwardIterator first, NoThrowForwardIterator last); - template - constexpr NoThrowForwardIterator destroy_n(NoThrowForwardIterator first, Size n); - template - NoThrowForwardIterator destroy_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - NoThrowForwardIterator first, Size n); + struct hash; namespace ranges { - template<@\libconcept{destructible}@ T> - constexpr void destroy_at(T* location) noexcept; - - template<@\exposconcept{nothrow-input-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S> - requires @\libconcept{destructible}@> - constexpr I destroy(I first, S last) noexcept; - template<@\exposconcept{nothrow-input-range}@ R> - requires @\libconcept{destructible}@> - constexpr borrowed_iterator_t destroy(R&& r) noexcept; - - template<@\exposconcept{nothrow-input-iterator}@ I> - requires @\libconcept{destructible}@> - constexpr I destroy_n(I first, iter_difference_t n) noexcept; + // \ref{range.cmp}, concept-constrained comparisons + struct equal_to; + struct not_equal_to; + struct greater; + struct less; + struct greater_equal; + struct less_equal; } +} +\end{codeblock} - // \ref{unique.ptr}, class template \tcode{unique_ptr} - template struct default_delete; - template struct default_delete; - template> class unique_ptr; - template class unique_ptr; +\pnum +\begin{example} +If a \Cpp{} program wants to have a by-element addition of two vectors \tcode{a} +and \tcode{b} containing \tcode{double} and put the result into \tcode{a}, +it can do: - template - constexpr unique_ptr make_unique(Args&&... args); // \tcode{T} is not array - template - constexpr unique_ptr make_unique(size_t n); // \tcode{T} is \tcode{U[]} - template - @\unspecnc@ make_unique(Args&&...) = delete; // \tcode{T} is \tcode{U[N]} +\begin{codeblock} +transform(a.begin(), a.end(), b.begin(), a.begin(), plus()); +\end{codeblock} +\end{example} - template - constexpr unique_ptr make_unique_for_overwrite(); // \tcode{T} is not array - template - constexpr unique_ptr make_unique_for_overwrite(size_t n); // \tcode{T} is \tcode{U[]} - template - @\unspecnc@ make_unique_for_overwrite(Args&&...) = delete; // \tcode{T} is \tcode{U[N]} - - template - constexpr void swap(unique_ptr& x, unique_ptr& y) noexcept; - - template - constexpr bool operator==(const unique_ptr& x, const unique_ptr& y); - template - bool operator<(const unique_ptr& x, const unique_ptr& y); - template - bool operator>(const unique_ptr& x, const unique_ptr& y); - template - bool operator<=(const unique_ptr& x, const unique_ptr& y); - template - bool operator>=(const unique_ptr& x, const unique_ptr& y); - template - requires @\libconcept{three_way_comparable_with}@::pointer, - typename unique_ptr::pointer> - compare_three_way_result_t::pointer, - typename unique_ptr::pointer> - operator<=>(const unique_ptr& x, const unique_ptr& y); - - template - constexpr bool operator==(const unique_ptr& x, nullptr_t) noexcept; - template - constexpr bool operator<(const unique_ptr& x, nullptr_t); - template - constexpr bool operator<(nullptr_t, const unique_ptr& y); - template - constexpr bool operator>(const unique_ptr& x, nullptr_t); - template - constexpr bool operator>(nullptr_t, const unique_ptr& y); - template - constexpr bool operator<=(const unique_ptr& x, nullptr_t); - template - constexpr bool operator<=(nullptr_t, const unique_ptr& y); - template - constexpr bool operator>=(const unique_ptr& x, nullptr_t); - template - constexpr bool operator>=(nullptr_t, const unique_ptr& y); - template - requires @\libconcept{three_way_comparable}@::pointer> - constexpr compare_three_way_result_t::pointer> - operator<=>(const unique_ptr& x, nullptr_t); - - template - basic_ostream& operator<<(basic_ostream& os, const unique_ptr& p); - - // \ref{util.smartptr.weak.bad}, class \tcode{bad_weak_ptr} - class bad_weak_ptr; - - // \ref{util.smartptr.shared}, class template \tcode{shared_ptr} - template class shared_ptr; - - // \ref{util.smartptr.shared.create}, \tcode{shared_ptr} creation - template - shared_ptr make_shared(Args&&... args); // \tcode{T} is not array - template - shared_ptr allocate_shared(const A& a, Args&&... args); // \tcode{T} is not array +\pnum +\begin{example} +To negate every element of \tcode{a}: - template - shared_ptr make_shared(size_t N); // \tcode{T} is \tcode{U[]} - template - shared_ptr allocate_shared(const A& a, size_t N); // \tcode{T} is \tcode{U[]} +\begin{codeblock} +transform(a.begin(), a.end(), a.begin(), negate()); +\end{codeblock} - template - shared_ptr make_shared(); // \tcode{T} is \tcode{U[N]} - template - shared_ptr allocate_shared(const A& a); // \tcode{T} is \tcode{U[N]} +\end{example} - template - shared_ptr make_shared(size_t N, const remove_extent_t& u); // \tcode{T} is \tcode{U[]} - template - shared_ptr allocate_shared(const A& a, size_t N, - const remove_extent_t& u); // \tcode{T} is \tcode{U[]} +\rSec2[func.def]{Definitions} - template - shared_ptr make_shared(const remove_extent_t& u); // \tcode{T} is \tcode{U[N]} - template - shared_ptr allocate_shared(const A& a, const remove_extent_t& u); // \tcode{T} is \tcode{U[N]} +\pnum +The following definitions apply to this Clause: - template - shared_ptr make_shared_for_overwrite(); // \tcode{T} is not \tcode{U[]} - template - shared_ptr allocate_shared_for_overwrite(const A& a); // \tcode{T} is not \tcode{U[]} +\pnum +A \defn{call signature} is the name of a return type followed by a +parenthesized comma-separated list of zero or more argument types. - template - shared_ptr make_shared_for_overwrite(size_t N); // \tcode{T} is \tcode{U[]} - template - shared_ptr allocate_shared_for_overwrite(const A& a, size_t N); // \tcode{T} is \tcode{U[]} +\pnum +A \defnadj{callable}{type} is a function object type\iref{function.objects} or a pointer to member. - // \ref{util.smartptr.shared.cmp}, \tcode{shared_ptr} comparisons - template - bool operator==(const shared_ptr& a, const shared_ptr& b) noexcept; - template - strong_ordering operator<=>(const shared_ptr& a, const shared_ptr& b) noexcept; +\pnum +A \defnadj{callable}{object} is an object of a callable type. - template - bool operator==(const shared_ptr& x, nullptr_t) noexcept; - template - strong_ordering operator<=>(const shared_ptr& x, nullptr_t) noexcept; - - // \ref{util.smartptr.shared.spec}, \tcode{shared_ptr} specialized algorithms - template - void swap(shared_ptr& a, shared_ptr& b) noexcept; - - // \ref{util.smartptr.shared.cast}, \tcode{shared_ptr} casts - template - shared_ptr static_pointer_cast(const shared_ptr& r) noexcept; - template - shared_ptr static_pointer_cast(shared_ptr&& r) noexcept; - template - shared_ptr dynamic_pointer_cast(const shared_ptr& r) noexcept; - template - shared_ptr dynamic_pointer_cast(shared_ptr&& r) noexcept; - template - shared_ptr const_pointer_cast(const shared_ptr& r) noexcept; - template - shared_ptr const_pointer_cast(shared_ptr&& r) noexcept; - template - shared_ptr reinterpret_pointer_cast(const shared_ptr& r) noexcept; - template - shared_ptr reinterpret_pointer_cast(shared_ptr&& r) noexcept; - - // \ref{util.smartptr.getdeleter}, \tcode{shared_ptr} \tcode{get_deleter} - template - D* get_deleter(const shared_ptr& p) noexcept; - - // \ref{util.smartptr.shared.io}, \tcode{shared_ptr} I/O - template - basic_ostream& operator<<(basic_ostream& os, const shared_ptr& p); +\pnum +A \defnx{call wrapper type}{call wrapper!type} is a type that holds a callable object +and supports a call operation that forwards to that object. - // \ref{util.smartptr.weak}, class template \tcode{weak_ptr} - template class weak_ptr; +\pnum +A \defn{call wrapper} is an object of a call wrapper type. - // \ref{util.smartptr.weak.spec}, \tcode{weak_ptr} specialized algorithms - template void swap(weak_ptr& a, weak_ptr& b) noexcept; +\pnum +A \defn{target object} is the callable object held by a call wrapper. - // \ref{util.smartptr.ownerless}, class template \tcode{owner_less} - template struct owner_less; +\pnum +A call wrapper type may additionally hold +a sequence of objects and references +that may be passed as arguments to the target object. +These entities are collectively referred to +as \defnx{bound argument entities}{bound argument entity}. - // \ref{util.smartptr.enab}, class template \tcode{enable_shared_from_this} - template class enable_shared_from_this; +\pnum +The target object and bound argument entities of the call wrapper are +collectively referred to as \defnx{state entities}{state entity}. - // \ref{util.smartptr.hash}, hash support - template struct hash; - template struct hash>; - template struct hash>; +\rSec2[func.require]{Requirements} - // \ref{util.smartptr.atomic}, atomic smart pointers - template struct atomic; - template struct atomic>; - template struct atomic>; +\pnum +\indexlibrary{invoke@\tcode{\placeholder{INVOKE}}}% +Define \tcode{\placeholdernc{INVOKE}(f, t$_1$, t$_2$, $\dotsc$, t$_N$)} as follows: +\begin{itemize} +\item \tcode{(t$_1$.*f)(t$_2$, $\dotsc$, t$_N$)} when \tcode{f} is a pointer to a +member function of a class \tcode{T} +and \tcode{is_base_of_v>} is \tcode{true}; - // \ref{out.ptr.t}, class template \tcode{out_ptr_t} - template - class out_ptr_t; +\item \tcode{(t$_1$.get().*f)(t$_2$, $\dotsc$, t$_N$)} when \tcode{f} is a pointer to a +member function of a class \tcode{T} +and \tcode{remove_cvref_t} is a specialization of \tcode{reference_wrapper}; - // \ref{out.ptr}, function template \tcode{out_ptr} - template - auto out_ptr(Smart& s, Args&&... args); +\item \tcode{((*t$_1$).*f)(t$_2$, $\dotsc$, t$_N$)} when \tcode{f} is a pointer to a +member function of a class \tcode{T} +and \tcode{t$_1$} does not satisfy the previous two items; - // \ref{inout.ptr.t}, class template \tcode{inout_ptr_t} - template - class inout_ptr_t; +\item \tcode{t$_1$.*f} when \tcode{N == 1} and \tcode{f} is a pointer to +data member of a class \tcode{T} +and \tcode{is_base_of_v>} is \tcode{true}; - // \ref{inout.ptr}, function template \tcode{inout_ptr} - template - auto inout_ptr(Smart& s, Args&&... args); -} -\end{codeblock} +\item \tcode{t$_1$.get().*f} when \tcode{N == 1} and \tcode{f} is a pointer to +data member of a class \tcode{T} +and \tcode{remove_cvref_t} is a specialization of \tcode{reference_wrapper}; -\rSec2[pointer.traits]{Pointer traits} +\item \tcode{(*t$_1$).*f} when \tcode{N == 1} and \tcode{f} is a pointer to +data member of a class \tcode{T} +and \tcode{t$_1$} does not satisfy the previous two items; -\rSec3[pointer.traits.general]{General} +\item \tcode{f(t$_1$, t$_2$, $\dotsc$, t$_N$)} in all other cases. +\end{itemize} \pnum -The class template \tcode{pointer_traits} supplies a uniform interface to certain -attributes of pointer-like types. +\indexlibrary{invoke@\tcode{\placeholder{INVOKE}}}% +Define \tcode{\placeholdernc{INVOKE}(f, t$_1$, t$_2$, $\dotsc$, t$_N$)} as +\tcode{static_cast(\placeholdernc{INVOKE}(f, t$_1$, t$_2$, $\dotsc$, t$_N$))} +if \tcode{R} is \cv{}~\keyword{void}, otherwise +\tcode{\placeholdernc{INVOKE}(f, t$_1$, t$_2$, $\dotsc$, t$_N$)} implicitly converted +to \tcode{R}. +If +\tcode{reference_converts_from_temporary_v} +is \tcode{true}, +\tcode{\placeholdernc{INVOKE}(f, t$_1$, t$_2$, $\dotsc$, t$_N$)} +is ill-formed. -\indexlibraryglobal{pointer_traits}% +\pnum +\indextext{call wrapper}% +\indextext{call wrapper!simple}% +\indextext{call wrapper!forwarding}% +Every call wrapper\iref{func.def} meets the \oldconcept{MoveConstructible} +and \oldconcept{Destructible} requirements. +An \defn{argument forwarding call wrapper} is a +call wrapper that can be called with an arbitrary argument list +and delivers the arguments to the target object as references. +This forwarding step delivers rvalue arguments as rvalue references +and lvalue arguments as lvalue references. +\begin{note} +In a typical implementation, argument forwarding call wrappers have +an overloaded function call operator of the form \begin{codeblock} -namespace std { - template struct pointer_traits { - using pointer = Ptr; - using element_type = @\seebelow@; - using difference_type = @\seebelow@; - - template using rebind = @\seebelow@; +template + constexpr R operator()(UnBoundArgs&&... unbound_args) @\textit{cv-qual}@; +\end{codeblock} +\end{note} - static pointer pointer_to(@\seebelow@ r); - }; +\pnum +\label{term.perfect.forwarding.call.wrapper}% +A \defnadj{perfect forwarding}{call wrapper} is +an argument forwarding call wrapper +that forwards its state entities to the underlying call expression. +This forwarding step delivers a state entity of type \tcode{T} +as \cv{} \tcode{T\&} +when the call is performed on an lvalue of the call wrapper type and +as \cv{} \tcode{T\&\&} otherwise, +where \cv{} represents the cv-qualifiers of the call wrapper and +where \cv{} shall be neither \tcode{volatile} nor \tcode{const volatile}. - template struct pointer_traits { - using pointer = T*; - using element_type = T; - using difference_type = ptrdiff_t; +\pnum +A \defn{call pattern} defines the semantics of invoking +a perfect forwarding call wrapper. +A postfix call performed on a perfect forwarding call wrapper is +expression-equivalent\iref{defns.expression.equivalent} to +an expression \tcode{e} determined from its call pattern \tcode{cp} +by replacing all occurrences +of the arguments of the call wrapper and its state entities +with references as described in the corresponding forwarding steps. - template using rebind = U*; +\pnum +\label{term.simple.call.wrapper}% +A \defn{simple call wrapper} is a perfect forwarding call wrapper that meets +the \oldconcept{CopyConstructible} and \oldconcept{CopyAssignable} requirements +and whose copy constructor, move constructor, and assignment operators +are constexpr functions that do not throw exceptions. - static constexpr pointer pointer_to(@\seebelow@ r) noexcept; - }; -} -\end{codeblock} +\pnum +The copy/move constructor of an argument forwarding call wrapper has +the same apparent semantics +as if memberwise copy/move of its state entities +were performed\iref{class.copy.ctor}. +\begin{note} +This implies that each of the copy/move constructors has +the same exception-specification as +the corresponding implicit definition and is declared as \keyword{constexpr} +if the corresponding implicit definition would be considered to be constexpr. +\end{note} -\rSec3[pointer.traits.types]{Member types} +\pnum +Argument forwarding call wrappers returned by +a given standard library function template have the same type +if the types of their corresponding state entities are the same. -\indexlibrarymember{element_type}{pointer_traits}% +\rSec2[func.invoke]{\tcode{invoke} functions} +\indexlibraryglobal{invoke}% +\indexlibrary{invoke@\tcode{\placeholder{INVOKE}}}% \begin{itemdecl} -using element_type = @\seebelow@; +template + constexpr invoke_result_t invoke(F&& f, Args&&... args) + noexcept(is_nothrow_invocable_v); \end{itemdecl} \begin{itemdescr} \pnum -\ctype \tcode{Ptr::element_type} if -the \grammarterm{qualified-id} \tcode{Ptr::element_type} is valid and denotes a -type\iref{temp.deduct}; otherwise, \tcode{T} if -\tcode{Ptr} is a class template instantiation of the form \tcode{SomePointer}, -where \tcode{Args} is zero or more type arguments; otherwise, the specialization is -ill-formed. +\constraints +\tcode{is_invocable_v} is \tcode{true}. + +\pnum +\returns +\tcode{\placeholdernc{INVOKE}(std::forward(f), std::forward(args)...)}\iref{func.require}. \end{itemdescr} -\indexlibrarymember{difference_type}{pointer_traits}% +\indexlibraryglobal{invoke_r}% \begin{itemdecl} -using difference_type = @\seebelow@; +template + constexpr R invoke_r(F&& f, Args&&... args) + noexcept(is_nothrow_invocable_r_v); \end{itemdecl} \begin{itemdescr} \pnum -\ctype \tcode{Ptr::difference_type} if -the \grammarterm{qualified-id} \tcode{Ptr::difference_type} is valid and denotes a -type\iref{temp.deduct}; otherwise, -\tcode{ptrdiff_t}. +\constraints +\tcode{is_invocable_r_v} is \tcode{true}. + +\pnum +\returns +\tcode{\placeholdernc{INVOKE}(std::forward(f), std::forward(args)...)}\iref{func.require}. \end{itemdescr} -\indexlibrarymember{rebind}{pointer_traits}% -\begin{itemdecl} -template using rebind = @\seebelow@; -\end{itemdecl} +\rSec2[refwrap]{Class template \tcode{reference_wrapper}} + +\rSec3[refwrap.general]{General} + +\indexlibraryglobal{reference_wrapper}% +\indextext{function object!\idxcode{reference_wrapper}}% +\begin{codeblock} +namespace std { + template class reference_wrapper { + public: + // types + using type = T; + + // \ref{refwrap.const}, constructors + template + constexpr reference_wrapper(U&&) noexcept(@\seebelow@); + constexpr reference_wrapper(const reference_wrapper& x) noexcept; + + // \ref{refwrap.assign}, assignment + constexpr reference_wrapper& operator=(const reference_wrapper& x) noexcept; + + // \ref{refwrap.access}, access + constexpr operator T& () const noexcept; + constexpr T& get() const noexcept; + + // \ref{refwrap.invoke}, invocation + template + constexpr invoke_result_t operator()(ArgTypes&&...) const; + }; + + template + reference_wrapper(T&) -> reference_wrapper; +} +\end{codeblock} -\begin{itemdescr} \pnum -\templalias \tcode{Ptr::rebind} if -the \grammarterm{qualified-id} \tcode{Ptr::rebind} is valid and denotes a -type\iref{temp.deduct}; otherwise, -\tcode{SomePointer} if -\tcode{Ptr} is a class template instantiation of the form \tcode{SomePointer}, -where \tcode{Args} is zero or more type arguments; otherwise, the instantiation of -\tcode{rebind} is ill-formed. -\end{itemdescr} +\tcode{reference_wrapper} is a \oldconcept{CopyConstructible} and \oldconcept{CopyAssignable} wrapper +around a reference to an object or function of type \tcode{T}. + +\pnum +\tcode{reference_wrapper} is +a trivially copyable type\iref{term.trivially.copyable.type}. + +\pnum +The template parameter \tcode{T} of \tcode{reference_wrapper} +may be an incomplete type. -\rSec3[pointer.traits.functions]{Member functions} +\rSec3[refwrap.const]{Constructors} -\indexlibrarymember{pointer_to}{pointer_traits}% +\indexlibraryctor{reference_wrapper}% \begin{itemdecl} -static pointer pointer_traits::pointer_to(@\seebelow@ r); -static constexpr pointer pointer_traits::pointer_to(@\seebelow@ r) noexcept; +template + constexpr reference_wrapper(U&& u) noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} \pnum -\mandates -For the first member function, -\tcode{Ptr::pointer_to(r)} is well-formed. +Let \tcode{\placeholdernc{FUN}} denote the exposition-only functions +\begin{codeblock} +void @\placeholdernc{FUN}@(T&) noexcept; +void @\placeholdernc{FUN}@(T&&) = delete; +\end{codeblock} \pnum -\expects -For the first member function, -\tcode{Ptr::pointer_to(r)} returns a pointer to \tcode{r} -through which indirection is valid. +\constraints +The expression \tcode{\placeholdernc{FUN}(declval())} is well-formed and +\tcode{is_same_v, reference_wrapper>} is \tcode{false}. \pnum -\returns -The first member function returns \tcode{Ptr::pointer_to(r)}. -The second member function returns \tcode{addressof(r)}. +\effects +Creates a variable \tcode{r} +as if by \tcode{T\& r = std::forward(u)}, +then constructs a \tcode{reference_wrapper} object +that stores a reference to \tcode{r}. \pnum \remarks -If \tcode{element_type} is \cv{}~\keyword{void}, the type of -\tcode{r} is unspecified; otherwise, it is \tcode{element_type\&}. +The exception specification is equivalent to +\tcode{noexcept(\placeholdernc{FUN}(declval()))}. \end{itemdescr} -\rSec3[pointer.traits.optmem]{Optional members} - -\pnum -Specializations of \tcode{pointer_traits} may define the member declared -in this subclause to customize the behavior of the standard library. - -\indexlibrarymember{to_address}{pointer_traits}% +\indexlibraryctor{reference_wrapper}% \begin{itemdecl} -static element_type* to_address(pointer p) noexcept; +constexpr reference_wrapper(const reference_wrapper& x) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns -A pointer of type \tcode{element_type*} that references -the same location as the argument \tcode{p}. - -\pnum -\begin{note} -This function is intended to be the inverse of \tcode{pointer_to}. -If defined, it customizes the behavior of -the non-member function -\tcode{to_address}\iref{pointer.conversion}. -\end{note} +\effects +Constructs a \tcode{reference_wrapper} object that +stores a reference to \tcode{x.get()}. \end{itemdescr} -\rSec2[pointer.conversion]{Pointer conversion} +\rSec3[refwrap.assign]{Assignment} -\indexlibraryglobal{to_address}% +\indexlibrarymember{operator=}{reference_wrapper}% \begin{itemdecl} -template constexpr T* to_address(T* p) noexcept; +constexpr reference_wrapper& operator=(const reference_wrapper& x) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\mandates -\tcode{T} is not a function type. - -\pnum -\returns -\tcode{p}. +\ensures +\tcode{*this} stores a reference to \tcode{x.get()}. \end{itemdescr} -\indexlibraryglobal{to_address}% +\rSec3[refwrap.access]{Access} + +\indexlibrarymember{operator T\&}{reference_wrapper}% \begin{itemdecl} -template constexpr auto to_address(const Ptr& p) noexcept; +constexpr operator T& () const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{pointer_traits::to_address(p)} if that expression is well-formed -(see \ref{pointer.traits.optmem}), -otherwise \tcode{to_address(p.operator->())}. +The stored reference. \end{itemdescr} -\rSec2[ptr.align]{Pointer alignment} - -\indexlibraryglobal{align}% +\indexlibrarymember{get}{reference_wrapper}% \begin{itemdecl} -void* align(size_t alignment, size_t size, void*& ptr, size_t& space); +constexpr T& get() const noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\expects -\begin{itemize} -\item -\tcode{alignment} is a power of two - -\item -\tcode{ptr} represents the address of contiguous storage of at least -\tcode{space} bytes -\end{itemize} - -\pnum -\effects -If it is possible to fit \tcode{size} bytes -of storage aligned by \tcode{alignment} into the buffer pointed to by -\tcode{ptr} with length \tcode{space}, the function updates -\tcode{ptr} to represent the first possible address of such storage -and decreases \tcode{space} by the number of bytes used for alignment. -Otherwise, the function does nothing. - \pnum \returns -A null pointer if the requested aligned buffer -would not fit into the available space, otherwise the adjusted value -of \tcode{ptr}. - -\pnum -\begin{note} -The function updates its \tcode{ptr} -and \tcode{space} arguments so that it can be called repeatedly -with possibly different \tcode{alignment} and \tcode{size} -arguments for the same buffer. -\end{note} +The stored reference. \end{itemdescr} -\indexlibraryglobal{assume_aligned}% +\rSec3[refwrap.invoke]{Invocation} + +\indexlibrarymember{operator()}{reference_wrapper}% \begin{itemdecl} -template - [[nodiscard]] constexpr T* assume_aligned(T* ptr); +template + constexpr invoke_result_t + operator()(ArgTypes&&... args) const; \end{itemdecl} \begin{itemdescr} \pnum \mandates -\tcode{N} is a power of two. - -\pnum -\expects -\tcode{ptr} points to an object \tcode{X} of -a type similar\iref{conv.qual} to \tcode{T}, -where \tcode{X} has alignment \tcode{N}\iref{basic.align}. +\tcode{T} is a complete type. \pnum \returns -\tcode{ptr}. - -\pnum -\throws -Nothing. - -\pnum -\begin{note} -The alignment assumption on an object \tcode{X} -expressed by a call to \tcode{assume_aligned} -might result in generation of more efficient code. -It is up to the program to ensure that the assumption actually holds. -The call does not cause the implementation to verify or enforce this. -An implementation might only make the assumption -for those operations on \tcode{X} that access \tcode{X} -through the pointer returned by \tcode{assume_aligned}. -\end{note} +\tcode{\placeholdernc{INVOKE}(get(), std::forward(args)...)}.\iref{func.require} \end{itemdescr} -\rSec2[allocator.tag]{Allocator argument tag} -\indexlibraryglobal{allocator_arg_t}% -\indexlibraryglobal{allocator_arg}% -\begin{itemdecl} -namespace std { - struct allocator_arg_t { explicit allocator_arg_t() = default; }; - inline constexpr allocator_arg_t allocator_arg{}; -} -\end{itemdecl} +\rSec3[refwrap.helpers]{Helper functions} \pnum -The \tcode{allocator_arg_t} struct is an empty class type used as a unique type to -disambiguate constructor and function overloading. Specifically, several types (see -\tcode{tuple}~\ref{tuple}) have constructors with \tcode{allocator_arg_t} as the first -argument, immediately followed by an argument of a type that meets the -\oldconcept{Allocator} requirements (\tref{cpp17.allocator}). - -\rSec2[allocator.uses]{\tcode{uses_allocator}} - -\rSec3[allocator.uses.trait]{\tcode{uses_allocator} trait} +The template parameter \tcode{T} of +the following \tcode{ref} and \tcode{cref} function templates +may be an incomplete type. -\indexlibraryglobal{uses_allocator}% +\indexlibrarymember{ref}{reference_wrapper}% \begin{itemdecl} -template struct uses_allocator; +template constexpr reference_wrapper ref(T& t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\remarks -Automatically detects whether \tcode{T} has a nested \tcode{allocator_type} that -is convertible from \tcode{Alloc}. Meets the \oldconcept{BinaryTypeTrait} -requirements\iref{meta.rqmts}. The implementation shall provide a definition that is -derived from \tcode{true_type} if the \grammarterm{qualified-id} \tcode{T::allocator_type} -is valid and denotes a type\iref{temp.deduct} and -\tcode{is_convertible_v != false}, otherwise it shall be -derived from \tcode{false_type}. A program may specialize this template to derive from -\tcode{true_type} for a program-defined type \tcode{T} that does not have a nested -\tcode{allocator_type} but nonetheless can be constructed with an allocator where -either: -\begin{itemize} -\item the first argument of a constructor has type \tcode{allocator_arg_t} and the -second argument has type \tcode{Alloc} or - -\item the last argument of a constructor has type \tcode{Alloc}. -\end{itemize} +\returns +\tcode{reference_wrapper(t)}. \end{itemdescr} -\rSec3[allocator.uses.construction]{Uses-allocator construction} - -\pnum -\defnx{Uses-allocator construction}{uses-allocator construction} -with allocator \tcode{alloc} and constructor arguments \tcode{args...} -refers to the construction of an object of type \tcode{T} -such that \tcode{alloc} is passed to the constructor of \tcode{T} -if \tcode{T} uses an allocator type compatible with \tcode{alloc}. -When applied to the construction of an object of type \tcode{T}, -it is equivalent to initializing it with the value of the expression -\tcode{make_obj_using_allocator(alloc, args...)}, described below. - -\pnum -The following utility functions support -three conventions for passing \tcode{alloc} to a constructor: -\begin{itemize} -\item - If \tcode{T} does not use an allocator compatible with \tcode{alloc}, - then \tcode{alloc} is ignored. -\item - Otherwise, if \tcode{T} has a constructor invocable as - \tcode{T(allocator_arg, alloc, args...)} (leading-allocator convention), - then uses-allocator construction chooses this constructor form. -\item - Otherwise, if \tcode{T} has a constructor invocable as - \tcode{T(args..., alloc)} (trailing-allocator convention), - then uses-allocator construction chooses this constructor form. -\end{itemize} - -\pnum -The \tcode{uses_allocator_construction_args} function template -takes an allocator and argument list and -produces (as a tuple) a new argument list matching one of the above conventions. -Additionally, overloads are provided -that treat specializations of \tcode{pair} -such that uses-allocator construction is applied individually -to the \tcode{first} and \tcode{second} data members. -The \tcode{make_obj_using_allocator} and -\tcode{uninitialized_construct_using_allocator} function templates -apply the modified constructor arguments -to construct an object of type \tcode{T} -as a return value or in-place, respectively. -\begin{note} -For \tcode{uses_allocator_construction_args} and -\tcode{make_obj_using_allocator}, type \tcode{T} -is not deduced and must therefore be specified explicitly by the caller. -\end{note} - -\indexlibraryglobal{uses_allocator_construction_args}% +\indexlibrarymember{ref}{reference_wrapper}% \begin{itemdecl} -template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, - Args&&... args) noexcept; +template constexpr reference_wrapper ref(reference_wrapper t) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\constraints -\tcode{T} is not a specialization of \tcode{pair}. - \pnum \returns -A \tcode{tuple} value determined as follows: -\begin{itemize} -\item - If \tcode{uses_allocator_v} is \tcode{false} and - \tcode{is_constructible_v} is \tcode{true}, - return \tcode{forward_as_tuple(std::forward(args)...)}. -\item - Otherwise, if \tcode{uses_allocator_v} is \tcode{true} and - \tcode{is_constructible_v} - is \tcode{true}, - return -\begin{codeblock} -tuple( - allocator_arg, alloc, std::forward(args)...) -\end{codeblock} -\item - Otherwise, if \tcode{uses_allocator_v} is \tcode{true} and - \tcode{is_constructible_v} is \tcode{true}, - return \tcode{forward_as_tuple(std::forward(args)..., alloc)}. -\item - Otherwise, the program is ill-formed. -\end{itemize} -\begin{note} -This definition prevents a silent failure -to pass the allocator to a constructor of a type for which -\tcode{uses_allocator_v} is \tcode{true}. -\end{note} +\tcode{t}. \end{itemdescr} -\indexlibraryglobal{uses_allocator_construction_args}% +\indexlibrarymember{cref}{reference_wrapper}% \begin{itemdecl} -template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, - Tuple1&& x, Tuple2&& y) noexcept; +template constexpr reference_wrapper cref(const T& t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{T} is a specialization of \tcode{pair}. - -\pnum -\effects -For \tcode{T} specified as \tcode{pair}, equivalent to: -\begin{codeblock} -return make_tuple( - piecewise_construct, - apply([&alloc](auto&&... args1) { - return uses_allocator_construction_args( - alloc, std::forward(args1)...); - }, std::forward(x)), - apply([&alloc](auto&&... args2) { - return uses_allocator_construction_args( - alloc, std::forward(args2)...); - }, std::forward(y))); -\end{codeblock} +\returns +\tcode{reference_wrapper (t)}. \end{itemdescr} -\indexlibraryglobal{uses_allocator_construction_args}% +\indexlibrarymember{cref}{reference_wrapper}% \begin{itemdecl} -template - constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept; +template constexpr reference_wrapper cref(reference_wrapper t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{T} is a specialization of \tcode{pair}. - -\pnum -\effects -Equivalent to: -\begin{codeblock} -return uses_allocator_construction_args(alloc, piecewise_construct, - tuple<>{}, tuple<>{}); -\end{codeblock} +\returns +\tcode{t}. \end{itemdescr} -\indexlibraryglobal{uses_allocator_construction_args}% -\begin{itemdecl} -template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, - U&& u, V&& v) noexcept; -\end{itemdecl} +\rSec2[arithmetic.operations]{Arithmetic operations} -\begin{itemdescr} -\pnum -\constraints -\tcode{T} is a specialization of \tcode{pair}. +\rSec3[arithmetic.operations.general]{General} \pnum -\effects -Equivalent to: -\begin{codeblock} -return uses_allocator_construction_args(alloc, piecewise_construct, - forward_as_tuple(std::forward(u)), - forward_as_tuple(std::forward(v))); -\end{codeblock} -\end{itemdescr} +The library provides basic function object classes for all of the arithmetic +operators in the language\iref{expr.mul,expr.add}. + +\rSec3[arithmetic.operations.plus]{Class template \tcode{plus}} -\indexlibraryglobal{uses_allocator_construction_args}% +\indexlibraryglobal{plus}% \begin{itemdecl} -template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, - pair& pr) noexcept; -template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, - const pair& pr) noexcept; +template struct plus { + constexpr T operator()(const T& x, const T& y) const; +}; \end{itemdecl} -\begin{itemdescr} -\pnum -\constraints -\tcode{T} is a specialization of \tcode{pair}. - -\pnum -\effects -Equivalent to: -\begin{codeblock} -return uses_allocator_construction_args(alloc, piecewise_construct, - forward_as_tuple(pr.first), - forward_as_tuple(pr.second)); -\end{codeblock} -\end{itemdescr} - -\indexlibraryglobal{uses_allocator_construction_args}% +\indexlibrarymember{operator()}{plus}% \begin{itemdecl} -template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, - pair&& pr) noexcept; -template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, - const pair&& pr) noexcept; +constexpr T operator()(const T& x, const T& y) const; \end{itemdecl} \begin{itemdescr} \pnum -\constraints -\tcode{T} is a specialization of \tcode{pair}. - -\pnum -\effects -Equivalent to: -\begin{codeblock} -return uses_allocator_construction_args(alloc, piecewise_construct, - forward_as_tuple(get<0>(std::move(pr))), - forward_as_tuple(get<1>(std::move(pr)))); -\end{codeblock} +\returns +\tcode{x + y}. \end{itemdescr} -\indexlibraryglobal{uses_allocator_construction_args}% +\indexlibraryglobal{plus<>}% \begin{itemdecl} -template - constexpr auto uses_allocator_construction_args(const Alloc& alloc, U&& u) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \exposid{FUN} be the function template: -\begin{codeblock} -template - void @\exposid{FUN}@(const pair&); -\end{codeblock} - -\pnum -\constraints -\tcode{T} is a specialization of \tcode{pair}, and -the expression \tcode{\exposid{FUN}(u)} is not well-formed -when considered as an unevaluated operand. - -\pnum -Let \exposid{pair-constructor} be an exposition-only class defined as follows: - -\begin{codeblock} -class @\exposid{pair-constructor}@ { - using @\exposid{pair-type}@ = remove_cv_t; // \expos - - constexpr auto @\exposid{do-construct}@(const @\exposid{pair-type}@& p) const { // \expos - return make_obj_using_allocator<@\exposid{pair-type}@>(@\exposid{alloc_}@, p); - } - constexpr auto @\exposid{do-construct}@(@\exposid{pair-type}@&& p) const { // \expos - return make_obj_using_allocator<@\exposid{pair-type}@>(@\exposid{alloc_}@, std::move(p)); - } - - const Alloc& @\exposid{alloc_}@; // \expos - U& @\exposid{u_}@; // \expos +template<> struct plus { + template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) + std::forward(u)); -public: - constexpr operator @\exposid{pair-type}@() const { - return @\exposid{do-construct}@(std::forward(@\exposid{u_}@)); - } + using is_transparent = @\unspec@; }; -\end{codeblock} - -\pnum -\returns -\tcode{make_tuple(pc)}, -where \tcode{pc} is a \exposid{pair-constructor} object -whose \exposid{alloc_} member is initialized with \tcode{alloc} and -whose \exposid{u_} member is initialized with \tcode{u}. -\end{itemdescr} +\end{itemdecl} -\indexlibraryglobal{make_obj_using_allocator}% +\indexlibrarymember{operator()}{plus<>}% \begin{itemdecl} -template - constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args); +template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) + std::forward(u)); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -return make_from_tuple(uses_allocator_construction_args( - alloc, std::forward(args)...)); -\end{codeblock} +\returns +\tcode{std::forward(t) + std::forward(u)}. \end{itemdescr} -\indexlibraryglobal{uninitialized_construct_using_allocator}% +\rSec3[arithmetic.operations.minus]{Class template \tcode{minus}} + +\indexlibraryglobal{minus}% +\begin{itemdecl} +template struct minus { + constexpr T operator()(const T& x, const T& y) const; +}; +\end{itemdecl} + +\indexlibrarymember{operator()}{minus}% \begin{itemdecl} -template - constexpr T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, Args&&... args); +constexpr T operator()(const T& x, const T& y) const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Equivalent to: -\begin{codeblock} -return apply([&](U&&... xs) { - return construct_at(p, std::forward(xs)...); - }, uses_allocator_construction_args(alloc, std::forward(args)...)); -\end{codeblock} +\returns +\tcode{x - y}. \end{itemdescr} -\rSec2[allocator.traits]{Allocator traits} - -\rSec3[allocator.traits.general]{General} - -\pnum -The class template \tcode{allocator_traits} supplies a uniform interface to all -allocator types. -An allocator cannot be a non-class type, however, even if \tcode{allocator_traits} -supplies the entire required interface. -\begin{note} -Thus, it is always possible to create -a derived class from an allocator. -\end{note} - -\indexlibraryglobal{allocator_traits}% -\begin{codeblock} -namespace std { - template struct allocator_traits { - using allocator_type = Alloc; - - using value_type = typename Alloc::value_type; - - using pointer = @\seebelow@; - using const_pointer = @\seebelow@; - using void_pointer = @\seebelow@; - using const_void_pointer = @\seebelow@; - - using difference_type = @\seebelow@; - using size_type = @\seebelow@; - - using propagate_on_container_copy_assignment = @\seebelow@; - using propagate_on_container_move_assignment = @\seebelow@; - using propagate_on_container_swap = @\seebelow@; - using is_always_equal = @\seebelow@; - - template using rebind_alloc = @\seebelow@; - template using rebind_traits = allocator_traits>; - - [[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n); - [[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n, - const_void_pointer hint); - - static constexpr void deallocate(Alloc& a, pointer p, size_type n); - - template - static constexpr void construct(Alloc& a, T* p, Args&&... args); - - template - static constexpr void destroy(Alloc& a, T* p); - - static constexpr size_type max_size(const Alloc& a) noexcept; - - static constexpr Alloc select_on_container_copy_construction(const Alloc& rhs); - }; -} -\end{codeblock} +\indexlibraryglobal{minus<>}% +\begin{itemdecl} +template<> struct minus { + template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) - std::forward(u)); -\rSec3[allocator.traits.types]{Member types} + using is_transparent = @\unspec@; +}; +\end{itemdecl} -\indexlibrarymember{pointer}{allocator_traits}% +\indexlibrarymember{operator()}{minus<>}% \begin{itemdecl} -using pointer = @\seebelow@; +template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) - std::forward(u)); \end{itemdecl} \begin{itemdescr} \pnum -\ctype \tcode{Alloc::pointer} if -the \grammarterm{qualified-id} \tcode{Alloc::pointer} is valid and denotes a -type\iref{temp.deduct}; otherwise, \tcode{value_type*}. +\returns +\tcode{std::forward(t) - std::forward(u)}. \end{itemdescr} -\indexlibrarymember{const_pointer}{allocator_traits}% +\rSec3[arithmetic.operations.multiplies]{Class template \tcode{multiplies}} + +\indexlibraryglobal{multiplies}% \begin{itemdecl} -using const_pointer = @\seebelow@; +template struct multiplies { + constexpr T operator()(const T& x, const T& y) const; +}; \end{itemdecl} -\begin{itemdescr} -\pnum -\ctype \tcode{Alloc::const_pointer} if -the \grammarterm{qualified-id} \tcode{Alloc::const_pointer} is valid and denotes a -type\iref{temp.deduct}; otherwise, -\tcode{pointer_traits::rebind<\brk{}const value_type>}. -\end{itemdescr} - -\indexlibrarymember{void_pointer}{allocator_traits}% +\indexlibrarymember{operator()}{multiplies}% \begin{itemdecl} -using void_pointer = @\seebelow@; +constexpr T operator()(const T& x, const T& y) const; \end{itemdecl} \begin{itemdescr} \pnum -\ctype \tcode{Alloc::void_pointer} if -the \grammarterm{qualified-id} \tcode{Alloc::void_pointer} is valid and denotes a -type\iref{temp.deduct}; otherwise, -\tcode{pointer_traits::rebind<\brk{}void>}. +\returns +\tcode{x * y}. \end{itemdescr} -\indexlibrarymember{const_void_pointer}{allocator_traits}% +\indexlibraryglobal{multiplies<>}% \begin{itemdecl} -using const_void_pointer = @\seebelow@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ctype \tcode{Alloc::const_void_pointer} if -the \grammarterm{qualified-id} \tcode{Alloc::const_void_pointer} is valid and denotes a -type\iref{temp.deduct}; otherwise, -\tcode{pointer_traits::\brk{}rebind}. -\end{itemdescr} +template<> struct multiplies { + template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) * std::forward(u)); -\indexlibrarymember{difference_type}{allocator_traits}% -\begin{itemdecl} -using difference_type = @\seebelow@; + using is_transparent = @\unspec@; +}; \end{itemdecl} -\begin{itemdescr} -\pnum -\ctype \tcode{Alloc::difference_type} if -the \grammarterm{qualified-id} \tcode{Alloc::difference_type} is valid and denotes a -type\iref{temp.deduct}; otherwise, -\tcode{pointer_traits::dif\-ference_type}. -\end{itemdescr} - -\indexlibrarymember{size_type}{allocator_traits}% +\indexlibrarymember{operator()}{multiplies<>}% \begin{itemdecl} -using size_type = @\seebelow@; +template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) * std::forward(u)); \end{itemdecl} \begin{itemdescr} \pnum -\ctype \tcode{Alloc::size_type} if -the \grammarterm{qualified-id} \tcode{Alloc::size_type} is valid and denotes a -type\iref{temp.deduct}; otherwise, -\tcode{make_unsigned_t}. +\returns +\tcode{std::forward(t) * std::forward(u)}. \end{itemdescr} -\indexlibrarymember{propagate_on_container_copy_assignment}{allocator_traits}% -\begin{itemdecl} -using propagate_on_container_copy_assignment = @\seebelow@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ctype \tcode{Alloc::propagate_on_container_copy_assignment} if -the \grammarterm{qualified-id} \tcode{Alloc::propagate_on_container_copy_assignment} is valid and denotes a -type\iref{temp.deduct}; otherwise -\tcode{false_type}. -\end{itemdescr} +\rSec3[arithmetic.operations.divides]{Class template \tcode{divides}} -\indexlibrarymember{propagate_on_container_move_assignment}{allocator_traits}% +\indexlibraryglobal{divides}% \begin{itemdecl} -using propagate_on_container_move_assignment = @\seebelow@; +template struct divides { + constexpr T operator()(const T& x, const T& y) const; +}; \end{itemdecl} -\begin{itemdescr} -\pnum -\ctype \tcode{Alloc::propagate_on_container_move_assignment} if -the \grammarterm{qualified-id} \tcode{Alloc::propagate_on_container_move_assignment} is valid and denotes a -type\iref{temp.deduct}; otherwise -\tcode{false_type}. -\end{itemdescr} - -\indexlibrarymember{propagate_on_container_swap}{allocator_traits}% +\indexlibrarymember{operator()}{divides}% \begin{itemdecl} -using propagate_on_container_swap = @\seebelow@; +constexpr T operator()(const T& x, const T& y) const; \end{itemdecl} \begin{itemdescr} \pnum -\ctype \tcode{Alloc::propagate_on_container_swap} if -the \grammarterm{qualified-id} \tcode{Alloc::propagate_on_container_swap} is valid and denotes a -type\iref{temp.deduct}; otherwise -\tcode{false_type}. +\returns +\tcode{x / y}. \end{itemdescr} -\indexlibrarymember{is_always_equal}{allocator_traits}% +\indexlibraryglobal{divides<>}% \begin{itemdecl} -using is_always_equal = @\seebelow@; -\end{itemdecl} +template<> struct divides { + template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) / std::forward(u)); -\begin{itemdescr} -\pnum -\ctype \tcode{Alloc::is_always_equal} if -the \grammarterm{qualified-id} \tcode{Alloc::is_always_equal} -is valid and denotes a type\iref{temp.deduct}; -otherwise \tcode{is_empty::type}. -\end{itemdescr} + using is_transparent = @\unspec@; +}; +\end{itemdecl} -\indexlibrarymember{rebind_alloc}{allocator_traits}% +\indexlibrarymember{operator()}{divides<>}% \begin{itemdecl} -template using rebind_alloc = @\seebelow@; +template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) / std::forward(u)); \end{itemdecl} \begin{itemdescr} \pnum -\templalias \tcode{Alloc::rebind::other} if -the \grammarterm{qualified-id} \tcode{Alloc::rebind::other} is valid and denotes a -type\iref{temp.deduct}; otherwise, -\tcode{Alloc} if \tcode{Alloc} is a class template instantiation -of the form \tcode{Alloc}, where \tcode{Args} is zero or more type arguments; -otherwise, the instantiation of \tcode{rebind_alloc} is ill-formed. +\returns +\tcode{std::forward(t) / std::forward(u)}. \end{itemdescr} -\rSec3[allocator.traits.members]{Static member functions} +\rSec3[arithmetic.operations.modulus]{Class template \tcode{modulus}} -\indexlibrarymember{allocate}{allocator_traits}% +\indexlibraryglobal{modulus}% \begin{itemdecl} -[[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n); +template struct modulus { + constexpr T operator()(const T& x, const T& y) const; +}; \end{itemdecl} -\begin{itemdescr} -\pnum -\returns -\tcode{a.allocate(n)}. -\end{itemdescr} - -\indexlibrarymember{allocate}{allocator_traits}% +\indexlibrarymember{operator()}{modulus}% \begin{itemdecl} -[[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n, const_void_pointer hint); +constexpr T operator()(const T& x, const T& y) const; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{a.allocate(n, hint)} if that expression is well-formed; otherwise, \tcode{a.allocate(n)}. +\tcode{x \% y}. \end{itemdescr} -\indexlibrarymember{deallocate}{allocator_traits}% +\indexlibraryglobal{modulus<>}% \begin{itemdecl} -static constexpr void deallocate(Alloc& a, pointer p, size_type n); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Calls \tcode{a.deallocate(p, n)}. - -\pnum -\throws -Nothing. -\end{itemdescr} +template<> struct modulus { + template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) % std::forward(u)); -\indexlibrarymember{construct}{allocator_traits}% -\begin{itemdecl} -template - static constexpr void construct(Alloc& a, T* p, Args&&... args); + using is_transparent = @\unspec@; +}; \end{itemdecl} -\begin{itemdescr} -\pnum -\effects -Calls \tcode{a.construct(p, std::forward(args)...)} -if that call is well-formed; -otherwise, invokes \tcode{construct_at(p, std::forward(args)...)}. -\end{itemdescr} - -\indexlibrarymember{destroy}{allocator_traits}% +\indexlibrarymember{operator()}{modulus<>}% \begin{itemdecl} -template - static constexpr void destroy(Alloc& a, T* p); +template constexpr auto operator()(T&& t, U&& u) const + -> decltype(std::forward(t) % std::forward(u)); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Calls \tcode{a.destroy(p)} if that call is well-formed; otherwise, invokes -\tcode{destroy_at(p)}. +\returns +\tcode{std::forward(t) \% std::forward(u)}. \end{itemdescr} -\indexlibrarymember{max_size}{allocator_traits}% +\rSec3[arithmetic.operations.negate]{Class template \tcode{negate}} + +\indexlibraryglobal{negate}% \begin{itemdecl} -static constexpr size_type max_size(const Alloc& a) noexcept; +template struct negate { + constexpr T operator()(const T& x) const; +}; \end{itemdecl} -\begin{itemdescr} -\pnum -\returns -\tcode{a.max_size()} if that expression is well-formed; otherwise, -\tcode{numeric_limits::\brk{}max()/sizeof(value_type)}. -\end{itemdescr} - -\indexlibrarymember{select_on_container_copy_construction}{allocator_traits}% +\indexlibrarymember{operator()}{negate}% \begin{itemdecl} -static constexpr Alloc select_on_container_copy_construction(const Alloc& rhs); +constexpr T operator()(const T& x) const; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{rhs.select_on_container_copy_construction()} if that expression is -well-formed; otherwise, \tcode{rhs}. +\tcode{-x}. \end{itemdescr} -\rSec3[allocator.traits.other]{Other} +\indexlibraryglobal{negate<>}% +\begin{itemdecl} +template<> struct negate { + template constexpr auto operator()(T&& t) const + -> decltype(-std::forward(t)); -\pnum -The class template \tcode{allocation_result} has -the template parameters, data members, and special members specified above. -It has no base classes or members other than those specified. + using is_transparent = @\unspec@; +}; +\end{itemdecl} +\indexlibrarymember{operator()}{negate<>}% \begin{itemdecl} -template -[[nodiscard]] constexpr allocation_result::pointer> - allocate_at_least(Allocator& a, size_t n); +template constexpr auto operator()(T&& t) const + -> decltype(-std::forward(t)); \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{a.allocate_at_least(n)} if that expression is well-formed; -otherwise, \tcode{\{a.allocate(n), n\}}. +\tcode{-std::forward(t)}. \end{itemdescr} -\rSec2[default.allocator]{The default allocator} -\rSec3[default.allocator.general]{General} +\rSec2[comparisons]{Comparisons} -\pnum -All specializations of the default allocator meet the -allocator completeness requirements\iref{allocator.requirements.completeness}. +\rSec3[comparisons.general]{General} -\indexlibraryglobal{allocator}% -\indexlibrarymember{value_type}{allocator}% -\indexlibrarymember{size_type}{allocator}% -\indexlibrarymember{difference_type}{allocator}% -\indexlibrarymember{propagate_on_container_move_assignment}{allocator}% -\indexlibrarymember{operator=}{allocator}% -\begin{codeblock} -namespace std { - template class allocator { - public: - using value_type = T; - using size_type = size_t; - using difference_type = ptrdiff_t; - using propagate_on_container_move_assignment = true_type; - - constexpr allocator() noexcept; - constexpr allocator(const allocator&) noexcept; - template constexpr allocator(const allocator&) noexcept; - constexpr ~allocator(); - constexpr allocator& operator=(const allocator&) = default; - - [[nodiscard]] constexpr T* allocate(size_t n); - [[nodiscard]] constexpr allocation_result allocate_at_least(size_t n); - constexpr void deallocate(T* p, size_t n); - }; -} -\end{codeblock} +\pnum +The library provides basic function object classes for all of the comparison +operators in the language\iref{expr.rel,expr.eq}. \pnum -\tcode{allocator_traits>::is_always_equal::value} -is \tcode{true} for any \tcode{T}. +For templates \tcode{less}, \tcode{greater}, \tcode{less_equal}, and +\tcode{greater_equal}, the specializations for any pointer type +yield a result consistent with the +implementation-defined strict total order over pointers\iref{defns.order.ptr}. +\begin{note} +If \tcode{a < b} is well-defined +for pointers \tcode{a} and \tcode{b} of type \tcode{P}, +then \tcode{(a < b) == less