From f4b02f348dca9be1083ad5ac45fe6892f4d0250d Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Wed, 23 Feb 2022 22:38:13 +0100 Subject: [PATCH 1/7] [bit] Move into [utilities] --- source/numerics.tex | 415 ------------------------------------------ source/utilities.tex | 417 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 416 insertions(+), 416 deletions(-) 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/utilities.tex b/source/utilities.tex index a18164278f..c18b5faa36 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -28,7 +28,8 @@ \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} @@ -24856,3 +24857,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} From 993b1cf22f126fcabfb933f800efa1a9ec8506e9 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Wed, 23 Feb 2022 22:44:52 +0100 Subject: [PATCH 2/7] [memory] Create new clause and move [memory], [smartptr], [mem.res], and [allocator.adaptor] from [utilities] into the new clause. --- source/lib-intro.tex | 5 + source/memory.tex | 6754 +++++++++++++++++++++++++++++++++++++++++ source/std.tex | 1 + source/utilities.tex | 6739 ---------------------------------------- tools/check-source.sh | 2 +- 5 files changed, 6761 insertions(+), 6740 deletions(-) create mode 100644 source/memory.tex diff --git a/source/lib-intro.tex b/source/lib-intro.tex index 870871efcd..d0973ce552 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -29,6 +29,7 @@ \ref{support} & Language support library \\ \ref{concepts} & Concepts library \\ \ref{diagnostics} & Diagnostics library \\ +\ref{mem} & Memory management library \\ \ref{utilities} & General utilities library \\ \ref{strings} & Strings library \\ \ref{containers} & Containers library \\ @@ -59,6 +60,10 @@ 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 general utilities library\iref{utilities} includes components used by other library elements, such as a predefined storage allocator for dynamic 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/std.tex b/source/std.tex index 552d663558..dc5385f897 100644 --- a/source/std.tex +++ b/source/std.tex @@ -119,6 +119,7 @@ \include{support} \include{concepts} \include{diagnostics} +\include{memory} \include{utilities} \include{strings} \include{containers} diff --git a/source/utilities.tex b/source/utilities.tex index c18b5faa36..e8693c39d5 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -18,10 +18,6 @@ \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 @@ -9422,6741 +9418,6 @@ (see~\ref{ostream.formatted}). \end{itemdescr} -\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} - \rSec1[function.objects]{Function objects} \rSec2[function.objects.general]{General} diff --git a/tools/check-source.sh b/tools/check-source.sh index 9a90e8b4db..6a8b21ecd7 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 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" texlib="lib-intro.tex $texlibdesc" # Filter that reformats the error message as a "workflow command", From 461f966d76b428b3f02f7c5f022c1c3e49556c4b Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Wed, 23 Feb 2022 22:48:10 +0100 Subject: [PATCH 3/7] [comparisons.three.way,func.search] Add namespace around class definition --- source/utilities.tex | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/source/utilities.tex b/source/utilities.tex index e8693c39d5..52a1a16d73 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -10549,12 +10549,14 @@ \indexlibraryglobal{compare_three_way}% \begin{codeblock} -struct compare_three_way { - template - constexpr auto operator()(T&& t, U&& u) const; +namespace std { + struct compare_three_way { + template + constexpr auto operator()(T&& t, U&& u) const; - using is_transparent = @\unspec@; -}; + using is_transparent = @\unspec@; + }; +} \end{codeblock} \begin{itemdecl} @@ -12387,7 +12389,8 @@ \indexlibraryglobal{default_searcher}% \begin{codeblock} -template> +namespace std { + template> class default_searcher { public: constexpr default_searcher(ForwardIterator1 pat_first, ForwardIterator1 pat_last, @@ -12402,6 +12405,7 @@ ForwardIterator1 pat_last_; // \expos BinaryPredicate pred_; // \expos }; +} \end{codeblock} \indexlibraryctor{default_searcher}% @@ -12446,9 +12450,10 @@ \indexlibraryglobal{boyer_moore_searcher}% \begin{codeblock} -template::value_type>, - class BinaryPredicate = equal_to<>> +namespace std { + template::value_type>, + class BinaryPredicate = equal_to<>> class boyer_moore_searcher { public: boyer_moore_searcher(RandomAccessIterator1 pat_first, @@ -12466,6 +12471,7 @@ Hash hash_; // \expos BinaryPredicate pred_; // \expos }; +} \end{codeblock} \indexlibraryctor{boyer_moore_searcher}% @@ -12545,9 +12551,10 @@ \indexlibraryglobal{boyer_moore_horspool_searcher}% \begin{codeblock} -template::value_type>, - class BinaryPredicate = equal_to<>> +namespace std { + template::value_type>, + class BinaryPredicate = equal_to<>> class boyer_moore_horspool_searcher { public: boyer_moore_horspool_searcher(RandomAccessIterator1 pat_first, @@ -12565,6 +12572,7 @@ Hash hash_; // \expos BinaryPredicate pred_; // \expos }; +} \end{codeblock} \indexlibraryctor{boyer_moore_horspool_searcher}% From b5bfb97c9e800054461e376d1603167adac66366 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Wed, 23 Feb 2022 22:54:01 +0100 Subject: [PATCH 4/7] Move [string.view] to before [string.classes] --- source/strings.tex | 6225 ++++++++++++++++++++++---------------------- 1 file changed, 3112 insertions(+), 3113 deletions(-) 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} From 78ce6fb1aa1fc1631bb7d89420fe55f086785e00 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Wed, 23 Feb 2022 23:01:35 +0100 Subject: [PATCH 5/7] [meta] Create new clause and move [intseq], [meta], and [ratio] from [utilities] into the new clause. --- source/lib-intro.tex | 8 +- source/meta.tex | 2630 +++++++++++++++++++++++++++++++++++++++++ source/std.tex | 1 + source/utilities.tex | 2618 ---------------------------------------- tools/check-source.sh | 2 +- 5 files changed, 2639 insertions(+), 2620 deletions(-) create mode 100644 source/meta.tex diff --git a/source/lib-intro.tex b/source/lib-intro.tex index d0973ce552..6405c26b63 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -30,6 +30,7 @@ \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 \\ @@ -64,6 +65,11 @@ 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 @@ -1337,7 +1343,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/meta.tex b/source/meta.tex new file mode 100644 index 0000000000..bd138d5e90 --- /dev/null +++ b/source/meta.tex @@ -0,0 +1,2630 @@ +%!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{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}% -\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. - \rSec1[type.index]{Class \tcode{type_index}} \rSec2[type.index.synopsis]{Header \tcode{} synopsis} diff --git a/tools/check-source.sh b/tools/check-source.sh index 6a8b21ecd7..8bd157fe6a 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 memory.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 atomics.tex threads.tex" texlib="lib-intro.tex $texlibdesc" # Filter that reformats the error message as a "workflow command", From 08b1b86c3397bc1a338edb94bd84dc6353098023 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Wed, 23 Feb 2022 23:06:45 +0100 Subject: [PATCH 6/7] [meta] Adjust cross-references --- source/compatibility.tex | 2 +- source/meta.tex | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) 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/meta.tex b/source/meta.tex index bd138d5e90..6c6d7914fd 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -73,8 +73,8 @@ \rSec2[type.traits.general]{General} \pnum -Subclause \ref{meta} describes components used by \Cpp{} programs, particularly in -templates, to support the widest possible range of types, optimise +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 @@ -86,7 +86,7 @@ \pnum \indextext{signal-safe!type traits}% -All functions specified in \ref{meta} are signal-safe\iref{support.signal}. +All functions specified in \ref{type.traits} are signal-safe\iref{support.signal}. \rSec2[meta.rqmts]{Requirements} @@ -132,16 +132,16 @@ \pnum Unless otherwise specified, the behavior of a program that adds specializations -for any of the templates specified in \ref{meta} +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{meta}. +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{meta} + an instantiation of a template specified in \ref{type.traits} directly or indirectly depends on an incompletely-defined object type \tcode{T}, and \item @@ -2627,4 +2627,3 @@ 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. - From 532c315391acbb6bd54af4865373d78c6826a672 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Wed, 23 Feb 2022 23:19:51 +0100 Subject: [PATCH 7/7] Move [atomics] into [thread] Rename [thread] to 'Concurrency support library'. --- source/atomics.tex | 3851 ----------------------------------------- source/lib-intro.tex | 10 +- source/std.tex | 1 - source/threads.tex | 3837 ++++++++++++++++++++++++++++++++++++++++ tools/check-source.sh | 2 +- 5 files changed, 3841 insertions(+), 3860 deletions(-) delete mode 100644 source/atomics.tex 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/lib-intro.tex b/source/lib-intro.tex index 6405c26b63..6c61e9440b 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -42,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 @@ -121,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} diff --git a/source/std.tex b/source/std.tex index aaad1709ee..040decb135 100644 --- a/source/std.tex +++ b/source/std.tex @@ -132,7 +132,6 @@ \include{locales} \include{iostreams} \include{regex} -\include{atomics} \include{threads} %%-------------------------------------------------- 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/tools/check-source.sh b/tools/check-source.sh index 8bd157fe6a..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 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 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/std.tex b/source/std.tex index dc5385f897..aaad1709ee 100644 --- a/source/std.tex +++ b/source/std.tex @@ -120,6 +120,7 @@ \include{concepts} \include{diagnostics} \include{memory} +\include{meta} \include{utilities} \include{strings} \include{containers} diff --git a/source/utilities.tex b/source/utilities.tex index 52a1a16d73..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 @@ -19,8 +18,6 @@ \ref{expected} & Expected objects & \tcode{} \\ \rowsep \ref{bitset} & Fixed-size sequences of bits & \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 @@ -645,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} @@ -12706,2566 +12648,6 @@ 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