diff --git a/source/algorithms.tex b/source/algorithms.tex index 6f0001c5ca..2fcdf94a67 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -2316,16 +2316,6 @@ template<@\libconcept{input_or_output_iterator}@ O, @\libconcept{copy_constructible}@ F> requires @\libconcept{invocable}@ && @\libconcept{indirectly_writable}@> constexpr O generate_n(O first, iter_difference_t n, F gen); - template<@\exposconcept{execution-policy}@ Ep, @\libconcept{random_access_iterator}@ O, @\libconcept{sized_sentinel_for}@ S, - @\libconcept{copy_constructible}@ F> - requires @\libconcept{invocable}@ && @\libconcept{indirectly_writable}@> - O generate(Ep&& exec, O first, S last, F gen); // freestanding-deleted - template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R, @\libconcept{copy_constructible}@ F> - requires @\libconcept{invocable}@ && @\libconcept{indirectly_writable}@, invoke_result_t> - borrowed_iterator_t generate(Ep&& exec, R&& r, F gen); // freestanding-deleted - template<@\exposconcept{execution-policy}@ Ep, @\libconcept{random_access_iterator}@ O, @\libconcept{copy_constructible}@ F> - requires @\libconcept{invocable}@ && @\libconcept{indirectly_writable}@> - O generate_n(Ep&& exec, O first, iter_difference_t n, F gen); // freestanding-deleted } // \ref{alg.remove}, remove @@ -2857,12 +2847,12 @@ class Comp = ranges::less, class Proj = identity> requires @\libconcept{sortable}@ I stable_sort(Ep&& exec, I first, S last, Comp comp = {}, - Proj proj = {}); // freestanding-deleted + Proj proj = {}); // hosted template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R, class Comp = ranges::less, class Proj = identity> requires @\libconcept{sortable}@, Comp, Proj> borrowed_iterator_t - stable_sort(Ep&& exec, R&& r, Comp comp = {}, Proj proj = {}); // freestanding-deleted + stable_sort(Ep&& exec, R&& r, Comp comp = {}, Proj proj = {}); // hosted } template @@ -3261,12 +3251,12 @@ requires @\libconcept{permutable}@ subrange stable_partition(Ep&& exec, I first, S last, Pred pred, - Proj proj = {}); // freestanding-deleted + Proj proj = {}); // hosted template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R, class Proj = identity, @\libconcept{indirect_unary_predicate}@, Proj>> Pred> requires @\libconcept{permutable}@> borrowed_subrange_t - stable_partition(Ep&& exec, R&& r, Pred pred, Proj proj = {}); // freestanding-deleted + stable_partition(Ep&& exec, R&& r, Pred pred, Proj proj = {}); // hosted } template requires @\libconcept{sortable}@ I inplace_merge(Ep&& exec, I first, I middle, S last, Comp comp = {}, - Proj proj = {}); // freestanding-deleted + Proj proj = {}); // hosted template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R, class Comp = ranges::less, class Proj = identity> requires @\libconcept{sortable}@, Comp, Proj> borrowed_iterator_t inplace_merge(Ep&& exec, R&& r, iterator_t middle, Comp comp = {}, - Proj proj = {}); // freestanding-deleted + Proj proj = {}); // hosted } // \ref{alg.set.operations}, set operations @@ -3643,6 +3633,8 @@ namespace ranges { template using @\libglobal{set_difference_result}@ = in_out_result; + template + using @\libglobal{set_difference_truncated_result}@ = in_in_out_result; template<@\libconcept{input_iterator}@ I1, @\libconcept{sentinel_for}@ S1, @\libconcept{input_iterator}@ I2, @\libconcept{sentinel_for}@ S2, @\libconcept{weakly_incrementable}@ O, class Comp = ranges::less, @@ -3663,7 +3655,7 @@ @\libconcept{random_access_iterator}@ O, @\libconcept{sized_sentinel_for}@ OutS, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{mergeable}@ - set_difference_result + set_difference_truncated_result set_difference(Ep&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result, OutS result_last, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); // freestanding-deleted @@ -3671,7 +3663,8 @@ @\exposconcept{sized-random-access-range}@ OutR, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{mergeable}@, iterator_t, iterator_t, Comp, Proj1, Proj2> - set_difference_result, borrowed_iterator_t> + set_difference_truncated_result, borrowed_iterator_t, + borrowed_iterator_t> set_difference(Ep&& exec, R1&& r1, R2&& r2, OutR&& result_r, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); // freestanding-deleted } @@ -7005,9 +6998,9 @@ ranges::transform(Ep&& exec, I first1, S last1, O result, OutS result_last, F op, Proj proj = {}); template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R, @\exposconcept{sized-random-access-range}@ OutR, - @\libconcept{copy_constructible}@ F, class Proj = identity> + @\libconcept{copy_constructible}@ F, class Proj = identity> requires @\libconcept{indirectly_writable}@, - indirect_result_t, Proj>>> + indirect_result_t, Proj>>> ranges::unary_transform_result, borrowed_iterator_t> ranges::transform(Ep&& exec, R&& r, OutR&& result_r, F op, Proj proj = {}); @@ -7032,17 +7025,17 @@ @\libconcept{random_access_iterator}@ O, @\libconcept{sized_sentinel_for}@ OutS, @\libconcept{copy_constructible}@ F, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{indirectly_writable}@, - projected>> + projected>> ranges::binary_transform_result ranges::transform(Ep&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result, OutS result_last, F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {}); template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R1, @\exposconcept{sized-random-access-range}@ R2, @\exposconcept{sized-random-access-range}@ OutR, @\libconcept{copy_constructible}@ F, - class Proj1 = identity, class Proj2 = identity> + class Proj1 = identity, class Proj2 = identity> requires @\libconcept{indirectly_writable}@, - indirect_result_t, Proj1>, - projected, Proj2>>> + indirect_result_t, Proj1>, + projected, Proj2>>> ranges::binary_transform_result, borrowed_iterator_t, borrowed_iterator_t> ranges::transform(Ep&& exec, R1&& r1, R2&& r2, OutR&& result_r, @@ -7178,8 +7171,8 @@ template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R, class Proj = identity, class T1 = projected_value_t, Proj>, class T2 = range_value_t> requires @\libconcept{indirectly_writable}@, const T2&> && - @\libconcept{indirect_binary_predicate}@, Proj>, const T1*> + @\libconcept{indirect_binary_predicate}@, Proj>, const T1*> borrowed_iterator_t ranges::replace(Ep&& exec, R&& r, const T1& old_value, const T2& new_value, Proj proj = {}); @@ -7299,7 +7292,7 @@ class T2 = range_value_t> requires @\libconcept{indirectly_copyable}@, iterator_t> && @\libconcept{indirect_binary_predicate}@, Proj>, const T1*> && + projected, Proj>, const T1*> && @\libconcept{indirectly_writable}@, const T2&> ranges::replace_copy_result, borrowed_iterator_t> ranges::replace_copy(Ep&& exec, R&& r, OutR&& result_r, const T1& old_value, @@ -7492,17 +7485,6 @@ template<@\libconcept{input_or_output_iterator}@ O, @\libconcept{copy_constructible}@ F> requires @\libconcept{invocable}@ && @\libconcept{indirectly_writable}@> constexpr O ranges::generate_n(O first, iter_difference_t n, F gen); - -template<@\exposconcept{execution-policy}@ Ep, @\libconcept{random_access_iterator}@ O, @\libconcept{sized_sentinel_for}@ S, - @\libconcept{copy_constructible}@ F> - requires @\libconcept{invocable}@ && @\libconcept{indirectly_writable}@> - O ranges::generate(Ep&& exec, O first, S last, F gen); -template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R, @\libconcept{copy_constructible}@ F> - requires @\libconcept{invocable}@ && @\libconcept{indirectly_writable}@, invoke_result_t> - borrowed_iterator_t ranges::generate(Ep&& exec, R&& r, F gen); -template<@\exposconcept{execution-policy}@ Ep, @\libconcept{random_access_iterator}@ O, @\libconcept{copy_constructible}@ F> - requires @\libconcept{invocable}@ && @\libconcept{indirectly_writable}@> - O ranges::generate_n(Ep&& exec, O first, iter_difference_t n, F gen); \end{itemdecl} \begin{itemdescr} @@ -7577,7 +7559,7 @@ class T = projected_value_t, Proj>> requires @\libconcept{permutable}@> && @\libconcept{indirect_binary_predicate}@, Proj>, const T*> + projected, Proj>, const T*> borrowed_subrange_t ranges::remove(Ep&& exec, R&& r, const T& value, Proj proj = {}); @@ -7604,7 +7586,7 @@ \begin{itemdescr} \pnum -Let $E$ be +Let $E(\tcode{i})$ be \begin{itemize} \item \tcode{bool(*i == value)} for \tcode{remove}; \item \tcode{bool(pred(*i))} for \tcode{remove_if}; @@ -7621,7 +7603,7 @@ \pnum \effects Eliminates all the elements referred to by iterator \tcode{i} -in the range \range{first}{last} for which $E$ holds. +in the range \range{first}{last} for which $E(\tcode{i})$ holds. \pnum \returns @@ -7701,7 +7683,7 @@ class Proj = identity, class T = projected_value_t, Proj>> requires @\libconcept{indirectly_copyable}@, iterator_t> && @\libconcept{indirect_binary_predicate}@, Proj>, const T*> + projected, Proj>, const T*> ranges::remove_copy_result, borrowed_iterator_t> ranges::remove_copy(Ep&& exec, R&& r, OutR&& result_r, const T& value, Proj proj = {}); @@ -9076,7 +9058,7 @@ @\libconcept{random_access_iterator}@ I2, @\libconcept{sized_sentinel_for}@ S2, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{indirectly_copyable}@ && @\libconcept{sortable}@ && - @\libconcept{indirect_strict_weak_order}@, projected> + @\libconcept{indirect_strict_weak_order}@, projected> ranges::partial_sort_copy_result ranges::partial_sort_copy(Ep&& exec, I1 first, S1 last, I2 result_first, S2 result_last, Comp comp = {}, Proj1 proj1 = {}, @@ -9281,7 +9263,7 @@ class Proj = identity, @\libconcept{indirect_strict_weak_order}@> Comp = ranges::less> I ranges::is_sorted_until(Ep&& exec, I first, S last, Comp comp = {}, - Proj proj = {}); + Proj proj = {}); template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R, class Proj = identity, @\libconcept{indirect_strict_weak_order}@, Proj>> Comp = ranges::less> borrowed_iterator_t @@ -9892,7 +9874,7 @@ class Proj = identity, @\libconcept{indirect_unary_predicate}@, Proj>> Pred> requires @\libconcept{indirectly_copyable}@, iterator_t> && - @\libconcept{indirectly_copyable}@, iterator_t> + @\libconcept{indirectly_copyable}@, iterator_t> ranges::partition_copy_result, borrowed_iterator_t, borrowed_iterator_t> ranges::partition_copy(Ep&& exec, R&& r, OutR1&& out_true_r, OutR2&& out_false_r, @@ -10340,7 +10322,7 @@ template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R1, @\exposconcept{sized-random-access-range}@ R2, class Proj1 = identity, class Proj2 = identity, @\libconcept{indirect_strict_weak_order}@, Proj1>, - projected, Proj2>> Comp = ranges::less> + projected, Proj2>> Comp = ranges::less> bool ranges::includes(Ep&& exec, R1&& r1, R2&& r2, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); \end{itemdecl} @@ -10557,8 +10539,8 @@ requires @\libconcept{mergeable}@ ranges::set_intersection_result ranges::set_intersection(Ep&& exec, I1 first1, S1 last1, - I2 first2, S2 last2, O result, OutS result_last, - Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); + I2 first2, S2 last2, O result, OutS result_last, + Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ R1, @\exposconcept{sized-random-access-range}@ R2, @\exposconcept{sized-random-access-range}@ OutR, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> @@ -10605,9 +10587,9 @@ If, of those elements, $k$ elements from the first range are copied to the output range, then the first $k$ elements from the second range -are considered \term{skipped}. -If $N < M$, a non-copied element is also considered skipped -if it compares less than the $(N + 1)^\text{th}$ element +are considered \defn{skipped}. +A non-copied element is also considered skipped +if it compares less than the $\min(M, N + 1)^\text{th}$ element of the sorted intersection. Copies the first $N$ elements of the sorted intersection to the range \range{result}{result + $N$}. @@ -10620,11 +10602,10 @@ for the overloads in namespace \tcode{std}. \item \tcode{\{last1, last2, result + $N$\}} - for the overloads in namespace \tcode{ranges}, - if $N$ is equal to $M$. + for the non-parallel algorithm overloads in namespace \tcode{ranges}. \item - Otherwise, \tcode{\{first1 + $A$, first2 + $B$, result_last\}} - for the overloads in namespace \tcode{ranges}, + Otherwise, \tcode{\{first1 + $A$, first2 + $B$, result + $N$\}} + for the parallel algorithm overloads in namespace \tcode{ranges}, where $A$ and $B$ are the numbers of copied or skipped elements in \range{first1}{last1} and \range{first2}{last2}, respectively. \end{itemize} @@ -10690,7 +10671,7 @@ @\libconcept{random_access_iterator}@ O, @\libconcept{sized_sentinel_for}@ OutS, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{mergeable}@ - ranges::set_difference_result + ranges::set_difference_truncated_result ranges::set_difference(Ep&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result, OutS result_last, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -10698,7 +10679,8 @@ @\exposconcept{sized-random-access-range}@ OutR, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{mergeable}@, iterator_t, iterator_t, Comp, Proj1, Proj2> - ranges::set_difference_result, borrowed_iterator_t> + ranges::set_difference_truncated_result, borrowed_iterator_t, + borrowed_iterator_t> ranges::set_difference(Ep&& exec, R1&& r1, R2&& r2, OutR&& result_r, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); \end{itemdecl} @@ -10737,6 +10719,12 @@ that are equivalent to them, the last $\max(m - n, 0)$ elements from \range{first1}{last1} are included in the sorted difference, in order. +Of those equivalent elements, +the first $\min(m, n)$ elements in both ranges +are considered \defn{skipped}. +An element from the second range is also considered skipped +if it compares less than the $\min(N + 1, M)^\text{th}$ element +of the sorted difference. Copies the first $N$ elements of the sorted difference to the range \range{result}{result + $N$}. @@ -10748,14 +10736,19 @@ for the overloads in namespace \tcode{std}. \item \tcode{\{last1, result + $N$\}} - for the overloads in namespace \tcode{ranges}, - if $N$ is equal to $M$. + for the non-parallel overloads in namespace \tcode{ranges}. \item - Otherwise, \tcode{\{j1, result_last\}} - for the overloads in namespace \tcode{ranges}, - where the iterator \tcode{j1} - points to the position of the element in \range{first1}{last1} - corresponding to the $(N + 1)^\text{th}$ element of the sorted difference. + For the parallel algorithm overloads in namespace \tcode{ranges}: + \begin{itemize} + \item + \tcode{\{last1, first2 + $B$, result + $N$\}}, + if $N$ is equal to $M$, + where $B$ is the number of skipped elements in \range{first2}{last2}. + \item + Otherwise, \tcode{\{first1 + $A$, first2 + $B$, result_last\}}, + where $A$ and $B$ are the numbers of copied or skipped elements + in \range{first1}{last1} and \range{first2}{last2}, respectively. + \end{itemize} \end{itemize} \pnum @@ -10830,7 +10823,7 @@ class Proj1 = identity, class Proj2 = identity> requires @\libconcept{mergeable}@, iterator_t, iterator_t, Comp, Proj1, Proj2> ranges::set_symmetric_difference_result, borrowed_iterator_t, - borrowed_iterator_t> + borrowed_iterator_t> ranges::set_symmetric_difference(Ep&& exec, R1&& r1, R2&& r2, OutR&& result_r, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); \end{itemdecl} @@ -12279,15 +12272,15 @@ // \ref{numeric.sat}, saturation arithmetic template - constexpr T add_sat(T x, T y) noexcept; + constexpr T saturating_add(T x, T y) noexcept; template - constexpr T sub_sat(T x, T y) noexcept; + constexpr T saturating_sub(T x, T y) noexcept; template - constexpr T mul_sat(T x, T y) noexcept; + constexpr T saturating_mul(T x, T y) noexcept; template - constexpr T div_sat(T x, T y) noexcept; + constexpr T saturating_div(T x, T y) noexcept; template - constexpr T saturate_cast(U x) noexcept; + constexpr T saturating_cast(U x) noexcept; } \end{codeblock} @@ -13431,10 +13424,10 @@ is performed as a mathematical operation with infinite range and then it is determined whether the mathematical result fits into the result type. -\indexlibraryglobal{add_sat}% +\indexlibraryglobal{saturating_add}% \begin{itemdecl} template - constexpr T add_sat(T x, T y) noexcept; + constexpr T saturating_add(T x, T y) noexcept; \end{itemdecl} \begin{itemdescr} @@ -13449,10 +13442,10 @@ whichever is closer to the value of $\tcode{x} + \tcode{y}$. \end{itemdescr} -\indexlibraryglobal{sub_sat}% +\indexlibraryglobal{saturating_sub}% \begin{itemdecl} template - constexpr T sub_sat(T x, T y) noexcept; + constexpr T saturating_sub(T x, T y) noexcept; \end{itemdecl} \begin{itemdescr} @@ -13467,10 +13460,10 @@ whichever is closer to the value of $\tcode{x} - \tcode{y}$. \end{itemdescr} -\indexlibraryglobal{mul_sat}% +\indexlibraryglobal{saturating_mul}% \begin{itemdecl} template - constexpr T mul_sat(T x, T y) noexcept; + constexpr T saturating_mul(T x, T y) noexcept; \end{itemdecl} \begin{itemdescr} @@ -13485,10 +13478,10 @@ whichever is closer to the value of $\tcode{x} \times \tcode{y}$. \end{itemdescr} -\indexlibraryglobal{div_sat}% +\indexlibraryglobal{saturating_div}% \begin{itemdecl} template - constexpr T div_sat(T x, T y) noexcept; + constexpr T saturating_div(T x, T y) noexcept; \end{itemdecl} \begin{itemdescr} @@ -13510,15 +13503,15 @@ \remarks A function call expression that violates the precondition in the \Fundescx{Preconditions} element -is not a core constant expression\iref{expr.const}. +is not a core constant expression\iref{expr.const.core}. \end{itemdescr} \rSec3[numeric.sat.cast]{Casting} -\indexlibraryglobal{saturate_cast}% +\indexlibraryglobal{saturating_cast}% \begin{itemdecl} template - constexpr R saturate_cast(T x) noexcept; + constexpr R saturating_cast(T x) noexcept; \end{itemdecl} \begin{itemdescr} @@ -14130,7 +14123,8 @@ \indexlibraryglobal{uninitialized_fill}% \begin{itemdecl} -template +template::value_type> constexpr void uninitialized_fill(NoThrowForwardIterator first, NoThrowForwardIterator last, const T& x); \end{itemdecl} @@ -14148,10 +14142,10 @@ \indexlibraryglobal{uninitialized_fill}% \begin{itemdecl} namespace ranges { - template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S, class T> + template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S, class T = iter_value_t> requires @\libconcept{constructible_from}@, const T&> constexpr I uninitialized_fill(I first, S last, const T& x); - template<@\exposconcept{nothrow-forward-range}@ R, class T> + template<@\exposconcept{nothrow-forward-range}@ R, class T = range_value_t> requires @\libconcept{constructible_from}@, const T&> constexpr borrowed_iterator_t uninitialized_fill(R&& r, const T& x); } @@ -14170,7 +14164,8 @@ \indexlibraryglobal{uninitialized_fill_n}% \begin{itemdecl} -template +template::value_type> constexpr NoThrowForwardIterator uninitialized_fill_n(NoThrowForwardIterator first, Size n, const T& x); \end{itemdecl} @@ -14189,7 +14184,7 @@ \indexlibraryglobal{uninitialized_fill_n}% \begin{itemdecl} namespace ranges { - template<@\exposconcept{nothrow-forward-iterator}@ I, class T> + template<@\exposconcept{nothrow-forward-iterator}@ I, class T = iter_value_t> requires @\libconcept{constructible_from}@, const T&> constexpr I uninitialized_fill_n(I first, iter_difference_t n, const T& x); } diff --git a/source/back.tex b/source/back.tex index da31760918..03939906da 100644 --- a/source/back.tex +++ b/source/back.tex @@ -7,10 +7,6 @@ \bibitem{iso4217} ISO 4217:2015, \doccite{Codes for the representation of currencies} -\bibitem{iso10967-1} - ISO/IEC 10967-1:2012, - \doccite{Information technology --- Language independent arithmetic --- - Part 1: Integer and floating point arithmetic} \bibitem{iso14882:2023} ISO/IEC 14882:2023, \doccite{Programming Languages --- \Cpp{}} diff --git a/source/basic.tex b/source/basic.tex index 266580c8bc..1851e2405e 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -32,10 +32,26 @@ \end{note} \pnum -A \defn{name} is an \grammarterm{identifier}\iref{lex.name}, -\grammarterm{conversion-function-id}\iref{class.conv.fct}, -\grammarterm{operator-function-id}\iref{over.oper}, or -\grammarterm{literal-operator-id}\iref{over.literal}. +A \defn{name} is +\begin{itemize} +\item an \grammarterm{identifier} token\iref{lex.token, lex.name} other than + \begin{itemize} + \item + the \grammarterm{identifier} of a + \grammarterm{label}\iref{stmt.label} or + \grammarterm{literal-operator-id}\iref{over.literal}, + \item + the \grammarterm{identifier} following a \keyword{goto} in a + \grammarterm{jump-statement}\iref{stmt.jump.general}, + \item + any \grammarterm{identifier} in a + \grammarterm{module-name}\iref{module.unit} or + \grammarterm{attribute-token}\iref{dcl.attr.grammar}, or + \end{itemize} +\item a \grammarterm{conversion-function-id}\iref{class.conv.fct}, +\item an \grammarterm{operator-function-id}\iref{over.oper}, or +\item a \grammarterm{literal-operator-id}\iref{over.literal}. +\end{itemize} \pnum Two names are \defnx{the same}{name!same} if @@ -115,13 +131,15 @@ \pnum A \defn{variable} is introduced by the -declaration of +declaration $D$ of \begin{itemize} \item a reference other than a non-static data member or \item -an object. +an object, \end{itemize} +where $D$ is not the \grammarterm{parameter-declaration} of +a \grammarterm{template-parameter}. \pnum An \defn{entity} is a @@ -274,7 +292,7 @@ \item it is an explicit instantiation declaration\iref{temp.explicit}, or \item it is -an explicit specialization\iref{temp.expl.spec} whose +an \grammarterm{explicit-specialization}\iref{temp.expl.spec} whose \grammarterm{declaration} is not a definition. \end{itemize} A declaration is said to be a \defn{definition} of each entity that it defines. @@ -492,13 +510,13 @@ \grammarterm{splice-expression}\iref{expr.prim.splice} that designates it. A variable \tcode{x} that is named by a -potentially-evaluated expression $N$ +potentially evaluated expression $N$ that appears at a point $P$ is \defnx{odr-used}{odr-use} by $N$ unless \begin{itemize} \item \tcode{x} is a reference -that is usable in constant expressions at $P$\iref{expr.const}, or +that is usable in constant expressions at $P$\iref{expr.const.init}, or \item $N$ is an element of the set of potential results of an expression $E$, where \begin{itemize} @@ -552,10 +570,10 @@ a \grammarterm{splice-expression} that designates that structured binding. A structured binding is odr-used -if it is named by a potentially-evaluated expression. +if it is named by a potentially evaluated expression. \pnum -\tcode{*\keyword{this}} is odr-used if \keyword{this} appears as a potentially-evaluated expression +\tcode{*\keyword{this}} is odr-used if \keyword{this} appears as a potentially evaluated expression (including as the result of any implicit transformation to a class member access expression\iref{expr.prim.id.general}). @@ -563,7 +581,7 @@ A virtual member function is odr-used if it is not pure. A function is odr-used if it is named by -a potentially-evaluated expression or conversion. +a potentially evaluated expression or conversion. A non-placement allocation or deallocation function for a class is odr-used by the definition of a constructor of that class. A non-placement deallocation function for a class is odr-used by the @@ -656,7 +674,7 @@ \pnum Every program shall contain at least one definition of every function or variable that is odr-used in that program -outside of a discarded statement\iref{stmt.if}; no diagnostic required. +outside of a discarded statement\iref{stmt.if}; no diagnostic required\ifndrdef{basic.def.odr.exact.one.def}. The definition can appear explicitly in the program, it can be found in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see~\ref{class.default.ctor}, \ref{class.copy.ctor}, @@ -739,7 +757,7 @@ \pnum If a definable item \tcode{D} is defined in a translation unit -by an injected declaration $X$\iref{expr.const} and +by an injected declaration $X$\iref{expr.const.reflect} and another translation unit contains a definition of \tcode{D}, that definition shall be an injected declaration having the same characteristic sequence as $X$; @@ -781,7 +799,7 @@ a non-volatile const object with internal or no linkage if the object \begin{itemize} \item has the same literal type in all definitions of \tcode{D}, -\item is initialized with a constant expression\iref{expr.const}, +\item is initialized with a constant expression\iref{expr.const.const}, \item is not odr-used in any definition of \tcode{D}, and \item has the same value in all definitions of \tcode{D}, \end{itemize} @@ -939,7 +957,7 @@ reachable unnamed enumeration definition in the same scope that have the same first enumerator name and do not have typedef names for linkage purposes\iref{dcl.enum}, -those unnamed enumeration types shall be the same; no diagnostic required. +those unnamed enumeration types shall be the same; no diagnostic required\ifndrdef{basic.def.odr.unnamed.enum.same.type}. \indextext{one-definition rule|)} \rSec1[basic.scope]{Scope}% @@ -999,7 +1017,7 @@ Corresponding declarations with appropriate linkage declare the same entity\iref{basic.link}. \item -The declaration in a \grammarterm{template-declaration} +The \grammarterm{declaration} of a \grammarterm{template-declaration} inhabits the same scope as the \grammarterm{template-declaration}. \item Friend declarations and @@ -1660,7 +1678,12 @@ used in further processing. \pnum -A program point $P$ is said to follow +There is a \defnadj{program}{point} +before the first token of the translation unit, +at least one between every pair of adjacent tokens, and +at least one after the last token of the translation unit. + +A program point $P$ is said to \defnx{follow}{follow!program point} any declaration in the same translation unit whose locus\iref{basic.scope.pdecl} is before $P$. \begin{note} @@ -1815,7 +1838,7 @@ If it is an invalid set, the program is ill-formed. If it differs from the result of a search in $T$ for $M$ in a complete-class context\iref{class.mem} of $T$, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{class.member.lookup.name.refers.diff.decl}. \begin{example} \begin{codeblock} struct A { int x; }; // S(x,A) = \{ \{ \tcode{A::x} \}, \{ \tcode{A} \} \} @@ -2065,7 +2088,8 @@ \pnum In a friend declaration \grammarterm{declarator} whose \grammarterm{declarator-id} is a \grammarterm{qualified-id} -whose lookup context\iref{basic.lookup.qual} is a class or namespace $S$, +whose \grammarterm{nested-name-specifier} +designates a class or namespace $S$\iref{expr.prim.id.qual}, lookup for an unqualified name that appears after the \grammarterm{declarator-id} performs a search in the scope associated with $S$. @@ -2557,13 +2581,13 @@ \end{footnote} \begin{itemize} \item -if the search finds the injected-class-name of \tcode{C}\iref{class.pre}, or +if the search finds the injected-class-name of $C$\iref{class.pre}, or \item if $N$ is dependent and is the terminal name of a \grammarterm{using-declarator}\iref{namespace.udecl} that names a constructor, \end{itemize} -$N$ is instead considered to name the constructor of class \tcode{C}. +$N$ is instead considered to name the constructor of class $C$. Such a constructor name shall be used only in the \grammarterm{declarator-id} of a (friend) declaration of a constructor or in a \grammarterm{using-declaration}. @@ -2834,7 +2858,7 @@ \pnum The \grammarterm{constant-expression} of a \grammarterm{splice-specifier} shall be a converted constant expression of -type \tcode{std::meta::info}\iref{expr.const}. +type \tcode{std::meta::info}\iref{expr.const.const}. A \grammarterm{splice-specifier} whose converted \grammarterm{constant-expression} represents a construct $X$ is said to \defn{designate} either @@ -3055,9 +3079,7 @@ \item they both declare type aliases or namespace aliases that have the same underlying entity, or \item -they both declare names with module linkage and are attached to the same module, or -\item -they both declare names with external linkage. +they both declare names with module or external linkage and are attached to the same module. \end{itemize} \begin{note} There are other circumstances in which declarations declare @@ -3074,9 +3096,11 @@ \end{note} \pnum -If two declarations of an entity are -attached to different modules, the program is ill-formed; -no diagnostic is required if neither is reachable from the other. +\begin{note} +If two declarations correspond but are +attached to different modules, the program is ill-formed +if one precedes the other\iref{basic.scope.scope}. +\end{note} \begin{example} \begin{codeblocktu}{\tcode{"decls.h"}} int f(); // \#1, attached to the global module @@ -3088,15 +3112,15 @@ #include "decls.h" export module M; export using ::f; // OK, does not declare an entity, exports \#1 -int g(); // error: matches \#2, but attached to \tcode{M} +int g(); // error: corresponds to \#2, but attached to \tcode{M} export int h(); // \#3 export int k(); // \#4 \end{codeblocktu} \begin{codeblocktu}{Other translation unit} import M; -static int h(); // error: matches \#3 -int k(); // error: matches \#4 +static int h(); // error: conflicts with \#3 +int k(); // error: conflicts with \#4 \end{codeblocktu} \end{example} As a consequence of these rules, @@ -3142,7 +3166,8 @@ declarations for an array object can specify array types that differ by the presence or absence of a major array bound\iref{dcl.array}. -No diagnostic is required if neither declaration is reachable from the other. +No diagnostic is required +if neither declaration is reachable from the other\ifndrdef{basic.link.consistent.types}. \begin{example} \begin{codeblock} int f(int x, int x); // error: different entities for \tcode{x} @@ -3171,10 +3196,10 @@ a \grammarterm{reflect-expression} or a \grammarterm{splice-specifier} that, respectively, represents or designates $E$, \item -$D$ is an injected declaration\iref{expr.const} +$D$ is an injected declaration\iref{expr.const.reflect} whose characteristic sequence contains a reflection that represents -a data member description ($T$, $N$, $A$, $W$, $\mathit{NUA}$)\iref{class.mem.general} +a data member description ($T$, $N$, $A$, $W$, $\mathit{NUA}$, $\mathit{ANN}$)\iref{class.mem.general} for which $T$ is $E$, \item $E$ is not a function or function template and $D$ contains an @@ -3278,7 +3303,7 @@ a direct base class relationship $(D, B)$\iref{class.derived.general} for which either $D$ or $B$ is TU-local, or \item -a data member description $(T, N, A, W, \mathit{NUA})$\iref{class.mem.general} +a data member description $(T, N, A, W, \mathit{NUA}, \mathit{ANN})$\iref{class.mem.general} for which $T$ is TU-local. \end{itemize} \end{itemize} @@ -3622,8 +3647,7 @@ \item the backing array of an initializer list\iref{dcl.init.ref}, or \item - the object introduced by a call to \tcode{std::meta::reflect_constant_array} - or \tcode{std::meta::reflect_constant_string}\iref{meta.define.static}, or + a template parameter object of array type\iref{meta.define.static}, or \item a subobject thereof. \end{itemize} @@ -3639,18 +3663,18 @@ may have the same address if \begin{itemize} \item one is nested within the other, -\item at least one is a subobject of zero size and they are not of similar types\iref{conv.qual}, +\item +they are both nested within some complete object $o$, +exactly one is a subobject of $o$, and the subobject is of zero size, +\item +they are both subobjects of the same complete object, +at least one is a subobject of zero size, and +they are not of similar types\iref{conv.qual}, or \item they are both potentially non-unique objects; \end{itemize} otherwise, they have distinct addresses and occupy disjoint bytes of storage. -\begin{footnote} -Under the ``as-if'' rule an -implementation is allowed to store two objects at the same machine address or -not store an object at all if the program cannot observe the -difference\iref{intro.execution}. -\end{footnote} \begin{example} \begin{codeblock} static const char test1 = 'x'; @@ -3670,6 +3694,16 @@ the address of an unspecified byte of storage occupied by the complete object of that subobject. +\pnum +A \defnadj{union elemental}{subobject} +\indextext{union!elemental subobject|see{subobject, union elemental}} +is a direct member of a union or +an element of an array that is a union elemental subobject. +An \defnx{inactive union elemental subobject}{subobject!union elemental!inactive} +\indextext{inactive union elemental subobject|see{subobject, union elemental, inactive}} +\indextext{union!inactive elemental subobject|see{subobject, union elemental, inactive}} +is a union elemental subobject that is not within its lifetime. + \pnum The \defnx{constituent values}{constituent value} of an object $o$ are \begin{itemize} @@ -3677,7 +3711,7 @@ if $o$ has scalar type, the value of $o$; \item otherwise, the constituent values of any direct subobjects of $o$ -other than inactive union members. +other than inactive union elemental subobjects. \end{itemize} The \defnx{constituent references}{constituent reference} of an object $o$ are \begin{itemize} @@ -3685,8 +3719,46 @@ any direct members of $o$ that have reference type, and \item the constituent references of any direct subobjects of $o$ -other than inactive union members. +other than inactive union elemental subobjects. \end{itemize} +\begin{example} +\begin{codeblock} +struct A { + struct X { + int i; + int j; + }; + + struct Y { + X x1; + X x2; + }; + + union { + int i; + int arr[4]; + Y y; + }; +}; + +constexpr A v1; // OK, no constituent values +constexpr A v2{.i=1}; // OK, the constituent values are \tcode{\{v2.i\}} +constexpr A v3 = []{ + A a; + std::start_lifetime(a.arr); // OK, \tcode{arr} is now the active element of the union + new (&a.arr[1]) int(1); + a.arr[2] = 2; + return a; +}(); // OK, the constituent values are \tcode{\{v3.arr[1], v3.arr[2]\}} +constexpr A v4 = []{ + A a; + a.y.x1.i = 1; + a.y.x2.j = 2; + return a; +}(); // error: the constituent values include \tcode{v4.y.x1.j} and \tcode{v4.y.x2.i} + // which have erroneous value +\end{codeblock} +\end{example} \pnum Some operations are described as @@ -3697,7 +3769,7 @@ zero or more objects of implicit-lifetime types\iref{term.implicit.lifetime.type} in its specified region of storage if doing so would result in the program having defined behavior. -If no such set of objects would give the program defined behavior, +If no such set of objects would give the program defined behavior\ubdef{intro.object.implicit.create}, the behavior of the program is undefined. If multiple such sets of objects would give the program defined behavior, it is unspecified which such set of objects is created. @@ -3715,7 +3787,7 @@ and produce a pointer value that points to that object, if that value would result in the program having defined behavior. If no such pointer value would give the program defined behavior, -the behavior of the program is undefined. +the behavior of the program is undefined\ubdef{intro.object.implicit.pointer}. If multiple such pointer values would give the program defined behavior, it is unspecified which such pointer value is produced. @@ -3766,10 +3838,10 @@ integer value representing the number of bytes between successive addresses at which a given object can be allocated. An object type imposes an alignment requirement on every object of that type; stricter alignment can be requested -using the alignment specifier\iref{dcl.align}. +using the \grammarterm{alignment-specifier}\iref{dcl.align}. Attempting to create an object\iref{intro.object} in storage that does not meet the alignment requirements of the object's type -is undefined behavior. +is undefined behavior\ubdef{basic.align.object.alignment}. \pnum A \defnadj{fundamental}{alignment} is represented by an alignment @@ -3826,8 +3898,8 @@ the narrow character types\iref{basic.fundamental} shall have the weakest alignment requirement. \begin{note} -This enables the ordinary character types to be used as the -underlying type for an aligned memory area\iref{dcl.align}. +The type \tcode{\keyword{unsigned} \keyword{char}} can be used as +the element type of an array providing aligned storage\iref{dcl.align}. \end{note} \pnum @@ -3958,19 +4030,20 @@ if the pointer were of type \tcode{\keyword{void}*} is well-defined. Indirection through such a pointer is permitted but the resulting lvalue may only be used in limited ways, as described below. The -program has undefined behavior if +program has undefined behavior if: \begin{itemize} \item - the pointer is used as the operand of a \grammarterm{delete-expression}, + the pointer is used as the operand of a \grammarterm{delete-expression}\ubdef{lifetime.outside.pointer.delete}, \item the pointer is used to access a non-static data member or call a - non-static member function of the object, or + non-static member function of the object\ubdef{lifetime.outside.pointer.member}, or \item the pointer is converted\iref{conv.ptr,expr.static.cast} to a pointer - to a virtual base class or to a base class thereof, or + to a virtual base class\ubdef{lifetime.outside.pointer.virtual} or + to a base class thereof, or \item the pointer is used as the operand of a - \keyword{dynamic_cast}\iref{expr.dynamic.cast}. + \keyword{dynamic_cast}\iref{expr.dynamic.cast}\ubdef{lifetime.outside.pointer.dynamic.cast}. \end{itemize} \begin{example} \begin{codeblock} @@ -4013,14 +4086,14 @@ a glvalue refers to allocated storage\iref{basic.stc.dynamic.allocation}, and using the properties of the glvalue that do not depend on its value is -well-defined. The program has undefined behavior if +well-defined. The program has undefined behavior if: \begin{itemize} -\item the glvalue is used to access the object, or -\item the glvalue is used to call a non-static member function of the object, or -\item the glvalue is bound to a reference to a virtual base class\iref{dcl.init.ref}, or +\item the glvalue is used to access the object\ubdef{lifetime.outside.glvalue.access}, or +\item the glvalue is used to call a non-static member function of the object\ubdef{lifetime.outside.glvalue.member}, or +\item the glvalue is bound to a reference to a virtual base class\iref{dcl.init.ref}\ubdef{lifetime.outside.glvalue.virtual}, or \item the glvalue is used as the operand of a \keyword{dynamic_cast}\iref{expr.dynamic.cast} or as the operand of -\keyword{typeid}. +\keyword{typeid}\ubdef{lifetime.outside.glvalue.dynamic.cast}. \end{itemize} \begin{note} @@ -4105,7 +4178,7 @@ \end{footnote} and another object of the original type does not occupy that same storage location when the implicit destructor call takes -place, the behavior of the program is undefined. This is true +place, the behavior of the program is undefined\ubdef{original.type.implicit.destructor}. This is true even if the block is exited with an exception. \begin{example} \begin{codeblock} @@ -4125,7 +4198,7 @@ Creating a new object within the storage that a const, complete object with static, thread, or automatic storage duration occupies, or within the storage that such a const object used to occupy before -its lifetime ended, results in undefined behavior. +its lifetime ended, results in undefined behavior\ubdef{creating.within.const.complete.obj}. \begin{example} \begin{codeblock} struct B { @@ -4186,7 +4259,7 @@ then the value produced by that operator is erroneous. Except in the following cases, if an indeterminate value is produced by an evaluation, -the behavior is undefined, and +the behavior is undefined\ubdef{basic.indet.value}, and if an erroneous value is produced by an evaluation, the behavior is erroneous and the result of the evaluation is that erroneous value: @@ -4473,7 +4546,7 @@ does not satisfy the semantic constraints specified in~\ref{basic.stc.dynamic.allocation} and~\ref{basic.stc.dynamic.deallocation}, -the behavior is undefined. +the behavior is undefined\ubdef{basic.stc.alloc.dealloc.constraint}. \indextext{storage duration!dynamic|)} @@ -4483,7 +4556,7 @@ \indextext{function!allocation}% An allocation function that is not a class member function shall belong to the global scope and not have a name with internal linkage. -The return type shall be \tcode{\keyword{void}*}. The first +The return type shall be ``pointer to \keyword{void}''. The first parameter shall have type \tcode{std::size_t}\iref{support.types}. The first parameter shall not have an associated default argument\iref{dcl.fct.default}. The value of the first parameter @@ -4513,7 +4586,7 @@ \tcode{p0} represents the address of a block of storage disjoint from the storage for any other object accessible to the caller. The effect of indirecting through a pointer -returned from a request for zero size is undefined. +returned from a request for zero size is undefined\ubdef{basic.stc.alloc.zero.dereference}. \begin{footnote} The intent is to have \tcode{\keyword{operator} \keyword{new}()} implementable by @@ -4604,9 +4677,9 @@ Each deallocation function shall return \keyword{void}. If the function is a destroying operator delete declared in class type \tcode{C}, -the type of its first parameter shall be \tcode{C*}; +the type of its first parameter shall be ``pointer to \tcode{C}''; otherwise, the type of its first -parameter shall be \tcode{\keyword{void}*}. A deallocation function may have more +parameter shall be ``pointer to \keyword{void}''. A deallocation function may have more than one parameter. \indextext{deallocation function!usual}% A \defn{usual deallocation function} is a deallocation function @@ -4636,7 +4709,7 @@ signature. \pnum -If a deallocation function terminates by throwing an exception, the behavior is undefined. +If a deallocation function terminates by throwing an exception, the behavior is undefined\ubdef{basic.stc.alloc.dealloc.throw}. The value of the first argument supplied to a deallocation function may be a null pointer value; if so, and if the deallocation function is one supplied in the standard library, the call has no effect. @@ -4743,7 +4816,7 @@ \pnum When an object of type \tcode{X} -is passed to or returned from a potentially-evaluated function call, +is passed to or returned from a potentially evaluated function call, if \tcode{X} is \begin{itemize} \item @@ -4891,7 +4964,7 @@ covered above. \begin{example} \begin{codeblock} -const int& x = (const int&)1; // temporary for value 1 has same lifetime as x +const int& x = (const int&)1; // temporary for value \tcode{1} has same lifetime as \tcode{x} \end{codeblock} \end{example} \end{note} @@ -4953,7 +5026,7 @@ \pnum The sixth context is when a temporary object is created in the \grammarterm{expansion-initializer} -of a destructuring expansion statement. +of an iterating or destructuring expansion statement. If such a temporary object would otherwise be destroyed at the end of that \grammarterm{expansion-initializer}, the object persists for the lifetime of the reference @@ -5222,7 +5295,7 @@ \begin{codeblock} class X; // \tcode{X} is an incomplete type extern X* xp; // \tcode{xp} is a pointer to an incomplete type -extern int arr[]; // the type of arr is incomplete +extern int arr[]; // the type of \tcode{arr} is incomplete typedef int UNKA[]; // \tcode{UNKA} is an incomplete type UNKA* arrp; // \tcode{arrp} is a pointer to an incomplete type UNKA** arrpp; @@ -5351,7 +5424,7 @@ during the evaluation of a core constant expression. \end{itemize} Every function of consteval-only type shall be -an immediate function\iref{expr.const}. +an immediate function\iref{expr.const.imm}. \rSec2[basic.fundamental]{Fundamental types} @@ -5635,13 +5708,12 @@ \indextext{type!\idxcode{void}}% A type \cv{}~\keyword{void} is an incomplete type that cannot be completed; such a type has -an empty set of values. It is used as the return -type for functions that do not return a value. +an empty set of values. \begin{note} An expression of type \cv{}~\keyword{void} can be used as \begin{itemize} -\item an expression statement\iref{stmt.expr}, -\item the expression in a \keyword{return} statement\iref{stmt.return} +\item the \grammarterm{expression} of an expression statement\iref{stmt.expr}, +\item the operand of a \keyword{return} statement\iref{stmt.return} for a function with the return type \cv{}~\keyword{void}, \item an operand of a comma expression\iref{expr.comma}, \item the operand of a parenthesized expression\iref{expr.prim.paren}, @@ -5660,7 +5732,12 @@ A prvalue of type \tcode{std::nullptr_t} is a null pointer constant\iref{conv.ptr}. Such values participate in the pointer and the pointer-to-member conversions\iref{conv.ptr,conv.mem}. -\tcode{\keyword{sizeof}(std::nullptr_t)} shall be equal to \tcode{\keyword{sizeof}(\keyword{void}*)}. +The size\iref{expr.sizeof} and alignment requirement\iref{basic.align} of +the type \tcode{std::nullptr_t} are those of +the type ``pointer to \keyword{void}''. +\begin{note} +The value representation can comprise no bits\iref{conv.lval}. +\end{note} \pnum A value of type \tcode{std::meta::info} is called a \defn{reflection}. @@ -5771,7 +5848,7 @@ If the implementation supports an extended floating-point type\iref{basic.fundamental} whose properties are specified by the \IsoFloatUndated{} floating-point interchange format binary16, -then the \grammarterm{typedef-name} \tcode{std::float16_t} +then the type alias \tcode{std::float16_t} is declared in the header \libheaderref{stdfloat} and names such a type, the macro \mname{STDCPP_FLOAT16_T} is defined\iref{cpp.predefined}, and the floating-point literal suffixes \tcode{f16} and \tcode{F16} @@ -5781,7 +5858,7 @@ If the implementation supports an extended floating-point type whose properties are specified by the \IsoFloatUndated{} floating-point interchange format binary32, -then the \grammarterm{typedef-name} \tcode{std::float32_t} +then the type alias \tcode{std::float32_t} is declared in the header \libheader{stdfloat} and names such a type, the macro \mname{STDCPP_FLOAT32_T} is defined, and the floating-point literal suffixes \tcode{f32} and \tcode{F32} are supported. @@ -5790,7 +5867,7 @@ If the implementation supports an extended floating-point type whose properties are specified by the \IsoFloatUndated{} floating-point interchange format binary64, -then the \grammarterm{typedef-name} \tcode{std::float64_t} +then the type alias \tcode{std::float64_t} is declared in the header \libheader{stdfloat} and names such a type, the macro \mname{STDCPP_FLOAT64_T} is defined, and the floating-point literal suffixes \tcode{f64} and \tcode{F64} are supported. @@ -5799,7 +5876,7 @@ If the implementation supports an extended floating-point type whose properties are specified by the \IsoFloatUndated{} floating-point interchange format binary128, -then the \grammarterm{typedef-name} \tcode{std::float128_t} +then the type alias \tcode{std::float128_t} is declared in the header \libheader{stdfloat} and names such a type, the macro \mname{STDCPP_FLOAT128_T} is defined, and the floating-point literal suffixes \tcode{f128} and \tcode{F128} are supported. @@ -5812,7 +5889,7 @@ precision in bits ($p$) of 8, maximum exponent ($emax$) of 127, and exponent field width in bits ($w$) of 8, then -the \grammarterm{typedef-name} \tcode{std::bfloat16_t} +the type alias \tcode{std::bfloat16_t} is declared in the header \libheader{stdfloat} and names such a type, the macro \mname{STDCPP_BFLOAT16_T} is defined, and the floating-point literal suffixes \tcode{bf16} and \tcode{BF16} are supported. @@ -5979,6 +6056,28 @@ alignment requirement. \end{note} +\pnum +A pointer value +pointing to a potentially non-unique object $O$\iref{intro.object} is +\indextext{value!associated with an evaluation}% +\defn{associated with} the evaluation of +\begin{itemize} +\item +the \grammarterm{string-literal}\iref{lex.string} that resulted in the string literal object, +\item +the initializer list\iref{dcl.init.list} that resulted in the backing array, +or +\item +the initialization of +the template parameter object\iref{temp.arg.nontype, meta.define.static} +\end{itemize} +that is $O$ or of which $O$ is a subobject. +\begin{note} +A pointer value obtained by pointer arithmetic\iref{expr.add} +from a pointer value associated with an evaluation $E$ +is also associated with $E$. +\end{note} + \pnum A pointer value $P$ is \indextext{value!valid in the context of an evaluation}% @@ -5990,7 +6089,7 @@ $P$ is not valid in the context of $E$, then the behavior is undefined if $E$ is an indirection\iref{expr.unary.op} or -an invocation of a deallocation function\iref{basic.stc.dynamic.deallocation}, +an invocation of a deallocation function\iref{basic.stc.dynamic.deallocation}\ubdef{basic.compound.invalid.pointer}, and \impldef{invalid pointer value in the context of an evaluation} otherwise. \begin{footnote} Some implementations might define that @@ -6252,7 +6351,7 @@ \tcode{\keyword{long} \keyword{double}}, \keyword{double}, and \tcode{std::float64_t} -have the same set of values (see \IsoC H.4.3). +have the same set of values (see \IsoC{} H.4.3). \end{tailnote} \end{itemize} \begin{note} @@ -6368,9 +6467,9 @@ \item an unevaluated operand\iref{expr.context}, \item -a \grammarterm{constant-expression}\iref{expr.const}, +a \grammarterm{constant-expression}\iref{expr.const.core}, \item -an immediate invocation\iref{expr.const}, +an immediate invocation\iref{expr.const.imm}, \item an \grammarterm{init-declarator}\iref{dcl.decl} (including such introduced by a structured binding\iref{dcl.struct.bind}) or @@ -6437,7 +6536,7 @@ \indextext{value computation|(}% Reading an object designated by a \keyword{volatile} glvalue\iref{basic.lval}, modifying an object, -producing an injected declaration\iref{expr.const}, +producing an injected declaration\iref{expr.const.reflect}, calling a library I/O function, or calling a function that does any of those operations are all \defn{side effects}, @@ -6510,7 +6609,7 @@ The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. -The behavior is undefined if +The behavior is undefined\iref{intro.multithread}\ubdef{intro.execution.unsequenced.modification} if \begin{itemize} \item \indextext{side effects}% @@ -6617,7 +6716,7 @@ \pnum During the evaluation of an expression -as a core constant expression\iref{expr.const}, +as a core constant expression\iref{expr.const.core}, evaluations of operands of individual operators and of subexpressions of individual expressions that are otherwise either unsequenced or indeterminately sequenced @@ -6806,7 +6905,7 @@ \item $A$ happens before $B$ and \item there is no other \indextext{side effects}% -side effect $X$ to $M$ such that $A$ +side effect $X$ on $M$ such that $A$ happens before $X$ and $X$ happens before $B$. \end{itemize} @@ -6918,7 +7017,7 @@ and neither happens before the other, except for the special case for signal handlers described below. Any such data race results in undefined -behavior. +behavior\ubdef{intro.races.data}. \begin{note} It can be shown that programs that correctly use mutexes and \tcode{memory_order::seq_cst} operations to prevent all data races and use no @@ -6977,8 +7076,8 @@ \rSec3[intro.progress]{Forward progress} \pnum -The implementation may assume that any thread will eventually do one of the -following: +The implementation may assume\ubdef{intro.progress.stops} that any thread +will eventually do one of the following: \begin{itemize} \item terminate, \item invoke the function \tcode{std::this_thread::yield}\iref{thread.thread.this}, @@ -7282,7 +7381,7 @@ objects with automatic storage duration\iref{class.dtor}. If \tcode{std::exit} is invoked during the destruction of an object with static or thread storage duration, the program has undefined -behavior. +behavior\ubdef{basic.start.main.exit.during.destruction}. \pnum \indextext{termination!program}% @@ -7311,7 +7410,7 @@ \indextext{initialization!constant}% \defnx{Constant initialization}{constant initialization} is performed if a variable with static or thread storage duration -is constant-initialized\iref{expr.const}. +is constant-initialized\iref{expr.const.init}. \indextext{initialization!zero-initialization}% If constant initialization is not performed, a variable with static storage duration\iref{basic.stc.static} or thread storage @@ -7349,16 +7448,18 @@ object \tcode{obj2} potentially requiring dynamic initialization and defined later in the same translation unit, it is unspecified whether the value of \tcode{obj2} used will be the value of the fully initialized \tcode{obj2} (because \tcode{obj2} was statically -initialized) or will be the value of \tcode{obj2} merely zero-initialized. For example, +initialized) or will be the value of \tcode{obj2} merely zero-initialized. For example: \begin{codeblock} inline double fd() { return 1.0; } extern double d1; -double d2 = d1; // unspecified: - // either statically initialized to \tcode{0.0} or - // dynamically initialized to \tcode{0.0} if \tcode{d1} is - // dynamically initialized, or \tcode{1.0} otherwise -double d1 = fd(); // either initialized statically or dynamically to \tcode{1.0} +double d2 = d1; +double d1 = fd(); \end{codeblock} +Both \tcode{d1} and \tcode {d2} can be initialized +either statically or dynamically. +If \tcode{d1} is initialized statically and \tcode{d2} dynamically, +both variables are initialized to \tcode{1.0}; +in all other cases, \tcode{d2} is initialized to \tcode{0.0}. \end{note} \rSec3[basic.start.dynamic]{Dynamic initialization of non-block variables} @@ -7562,7 +7663,7 @@ \pnum The destruction of a complete object with thread storage duration within a given thread -and having constant destruction\iref{expr.const} +and having constant destruction\iref{expr.const.defns} is sequenced after the destruction of any other complete object with thread storage duration within the thread. The destruction of a complete object with static storage duration @@ -7617,7 +7718,7 @@ \pnum If a function contains a block variable of static or thread storage duration that has been destroyed and the function is called during the destruction of an object with static or -thread storage duration, the program has undefined behavior if the flow of control +thread storage duration, the program has undefined behavior\ubdef{basic.start.term.use.after.destruction} if the flow of control passes through the definition of the previously destroyed block variable. \begin{note} Likewise, the behavior is undefined @@ -7645,7 +7746,7 @@ handlers\iref{support.runtime} that does not happen before\iref{intro.multithread} completion of destruction of objects with static storage duration and execution of \tcode{std::atexit} registered functions\iref{support.start.term}, the program has -undefined behavior. +undefined behavior\ubdef{basic.start.term.signal.handler}. \begin{note} If there is a use of an object with static storage duration that does not happen before the object's destruction, the program has undefined @@ -7694,7 +7795,7 @@ An invocation of the macro \tcode{va_start}\iref{cstdarg.syn} shall not be a subexpression of the predicate of a contract assertion, -no diagnostic required. +no diagnostic required\ifndrdef{basic.contract.vastart.contract.predicate}. \pnum \begin{note} @@ -7801,7 +7902,7 @@ \item the evaluation of the predicate is performed in a context that is -manifestly constant-evaluated\iref{expr.const} +manifestly constant-evaluated\iref{expr.const.defns} and the predicate is not a core constant expression. \end{itemize} @@ -7822,7 +7923,7 @@ \pnum \indexdefn{contract evaluation semantics!terminating}% If a contract violation occurs -in a context that is manifestly constant-evaluated\iref{expr.const}, +in a context that is manifestly constant-evaluated\iref{expr.const.defns}, and the evaluation semantic is a terminating semantic, the program is ill-formed. @@ -8100,6 +8201,6 @@ If the contract-violation handler is not replaceable, a declaration of a replacement function for the contract-violation handler -is ill-formed, no diagnostic required. +is ill-formed, no diagnostic required.\ifndrdef{basic.contract.handler.replacing.nonreplaceable} \indextext{contract assertion|)} diff --git a/source/classes.tex b/source/classes.tex index c6bb8eb3f1..f477ee2e41 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -580,6 +580,10 @@ shall either declare at least one member name of the class or declare at least one unnamed bit-field. +A \defnx{user-declared}{entity!user-declared} +\indextext{user-declared entity|see{entity, user-declared}} +entity is a direct member or a friend that, in either case, +is declared by a \grammarterm{member-declaration}. \pnum A \defn{data member} is either a non-function member introduced by a @@ -717,7 +721,7 @@ shall not directly or indirectly cause the implicit definition of a defaulted default constructor for the enclosing class or the exception specification of that constructor. -An immediate invocation\iref{expr.const} that +An immediate invocation\iref{expr.const.imm} that is a potentially-evaluated subexpression\iref{intro.execution} of a default member initializer is neither evaluated nor checked for whether it @@ -928,18 +932,24 @@ \pnum A \defnadj{data member}{description} is -a quintuple ($T$, $N$, $A$, $W$, $\mathit{NUA}$) +a sextuple ($T$, $N$, $A$, $W$, $\mathit{NUA}$, $\mathit{ANN}$) describing the potential declaration of a non-static data member where \begin{itemize} \item $T$ is a type, \item $N$ is an \grammarterm{identifier} or $\bot$, \item $A$ is an alignment or $\bot$, -\item $W$ is a bit-field width or $\bot$, and -\item $\mathit{NUA}$ is a boolean value. +\item $W$ is a bit-field width or $\bot$, +\item $\mathit{NUA}$ is a boolean value, and +\item $\mathit{ANN}$ is a sequence of reflections +representing either values or template parameter objects. \end{itemize} Two data member descriptions are equal -if each of their respective components are the same entities, -are the same identifiers, have equal values, or are both $\bot$. +if each of their respective components are +the same entity, +the same identifier, +the same value, +the same sequence, or +both $\bot$. \begin{note} The components of a data member description describe a data member such that \begin{itemize} @@ -1273,8 +1283,9 @@ has a default argument (including the case of a constructor with no parameters). \indextext{implicitly-declared default constructor}% -If there is no user-declared constructor or constructor template for class -\tcode{X}, +If a class does not have +a user-declared constructor or constructor template, +and the class is not an anonymous union, a non-explicit constructor having no parameters is implicitly declared as defaulted\iref{dcl.fct.def}. An implicitly-declared default constructor is an @@ -1332,26 +1343,14 @@ \defnx{non-trivial}{constructor!default!non-trivial}. \pnum -If a default constructor of a union-like class \tcode{X} is trivial, -then for each union \tcode{U} -that is either \tcode{X} or an anonymous union member of \tcode{X}, -if the first variant member, if any, of \tcode{U} -has implicit-lifetime type\iref{basic.types.general}, -the default constructor of \tcode{X} begins the lifetime of that member -if it is not the active member of its union. -\begin{note} -It is already the active member if \tcode{U} was value-initialized. -\end{note} -Otherwise, -an implicitly-defined\iref{dcl.fct.def.default} default constructor performs the set of +An implicitly-defined\iref{dcl.fct.def.default} default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with no \grammarterm{ctor-initializer}\iref{class.base.init} and an empty \grammarterm{compound-statement}. If that user-written default constructor would be ill-formed, the program is ill-formed. -The implicitly-defined -default constructor is \keyword{constexpr}. +The implicitly-defined default constructor is constexpr. Before the defaulted default constructor for a class is implicitly defined, all the non-user-provided default constructors for its base classes and @@ -1503,7 +1502,8 @@ \end{example} \pnum -If the class definition does not explicitly declare a copy constructor, +If the class does not have a user-declared copy constructor +and the class is not an anonymous union, a non-explicit one is declared \defnx{implicitly}{constructor!copy!implicitly declared}. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy @@ -1543,10 +1543,13 @@ \pnum \indextext{constructor!move!implicitly declared}% -If the definition of a class \tcode{X} does not explicitly declare -a move constructor, a non-explicit one will be +If a class \tcode{X} does not have +a user-declared move constructor, a non-explicit one will be implicitly declared as defaulted if and only if \begin{itemize} +\item +\tcode{X} is not an anonymous union, + \item \tcode{X} does not have a user-declared copy constructor, @@ -1601,6 +1604,17 @@ an rvalue which can use the copy constructor instead. \end{note} +\pnum +\begin{note} +A using-declaration in a derived class \tcode{C} that +names a constructor from a base class +never suppresses the implicit declaration of +a copy/move constructor of \tcode{C}, +even if the base class constructor would be +a copy or move constructor +if declared as a member of \tcode{C}. +\end{note} + \pnum \indextext{constructor!copy!trivial}% \indextext{constructor!move!trivial}% @@ -1636,8 +1650,7 @@ The copy/move constructor is implicitly defined even if the implementation elided its odr-use\iref{term.odr.use,class.temporary}. \end{note} -The implicitly-defined\iref{dcl.fct.def.default} -constructor is \keyword{constexpr}. +The implicitly-defined\iref{dcl.fct.def.default} constructor is constexpr. \pnum Before the defaulted copy/move constructor for a class is @@ -1742,9 +1755,10 @@ \end{note} \pnum -If the class definition does not explicitly declare a copy assignment operator, +If the class does not have a user-declared copy assignment operator +and the class is not an anonymous union, one is declared \defnx{implicitly}{assignment operator!copy!implicitly declared}. -If the class definition declares a move +If the class has a user-declared move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defaulted\iref{dcl.fct.def}. @@ -1796,6 +1810,9 @@ move assignment operator, one will be implicitly declared as defaulted if and only if \begin{itemize} +\item +\tcode{X} is not an anonymous union, + \item \tcode{X} does not have a user-declared copy constructor, @@ -1913,7 +1930,7 @@ \defnx{non-trivial}{assignment operator!copy!non-trivial}. \pnum -An implicitly-defined\iref{dcl.fct.def.default} copy/move assignment operator is \keyword{constexpr}. +An implicitly-defined\iref{dcl.fct.def.default} copy/move assignment operator is constexpr. \pnum Before the defaulted copy/move assignment operator for a class is @@ -2030,7 +2047,8 @@ \indextext{generated destructor|see{destructor, default}}% \indextext{destructor!default}% If a class has no user-declared -prospective destructor, +prospective destructor +and the class is not an anonymous union, a prospective destructor is implicitly declared as defaulted\iref{dcl.fct.def}. An implicitly-declared prospective destructor is an @@ -2043,7 +2061,8 @@ \end{codeblock} \pnum -At the end of the definition of a class, +At the end of the definition of a class +other than an anonymous union, overload resolution is performed among the prospective destructors declared in that class with an empty argument list @@ -2316,7 +2335,7 @@ \pnum Once a destructor is invoked for an object, the object's lifetime ends; -the behavior is undefined if the destructor is invoked +the behavior is undefined\ubdef{class.dtor.no.longer.exists} if the destructor is invoked for an object whose lifetime has ended\iref{basic.life}. \begin{example} If the destructor for an object with automatic storage duration is explicitly invoked, @@ -2750,7 +2769,7 @@ its declaration in the class definition can specify a \grammarterm{brace-or-equal-initializer} in which every \grammarterm{initializer-clause} that is an \grammarterm{assignment-expression} -is a constant expression\iref{expr.const}. +is a constant expression\iref{expr.const.const}. The member shall still be defined in a namespace scope if it is odr-used\iref{term.odr.use} in the program and the namespace scope definition shall not contain an \grammarterm{initializer}. @@ -3266,13 +3285,16 @@ an \defnx{anonymous union member}{member!anonymous union} if it is a non-static data member or an \defnx{anonymous union variable}{variable!anonymous union} otherwise. +Each object of such an unnamed type shall be such an unnamed object. \indextext{access control!anonymous \tcode{union}}% \indextext{restriction!anonymous \tcode{union}}% Each \grammarterm{member-declaration} in the \grammarterm{member-specification} of an anonymous union shall define one or more public non-static data members, be an \grammarterm{empty-declaration}, or be a \grammarterm{static_assert-declaration}. -Nested types, anonymous unions, and functions +Nested types +(including closure types\iref{expr.prim.lambda.closure} and anonymous unions) +and functions shall not be declared within an anonymous union. The names of the members of an anonymous union are bound in the scope inhabited by the union declaration. @@ -3984,7 +4006,7 @@ \indextext{definition!virtual function}% A virtual function declared in a class shall be defined, or declared pure\iref{class.abstract} in that class, or both; no diagnostic is -required\iref{basic.def.odr}. +required\iref{basic.def.odr}\ifndrdef{class.virtual.pure.or.defined}. \indextext{friend!\tcode{virtual} and}% \pnum @@ -4099,11 +4121,11 @@ \indextext{function!virtual|)} \pnum -A class with a \keyword{consteval} virtual function that overrides -a virtual function that is not \keyword{consteval} +A class with an immediate virtual function that overrides +a non-immediate virtual function shall have consteval-only type\iref{basic.types.general}. -A \keyword{consteval} virtual function shall not be overridden by -a virtual function that is not \keyword{consteval}. +An immediate virtual function shall not be overridden by +a non-immediate virtual function. \rSec2[class.abstract]{Abstract classes}% @@ -4218,7 +4240,7 @@ \indextext{virtual function call!undefined pure}% the effect of making a virtual call\iref{class.virtual} to a pure virtual function directly or indirectly for the object being created (or -destroyed) from such a constructor (or destructor) is undefined.% +destroyed) from such a constructor (or destructor) is undefined\ubdef{class.abstract.pure.virtual}.% \indextext{derived class|)} \rSec1[class.access]{Member access control}% @@ -5359,9 +5381,9 @@ Here, \tcode{x.i} -is initialized with 99, +is initialized with \tcode{99}, \tcode{x.f} -is initialized with 88.8, and +is initialized with \tcode{88.8}, and \tcode{complex::complex(double)} is called for the initialization of \tcode{x.c}. @@ -5503,7 +5525,7 @@ The target constructor is selected by overload resolution. Once the target constructor returns, the body of the delegating constructor is executed. If a constructor delegates to itself directly or indirectly, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{class.base.init.delegate.itself}. \begin{example} \begin{codeblock} struct C { @@ -5818,7 +5840,7 @@ \item a postcondition assertion of a destructor\iref{dcl.contract.func}, \end{itemize} -the program has undefined behavior. +the program has undefined behavior\ubdef{class.base.init.mem.fun}. \begin{example} \begin{codeblock} class A { @@ -6015,9 +6037,10 @@ \indextext{destruction!member access}% For an object with a non-trivial constructor, referring to any non-static member or base class of the object before the constructor begins execution results in -undefined behavior. For an object with a non-trivial destructor, referring to +undefined behavior\ubdef{class.cdtor.before.ctor}. +For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor finishes -execution results in undefined behavior. +execution results in undefined behavior\ubdef{class.cdtor.after.dtor}. \begin{example} \begin{codeblock} struct X { int i; }; @@ -6102,7 +6125,7 @@ indirectly derive from \tcode{B} shall have started and the destruction of these classes shall not have -completed, otherwise the conversion results in undefined behavior. +completed, otherwise the conversion results in undefined behavior\ubdef{class.cdtor.convert.pointer}. To form a pointer to (or access the value of) a direct non-static member of an object \tcode{obj}, @@ -6110,7 +6133,7 @@ \tcode{obj} shall have started and its destruction shall not have completed, otherwise the computation of the pointer value (or accessing the member -value) results in undefined behavior. +value) results in undefined behavior\ubdef{class.cdtor.form.pointer}. \begin{example} \begin{codeblock} struct A { }; @@ -6154,7 +6177,7 @@ and the object expression refers to the complete object of \tcode{x} or one of that object's base class subobjects but not \tcode{x} or one of its base class subobjects, the behavior -is undefined. +is undefined\ubdef{class.cdtor.virtual.not.x}. \begin{example} \begin{codeblock} struct V { @@ -6211,7 +6234,7 @@ \tcode{typeid} refers to the object under construction or destruction and the static type of the operand is neither the constructor or destructor's class nor one of its -bases, the behavior is undefined. +bases, the behavior is undefined\ubdef{class.cdtor.typeid}. \pnum \indextext{construction!dynamic cast and}% @@ -6236,7 +6259,7 @@ the operand is not a pointer to or object of the constructor or destructor's own class or one of its bases, the \keyword{dynamic_cast} -results in undefined behavior. +results in undefined behavior\ubdef{class.cdtor.dynamic.cast}. \begin{example} \begin{codeblock} struct V { @@ -6341,7 +6364,7 @@ \end{itemize} Copy elision is not permitted where an expression is evaluated in a context -requiring a constant expression\iref{expr.const} +requiring a constant expression\iref{expr.const.const} and in constant initialization\iref{basic.start.static}. \begin{note} It is possible that copy elision is performed @@ -6377,7 +6400,7 @@ } constexpr A a; // well-formed, \tcode{a.p} points to \tcode{a} -constexpr A b = g(); // error: \tcode{b.p} would be dangling\iref{expr.const} +constexpr A b = g(); // error: \tcode{b.p} would be dangling\iref{expr.const.const} void h() { A c = g(); // well-formed, \tcode{c.p} can point to \tcode{c} or be dangling diff --git a/source/compatibility.tex b/source/compatibility.tex index a0ae25da56..e3512400d3 100644 --- a/source/compatibility.tex +++ b/source/compatibility.tex @@ -222,6 +222,23 @@ type deductions from \#2 and \#3 both succeed. \end{example} +\rSec2[diff.cpp23.cpp]{\ref{cpp}: preprocessing directives} + +\diffref{cpp.replace.general} +\change +Additional restrictions on macro names. +\rationale +Avoid hard to diagnose or non-portable constructs. +\effect +Keywords, +names of identifiers with special meaning\iref{lex.name}, +and (unless otherwise specified) \grammarterm{attribute-token}{s} +specified in \ref{dcl.attr} +may not be used as macro names. +For example, valid \CppXXIII{} code that +defines \tcode{post} or \tcode{pre} as macros +is invalid in this revision of \Cpp{}. + \rSec2[diff.cpp23.library]{\ref{library}: library introduction} \diffref{headers} @@ -258,32 +275,6 @@ Valid \CppXXIII{} code that calls \tcode{realloc} with a non-null pointer and a size of zero is erroneous and may change behavior. -\rSec2[diff.cpp23.containers]{\ref{containers}: containers library} - -\diffref{span.overview} -\change -\tcode{span} is constructible from \tcode{initializer_list}. -\rationale -Permit passing a braced initializer list to a function taking \tcode{span}. -\effect -Valid \CppXXIII{} code that relies on the lack of this constructor -may refuse to compile, or change behavior in this revision of \Cpp{}. -\begin{example} -\begin{codeblock} -void one(pair); // \#1 -void one(span); // \#2 -void t1() { one({1, 2}); } // ambiguous between \#1 and \#2; previously called \#1 - -void two(span); -void t2() { two({{1, 2}}); } // ill-formed; previously well-formed - -void *a[10]; -int x = span{a, 0}.size(); // \tcode{x} is \tcode{2}; previously \tcode{0} -any b[10]; -int y = span{b, b + 10}.size(); // \tcode{y} is \tcode{2}; previously \tcode{10} -\end{codeblock} -\end{example} - \rSec2[diff.cpp23.strings]{\ref{strings}: strings library} \diffref{string.conversions} @@ -2916,11 +2907,10 @@ \diffref{basic.types} \change -C allows ``compatible types'' in several places, \Cpp{} does not.\\ +C allows mixing between ``compatible types'' in several places where \Cpp{} does not.\\ For example, -otherwise-identical \keyword{struct} types with different tag names -are ``compatible'' in C but are distinctly different types -in \Cpp{}. +enumerated types are ``compatible'' with their underlying types in C but, in \Cpp{}, +enumerations are types distinct from their underlying types. \rationale Stricter type checking is essential for \Cpp{}. \effect @@ -2928,9 +2918,8 @@ \difficulty Semantic transformation. The ``typesafe linkage'' mechanism will find many, but not all, -of such problems. -Those problems not found by typesafe linkage will continue to -function properly, +such problems. +Some cases are allowed by \Cpp{} according to the ``layout compatibility rules'' of this document. \howwide @@ -3078,8 +3067,8 @@ \begin{codeblock} int arr1[5]; int arr2[5]; -int same = arr1 == arr2; // valid C, ill-formed C++ -int idem = arr1 == +arr2; // valid in both C and C++ +int same = arr1 == arr2; // valid C, ill-formed \Cpp{} +int idem = arr1 == +arr2; // valid \Cpp{}, constraint violation in C \end{codeblock} \end{example} \howwide @@ -3449,14 +3438,15 @@ \diffref{dcl.enum} \change -In \Cpp{}, the type of an enumerator is its enumeration. In C, the type of an enumerator is \keyword{int}. +In \Cpp{}, the type of an enumerator is its enumeration. In C, the type of an enumerator is an integer type. \begin{example} \begin{codeblock} enum e { A }; -sizeof(A) == sizeof(int) // in C -sizeof(A) == sizeof(e) // in \Cpp{} -/* and @sizeof(int)@ is not necessarily equal to @sizeof(e)@ */ +void f() { + auto x = A; + int *p = &x; // valid C, invalid \Cpp{} +} \end{codeblock} \end{example} @@ -3468,10 +3458,6 @@ Semantic transformation. \howwide Seldom. -The only time this affects existing C code is when the size of an -enumerator is taken. -Taking the size of an enumerator is not a -common C coding practice. \diffref{dcl.align} \change diff --git a/source/concepts.tex b/source/concepts.tex index 3cbd110a4a..d1e15a6e1a 100644 --- a/source/concepts.tex +++ b/source/concepts.tex @@ -1033,7 +1033,7 @@ \item \tcode{\exposid{CONVERT_TO_LVALUE}(u1)} equals \tcode{\exposid{CONVERT_TO_LVALUE}(u2)} -if and only if \tcode{u1} equals \tcode{u2} +if and only if \tcode{u1} equals \tcode{u2}. \end{itemize} \rSec2[concept.equalitycomparable]{Concept \cname{equality_comparable}} diff --git a/source/containers.tex b/source/containers.tex index 771e3f1a06..38adf12f61 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -7117,7 +7117,7 @@ constexpr size_type remove(const T& value); template constexpr size_type remove_if(Predicate pred); - size_type unique(); + constexpr size_type unique(); template constexpr size_type unique(BinaryPredicate binary_pred); constexpr void merge(forward_list& x); @@ -7980,9 +7980,15 @@ The maximum hard limit shall be no larger than \tcode{std::allocator_traits::max_size()}. \item -If user-specified limits are not within hard limits, or +If user-specified limits passed to +a \tcode{hive} constructor or \tcode{reshape} +are not within hard limits, or if the specified minimum limit is greater than the specified maximum limit, -the behavior is undefined. +the behavior is erroneous and the effects are +\impldef{effects of invalid \tcode{hive} limits}. +\begin{tailnote} +This condition can be checked using \tcode{is_within_hard_limits}. +\end{tailnote} \item An element block is said to be \defnx{within the bounds}{element block!bounds} of a pair of minimum/maximum limits @@ -8089,6 +8095,7 @@ constexpr hive_limits block_capacity_limits() const noexcept; static constexpr hive_limits block_capacity_default_limits() noexcept; static constexpr hive_limits block_capacity_hard_limits() noexcept; + static constexpr bool is_within_hard_limits(hive_limits) noexcept; void reshape(hive_limits block_limits); // \ref{hive.modifiers}, modifiers @@ -8478,7 +8485,9 @@ \pnum \throws -\tcode{length_error} if \tcode{n > max_size()}, +\tcode{length_error} if +satisfying the postcondition +would cause \tcode{capacity()} to exceed \tcode{max_size()}, as well as any exceptions thrown by the allocator. \pnum @@ -8604,6 +8613,20 @@ Constant. \end{itemdescr} +\indexlibrarymember{is_within_hard_limits}{hive}% +\begin{itemdecl} +static constexpr bool is_within_hard_limits(hive_limits lim) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{hl} be \tcode{block_capacity_hard_limits()}. + +\pnum +\returns +\tcode{hl.min <= lim.min \&\& lim.min <= lim.max \&\& lim.max <= hl.max}. +\end{itemdescr} + \indexlibrarymember{reshape}{hive}% \begin{itemdecl} void reshape(hive_limits block_limits); @@ -8847,7 +8870,8 @@ \pnum \throws \tcode{length_error} if any of \tcode{x}'s active blocks -are not within the bounds of \exposid{current-limits}. +are not within the bounds of \exposid{current-limits}, +as well as any exceptions thrown by the allocator. \pnum \complexity @@ -8931,7 +8955,7 @@ References, pointers, and iterators referring to elements in \tcode{*this}, as well as the past-the-end iterator, may be invalidated. \begin{note} -Not required to be stable\ref{algorithm.stable}. +Not required to be stable\iref{algorithm.stable}. \end{note} \end{itemdescr} @@ -9074,7 +9098,7 @@ \pnum The types \tcode{iterator} and \tcode{const_iterator} meet -the constexpr iterator requirements\ref{iterator.requirements.general}. +the constexpr iterator requirements\iref{iterator.requirements.general}. \begin{codeblock} namespace std { @@ -9235,7 +9259,7 @@ \begin{itemdescr} \pnum \effects -Constructs an empty list, using the specified allocator. +Constructs an empty \tcode{list}, using the specified allocator. \pnum \complexity @@ -10651,6 +10675,18 @@ \tcode{*this}. \end{itemdescr} +\indexlibrarymember{operator bool}{vector::reference}% +\begin{itemdecl} +constexpr reference::operator bool() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if the value of the bit referred to by \tcode{*this} is one, +\tcode{false} otherwise. +\end{itemdescr} + \indexlibrarymember{flip}{vector::reference}% \begin{itemdecl} constexpr void reference::flip() noexcept; @@ -10735,7 +10771,7 @@ parse(ParseContext& ctx); template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(const T& ref, FormatContext& ctx) const; }; } @@ -10756,7 +10792,7 @@ \indexlibrarymember{format}{formatter}% \begin{itemdecl} template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(const T& ref, FormatContext& ctx) const; \end{itemdecl} @@ -10953,11 +10989,9 @@ constexpr void pop_back(); template - constexpr pointer try_emplace_back(Args&&... args); - constexpr pointer try_push_back(const T& x); - constexpr pointer try_push_back(T&& x); - template<@\exposconcept{container-compatible-range}@ R> - constexpr ranges::borrowed_iterator_t try_append_range(R&& rg); + constexpr optional try_emplace_back(Args&&... args); + constexpr optional try_push_back(const T& x); + constexpr optional try_push_back(T&& x); template constexpr reference unchecked_emplace_back(Args&&... args); @@ -10986,8 +11020,13 @@ friend constexpr bool operator==(const inplace_vector& x, const inplace_vector& y); - friend constexpr @\exposid{synth-three-way-result}@ - operator<=>(const inplace_vector& x, const inplace_vector& y); + friend constexpr auto + operator<=>(const inplace_vector& x, const inplace_vector& y) + requires requires (const T t) { @\exposid{synth-three-way}@(t, t); } + { + return lexicographical_compare_three_way(x.begin(), x.end(), y.begin(), y.end(), + @\exposid{synth-three-way}@); + } friend constexpr void swap(inplace_vector& x, inplace_vector& y) noexcept(N == 0 || (is_nothrow_swappable_v && is_nothrow_move_constructible_v)) @@ -11262,9 +11301,9 @@ \indexlibrarymember{try_push_back}{inplace_vector}% \begin{itemdecl} template - constexpr pointer try_emplace_back(Args&&... args); -constexpr pointer try_push_back(const T& x); -constexpr pointer try_push_back(T&& x); + constexpr optional try_emplace_back(Args&&... args); +constexpr optional try_push_back(const T& x); +constexpr optional try_push_back(T&& x); \end{itemdecl} \begin{itemdescr} @@ -11290,8 +11329,8 @@ \pnum \returns -\keyword{nullptr} if \tcode{size() == capacity()} is \tcode{true}, -otherwise \tcode{addressof(back())}. +\keyword{nullopt} if \tcode{size() == capacity()} is \tcode{true}, +otherwise \tcode{optional(in_place, back())}. \pnum \throws @@ -11306,45 +11345,6 @@ If an exception is thrown, there are no effects on \tcode{*this}. \end{itemdescr} -\indexlibrarymember{try_append_range}{inplace_vector}% -\begin{itemdecl} -template<@\exposconcept{container-compatible-range}@ R> - constexpr ranges::borrowed_iterator_t try_append_range(R&& rg); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{value_type} is \oldconcept{EmplaceConstructible} -into \tcode{inplace_vector} from\\\tcode{*ranges::begin(rg)}. - -\pnum -\effects -Appends copies of initial elements in \tcode{rg} before \tcode{end()}, -until all elements are inserted or \tcode{size() == capacity()} is \tcode{true}. -Each iterator in the range \tcode{rg} is dereferenced at most once. - -\pnum -\returns -The first iterator in the range -\countedrange{ranges::begin(rg)}{n} -that was not inserted into \tcode{*this}, -where \tcode{n} is the number of elements in \tcode{rg}. - -\pnum -\complexity -Linear in the number of elements inserted. - -\pnum -\remarks -Let $n$ be the value of \tcode{size()} prior to this call. -If an exception is thrown after the insertion of $k$ elements, then -\tcode{size()} equals $n + k$, -elements in the range \tcode{begin() + \range{0}{$n$}} are not modified, and -elements in the range \tcode{begin() + \range{$n$}{$n + k$}} correspond to -the inserted elements. -\end{itemdescr} - \indexlibrarymember{unchecked_emplace_back}{inplace_vector}% \begin{itemdecl} template @@ -11405,6 +11405,26 @@ equal to the number of elements after the erased elements. \end{itemdescr} +\indexlibrarymember{swap}{inplace_vector}% +\begin{itemdecl} +constexpr void swap(inplace_vector& x) noexcept( + N == 0 || (is_nothrow_swappable_v && is_nothrow_move_constructible_v)); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{T} meets the \oldconcept{MoveConstructible} requirements. +Let $M$ be \tcode{min(size(), x.size())}. +For each non-negative integer $n < M$, +\tcode{(*this)[$n$]} is swappable +with \tcode{x[$n$]}\iref{swappable.requirements}. + +\pnum +\effects +Exchanges the contents of \tcode{*this} and \tcode{x}. +\end{itemdescr} + \rSec3[inplace.vector.erasure]{Erasure} \indexlibrarymember{erase}{inplace_vector}% @@ -11459,24 +11479,25 @@ template using @\placeholder{iter-value-type}@ = iterator_traits::value_type; // \expos template - using @\placeholder{iter-key-type}@ = remove_const_t< + using @\placeholder{iter-key-type}@ = remove_cvref_t< tuple_element_t<0, @\exposid{iter-value-type}@>>; // \expos template - using @\placeholder{iter-mapped-type}@ = - tuple_element_t<1, @\exposid{iter-value-type}@>; // \expos + using @\placeholder{iter-mapped-type}@ = remove_cvref_t< + tuple_element_t<1, @\exposid{iter-value-type}@>>; // \expos template using @\placeholder{iter-to-alloc-type}@ = pair< - const tuple_element_t<0, @\exposid{iter-value-type}@>, - tuple_element_t<1, @\exposid{iter-value-type}@>>; // \expos + const @\exposid{iter-key-type}@, + @\exposid{iter-mapped-type}@>; // \expos template using @\exposid{range-key-type}@ = - remove_const_t::first_type>; // \expos + remove_cvref_t>>; // \expos template - using @\exposid{range-mapped-type}@ = ranges::range_value_t::second_type; // \expos + using @\exposid{range-mapped-type}@ = + remove_cvref_t>>; // \expos template using @\exposid{range-to-alloc-type}@ = - pair::first_type, - typename ranges::range_value_t::second_type>; // \expos + pair, + @\exposid{range-mapped-type}@>; // \expos \end{codeblock} \rSec2[associative.map.syn]{Header \tcode{} synopsis} @@ -17619,7 +17640,7 @@ \pnum \effects Equivalent to \tcode{flat_map(sorted_unique, key_cont, mapped_cont)} and -\tcode{flat_map(sorted_unique, key_cont, \linebreak{}mapped_cont, comp)}, respectively, +\tcode{flat_map(sorted_unique, key_cont, mapped_cont, comp)}, respectively, except that \tcode{\exposid{c}.keys} and \tcode{\exposid{c}.values} are constructed with uses-allocator construction\iref{allocator.uses.construction}. @@ -18774,11 +18795,11 @@ \begin{itemdecl} template constexpr flat_multimap(sorted_equivalent_t, const key_container_type& key_cont, - const mapped_container_type& mapped_cont, const Alloc& a); + const mapped_container_type& mapped_cont, const Alloc& a); template constexpr flat_multimap(sorted_equivalent_t, const key_container_type& key_cont, - const mapped_container_type& mapped_cont, const key_compare& comp, - const Alloc& a); + const mapped_container_type& mapped_cont, const key_compare& comp, + const Alloc& a); \end{itemdecl} \begin{itemdescr} @@ -19494,8 +19515,8 @@ \effects Adds elements to \exposid{c} as if by: \begin{codeblock} -ranges::for_each(rg, [&](auto&& e) { - @\exposid{c}@.insert(@\exposid{c}@.end(), std::forward(e)); +ranges::for_each(rg, [&](value_type e) { + @\exposid{c}@.insert(@\exposid{c}@.end(), std::move(e)); }); \end{codeblock} Then, @@ -20182,8 +20203,8 @@ \effects Adds elements to \exposid{c} as if by: \begin{codeblock} -ranges::for_each(rg, [&](auto&& e) { - @\exposid{c}@.insert(@\exposid{c}@.end(), std::forward(e)); +ranges::for_each(rg, [&](value_type e) { + @\exposid{c}@.insert(@\exposid{c}@.end(), std::move(e)); }); \end{codeblock} Then, sorts the range of newly inserted elements with respect to \exposid{compare}, @@ -20308,7 +20329,7 @@ \tcode{queue}, \tcode{priority_queue}, and \tcode{stack}, -the library provides the following formatter specialization +the library provides the following constexpr-enabled formatter specialization where \tcode{\placeholder{adaptor-type}} is the name of the template: \indexlibraryglobal{formatter}% @@ -20330,7 +20351,7 @@ parse(ParseContext& ctx); template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\exposid{maybe-const-adaptor}@& r, FormatContext& ctx) const; }; } @@ -20352,7 +20373,7 @@ \indexlibrarymember{format}{formatter}% \begin{itemdecl} template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\exposid{maybe-const-adaptor}@& r, FormatContext& ctx) const; \end{itemdecl} @@ -20381,8 +20402,6 @@ \indexheader{span}% \begin{codeblock} -#include // see \ref{initializer.list.syn} - // mostly freestanding namespace std { // constants @@ -20392,10 +20411,7 @@ concept @\defexposconcept{integral-constant-like}@ = // \expos is_integral_v> && !is_same_v> && - @\libconcept{convertible_to}@ && - @\libconcept{equality_comparable_with}@ && - bool_constant::value && - bool_constant(T()) == T::value>::value; + @\exposconcept{constexpr-wrapper-like}@; template constexpr size_t @\defexposconcept{maybe-static-ext}@ = dynamic_extent; // \expos @@ -20469,7 +20485,6 @@ constexpr span(const array& arr) noexcept; template constexpr explicit(extent != dynamic_extent) span(R&& r); - constexpr explicit(extent != dynamic_extent) span(std::initializer_list il); constexpr span(const span& other) noexcept = default; template constexpr explicit(@\seebelow@) span(const span& s) noexcept; @@ -20730,27 +20745,6 @@ What and when \tcode{ranges::data(r)} and \tcode{ranges::size(r)} throw. \end{itemdescr} -\indexlibraryctor{span}% -\begin{itemdecl} -constexpr explicit(extent != dynamic_extent) span(std::initializer_list il); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{is_const_v} is \tcode{true}. - -\pnum -\hardexpects -If \tcode{extent} is not equal to \tcode{dynamic_extent}, -then \tcode{il.size() == extent} is \tcode{true}. - -\pnum -\effects -Initializes \exposid{data_} with \tcode{il.data()} and -\exposid{size_} with \tcode{il.size()}. -\end{itemdescr} - \indexlibraryctor{span}% \begin{itemdecl} constexpr span(const span& other) noexcept = default; @@ -21280,7 +21274,9 @@ // \ref{mdspan.sub}, \tcode{submdspan} creation template - struct strided_slice; + struct extent_slice; + template> + struct range_slice; template struct submdspan_mapping_result; @@ -21289,12 +21285,12 @@ inline constexpr full_extent_t full_extent{}; template - constexpr auto submdspan_extents(const extents&, SliceSpecifiers...); + constexpr auto subextents(const extents&, SliceSpecifiers...); // \ref{mdspan.sub.canonical}, \tcode{submdspan} slice canonicalization - template - constexpr auto submdspan_canonicalize_slices(const extents& src, - Slices... slices); + template + constexpr auto canonical_slices(const extents& src, + SliceSpecifiers... slices); // \ref{mdspan.sub.sub}, \tcode{submdspan} function template template} is an integral type other than \tcode{bool}, then equivalent to \tcode{return i;}, \item -otherwise, equivalent to \tcode{return static_cast(i);}. +otherwise, equivalent to \tcode{return static_cast(std::forward(\brk{}i));}. \end{itemize} \begin{note} This function will always return an integral type other than \tcode{bool}. @@ -22032,7 +22028,7 @@ \begin{itemdescr} \pnum \result -A constant expression\iref{expr.const} of type \tcode{bool}. +A constant expression\iref{expr.const.const} of type \tcode{bool}. \pnum \returns @@ -22052,7 +22048,7 @@ \begin{itemdescr} \pnum \result -A constant expression\iref{expr.const} of type \tcode{bool}. +A constant expression\iref{expr.const.const} of type \tcode{bool}. \pnum \returns @@ -22072,7 +22068,7 @@ \begin{itemdescr} \pnum \result -A constant expression\iref{expr.const} of type \tcode{bool}. +A constant expression\iref{expr.const.const} of type \tcode{bool}. \pnum \returns @@ -22203,7 +22199,7 @@ -> @\seebelow@; template - friend constexpr auto submdspan_mapping( + friend constexpr auto @\libmember{submdspan_mapping}{layout_left::mapping}@( const mapping& src, SliceSpecifiers... slices) { return src.@\exposid{submdspan-mapping-impl}@(slices...); } @@ -22423,7 +22419,7 @@ is \tcode{true}. Equivalent to: \begin{codeblock} -return ((static_cast(i) * stride(P)) + ... + 0); +return ((static_cast(std::move(i)) * stride(P)) + ... + 0); \end{codeblock} \end{itemdescr} @@ -22532,7 +22528,7 @@ -> @\seebelow@; template - friend constexpr auto submdspan_mapping( + friend constexpr auto @\libmember{submdspan_mapping}{layout_right::mapping}@( const mapping& src, SliceSpecifiers... slices) { return src.@\exposid{submdspan-mapping-impl}@(slices...); } @@ -22756,7 +22752,7 @@ \end{codeblock} is \tcode{true}. Equivalent to: \begin{codeblock} -return ((static_cast(i) * stride(P)) + ... + 0); +return ((static_cast(std::move(i)) * stride(P)) + ... + 0); \end{codeblock} \end{itemdescr} @@ -22863,7 +22859,7 @@ -> @\seebelow@; template - friend constexpr auto submdspan_mapping( + friend constexpr auto @\libmember{submdspan_mapping}{layout_stride::mapping}@( const mapping& src, SliceSpecifiers... slices) { return src.@\exposid{submdspan-mapping-impl}@(slices...); } @@ -23120,7 +23116,7 @@ is \tcode{true}. Equivalent to: \begin{codeblock} -return ((static_cast(i) * stride(P)) + ... + 0); +return ((static_cast(std::move(i)) * stride(P)) + ... + 0); \end{codeblock} \end{itemdescr} @@ -23249,7 +23245,7 @@ // \ref{mdspan.layout.leftpad.obs}, observers constexpr const extents_type& extents() const noexcept { return @\exposid{extents_}@; } - constexpr array strides() const noexcept; + constexpr array strides() const noexcept; constexpr index_type required_span_size() const noexcept; template @@ -23272,13 +23268,13 @@ // \ref{mdspan.layout.leftpad.expo}, exposition-only members index_type @\exposid{stride-1}@ = @\exposid{static-padding-stride}@; // \expos extents_type @\exposid{extents_}@{}; // \expos - // \ref{mdspan.sub.map}, submdspan mapping specialization + // \ref{mdspan.sub.map}, \tcode{submdspan} mapping specialization template constexpr auto @\exposid{submdspan-mapping-impl}@(SliceSpecifiers...) const // \expos -> @\seebelow@; template - friend constexpr auto submdspan_mapping(const mapping& src, SliceSpecifiers... slices) { + friend constexpr auto @\libmember{submdspan_mapping}{layout_left_padded::mapping}@(const mapping& src, SliceSpecifiers... slices) { return src.@\exposid{submdspan-mapping-impl}@(slices...); } }; @@ -23424,7 +23420,7 @@ direct-non-list-initializes \exposid{stride-1} \begin{itemize} \item -with \tcode{ext.extent(0)} if padding_value is \tcode{dynamic_extent}, +with \tcode{ext.extent(0)} if \tcode{padding_value} is \tcode{dynamic_extent}, \item otherwise with \tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(padding_value, ext.extent(0))}. @@ -23435,10 +23431,14 @@ \indexlibraryctor{layout_left_padded::mapping}% \begin{itemdecl} template -constexpr mapping(const extents_type& ext, OtherIndexType pad); +constexpr mapping(const extents_type& ext, OtherIndexType padding); \end{itemdecl} \begin{itemdescr} +\pnum +Let \tcode{pad} be +\tcode{extents_type::\exposid{index-cast}(std::move(padding))}. + \pnum \constraints \begin{itemize} @@ -23454,7 +23454,7 @@ \item \tcode{pad} is representable as a value of type \tcode{index_type}. \item -\tcode{extents_type::\exposid{index-cast}(pad)} is greater than zero. +\tcode{pad} is greater than zero. \item If \exposid{rank_} is greater than one, then \tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(pad, ext.extent(0))} @@ -23468,7 +23468,7 @@ is representable as a value of type \tcode{index_type}. \item If \tcode{padding_value} is not equal to \tcode{dynamic_extent}, -\tcode{padding_value} equals \tcode{extents_type::\exposid{in\-dex-cast}(pad)}. +\tcode{padding_value} equals \tcode{pad}. \end{itemize} \pnum @@ -23723,7 +23723,7 @@ \begin{itemdecl} template -constexpr size_t operator()(Indices... idxs) const noexcept; +constexpr index_type operator()(Indices... idxs) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -23745,7 +23745,7 @@ \pnum \returns -\tcode{((static_cast(idxs) * stride(P_rank)) + ... + 0)}. +\tcode{((static_cast(std::move(idxs)) * stride(P_rank)) + ... + 0)}. \end{itemdescr} \begin{itemdecl} @@ -23881,8 +23881,8 @@ constexpr mapping& operator=(const mapping&) noexcept = default; // \ref{mdspan.layout.rightpad.obs}, observers - constexpr const extents_type& extents() const noexcept { return extents_; } - constexpr array strides() const noexcept; + constexpr const extents_type& extents() const noexcept { return @\exposid{extents_}@; } + constexpr array strides() const noexcept; constexpr index_type required_span_size() const noexcept; @@ -23907,13 +23907,13 @@ index_type @\exposid{stride-rm2}@ = @\exposid{static-padding-stride}@; // \expos extents_type @\exposid{extents_}@{}; // \expos - // \ref{mdspan.sub.map}, submdspan mapping specialization + // \ref{mdspan.sub.map}, \tcode{submdspan} mapping specialization template constexpr auto @\exposid{submdspan-mapping-impl}@(SliceSpecifiers...) const // \expos -> @\seebelow@; template - friend constexpr auto submdspan_mapping(const mapping& src, SliceSpecifiers... slices) { + friend constexpr auto @\libmember{submdspan_mapping}{layout_right_padded::mapping}@(const mapping& src, SliceSpecifiers... slices) { return src.@\exposid{submdspan-mapping-impl}@(slices...); } }; @@ -24072,10 +24072,14 @@ \indexlibraryctor{layout_right_padded::mapping}% \begin{itemdecl} template -constexpr mapping(const extents_type& ext, OtherIndexType pad); +constexpr mapping(const extents_type& ext, OtherIndexType padding); \end{itemdecl} \begin{itemdescr} +\pnum +Let \tcode{pad} be +\tcode{extents_type::\exposid{index-cast}(std::move(padding))}. + \pnum \constraints \begin{itemize} @@ -24091,7 +24095,7 @@ \item \tcode{pad} is representable as a value of type \tcode{index_type}. \item -\tcode{extents_type::\exposid{index-cast}(pad)} is greater than zero. +\tcode{pad} is greater than zero. \item If \exposid{rank_} is greater than one, then \tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(pad, ext.extent(\exposid{rank_} - 1))} @@ -24105,7 +24109,7 @@ is representable as a value of type \tcode{index_type}. \item If \tcode{padding_value} is not equal to \tcode{dynamic_extent}, -\tcode{padding_value} equals \tcode{extents_type::\linebreak \exposid{index-cast}(pad)}. +\tcode{padding_value} equals \tcode{pad}. \end{itemize} \pnum @@ -24358,7 +24362,7 @@ \indexlibrarymember{layout_right_padded::mapping}{operator()}% \begin{itemdecl} template -constexpr size_t operator()(Indices... idxs) const noexcept; +constexpr index_type operator()(Indices... idxs) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -24380,7 +24384,7 @@ \pnum \returns -\tcode{((static_cast(idxs) * stride(P_rank)) + ... + 0)}. +\tcode{((static_cast(std::move(idxs)) * stride(P_rank)) + ... + 0)}. \end{itemdescr} \indexlibrarymember{layout_right_padded::mapping}{is_always_exhaustive}% @@ -25033,7 +25037,7 @@ typename MappingType::layout_type>; template - mdspan(const typename AccessorType::data_handle_type&, const MappingType&, + mdspan(typename AccessorType::data_handle_type, const MappingType&, const AccessorType&) -> mdspan; @@ -25124,7 +25128,7 @@ \item \tcode{(is_convertible_v \&\& ...)} is \tcode{true}, \item -\tcode{(is_nothrow_constructible \&\& ...)} is \tcode{true}, +\tcode{(is_nothrow_constructible_v \&\& ...)} is \tcode{true}, \item \tcode{N == rank() || N == rank_dynamic()} is \tcode{true}, \item @@ -25543,11 +25547,17 @@ \item \tcode{is_convertible_v<$S$, IndexType>} is \tcode{true}; \item - $S$ is a specialization of \tcode{strided_slice} and + $S$ is a specialization of \tcode{extent_slice} and \tcode{is_convertible_v<$X$, IndexType>} is \tcode{true} for $X$ denoting \tcode{$S$::offset_type}, \tcode{$S$::extent_type}, and - \tcode{$S$::stride_type}; or + \tcode{$S$::stride_type}; +\item + $S$ is a specialization of \tcode{range_slice} and + \tcode{is_convertible_v<$X$, IndexType>} is \tcode{true} for $X$ denoting type of + \tcode{$S$::first}, + \tcode{$S$::last}, and + \tcode{$S$::stride} members; or \item all of the following hold: \begin{itemize} @@ -25580,7 +25590,7 @@ \item $S$ is a canonical \tcode{submdspan} index type for \tcode{IndexType}; or \item - $S$ is a specialization of \tcode{strided_slice} + $S$ is a specialization of \tcode{extent_slice} where all of the following hold: \begin{itemize} \item @@ -25596,7 +25606,7 @@ \pnum A type \tcode{S} is a \defnadj{collapsing}{slice type} if it is neither \tcode{full_extent_t} nor -a specialization of \tcode{strided_slice}. +a specialization of \tcode{extent_slice}. \begin{note} Each collapsing slice type in \tcode{submdspan_mapping}'s parameter pack of slice specifier types @@ -25607,7 +25617,7 @@ A type \tcode{S} is a \defnadj{unit-stride}{slice type} if \begin{itemize} \item - \tcode{S} is a specialization of \tcode{strided_slice} + \tcode{S} is a specialization of \tcode{extent_slice} where \tcode{S::stride_type} is a specialization of \tcode{constant_wrapper} and \tcode{S::stride_type::value} is equal to 1, or \item @@ -25625,8 +25635,12 @@ \range{$0$}{e.extent($k$)}, if \tcode{S} is \tcode{full_extent_t}; \item - \range{E::index_type(s.offset)}{E::index_type(s.offset + s.extent)}, - if \tcode{S} is a specialization of \tcode{stri\-ded_slice}; otherwise + \range{E::index_type(s.offset)}{E::index_type(s.offset)}, + if \tcode{S} is a specialization of \tcode{extent_slice} and + \tcode{E::index_type(s.extent)} is zero; otherwise +\item + \range{E::index_type(s.offset)}{E::index_type(s.offset + 1 + (s.extent - 1) * s.stride)}, + if \tcode{S} is a specialization of \tcode{extent_slice}; otherwise \item \range{\tcode{E::index_type(s)}}{$\tcode{E::index_type(s)} + 1$} \end{itemize} @@ -25640,19 +25654,33 @@ either $x$ is equal to \tcode{dynamic_extent}; or \begin{itemize} \item - if \tcode{S} is a specialization of \tcode{strided_slice}: + if \tcode{S} is a specialization of \tcode{extent_slice}, then + \begin{itemize} + \item + $o$ is less than or equal to $x$; + \item + $e$ is less than or equal to $x$; + \item + if $e$ is greater than one, + then $t$ is greater than zero, + \item + if $e$ is greater than zero, + then $o + 1 + (e - 1) * t$ is less than or equal to $x$, + \end{itemize} + where \begin{itemize} \item - if \tcode{S::offset_type} is a specialization of \tcode{constant_wrapper}, - then \tcode{S::offset_type::value} is less than or equal to $x$; + $o$ is the value of \tcode{S::offset_type::value} + if \tcode{S::offset_type} is a specialization of \tcode{constant_wrapper} and + \tcode{0} otherwise, \item - if \tcode{S::offset_type} is a specialization of \tcode{constant_wrapper}, - then \tcode{S::extent_type::value} is less than or equal to $x$; and + $e$ is the value of \tcode{S::extent_type::value} + if \tcode{S::extend_type} is a specialization of \tcode{constant_wrapper} and + \tcode{0} otherwise, \item - if both \tcode{S::offset_type} and \tcode{S::extent_type} - are specializations of \tcode{constant_wrapper}, - then \tcode{S::offset_type::value + S::extent_type::value} - is less than or equal to $x$; or + $t$ is the value of \tcode{S::stride_type::value} + if \tcode{S::stride_type} is a specialization of \tcode{constant_wrapper} and + \tcode{1} otherwise; and \end{itemize} \item if $S$ is a specialization of \tcode{constant_wrapper}, @@ -25674,26 +25702,27 @@ contains the \tcode{submdspan} slice range of \tcode{s} for the $k^\text{th}$ extent of \tcode{e}; and \item - if \tcode{S} is a specialization of \tcode{strided_slice}, then: + if \tcode{S} is a specialization of \tcode{extent_slice}, then \begin{itemize} \item \tcode{s.extent} is greater than or equal to zero, and - \item either \tcode{s.extent} equals zero or \tcode{s.stride} is greater than zero. + \item either \tcode{s.extent} is less than two or \tcode{s.stride} is greater than zero. \end{itemize} \end{itemize} -\rSec4[mdspan.sub.strided.slice]{\tcode{strided_slice}} +\rSec4[mdspan.sub.range.slices]{Range slices} \pnum -\tcode{strided_slice} represents a set of +\tcode{extent_slice} and \tcode{range_slice} represent a set of \tcode{extent} regularly spaced integer indices. -The indices start at \tcode{offset}, and +The indices start at \tcode{offset} and \tcode{first}, respectively, and increase by increments of \tcode{stride}. -\indexlibraryglobal{strided_slice}% +\indexlibraryglobal{extent_slice}% +\indexlibraryglobal{range_slice}% \begin{codeblock} namespace std { template - struct strided_slice { + struct extent_slice { using offset_type = OffsetType; using extent_type = ExtentType; using stride_type = StrideType; @@ -25702,21 +25731,31 @@ [[no_unique_address]] extent_type extent{}; [[no_unique_address]] stride_type stride{}; }; + + template> + struct range_slice { + [[no_unique_address]] FirstType first{}; + [[no_unique_address]] LastType last{}; + [[no_unique_address]] StrideType stride{}; + }; } \end{codeblock} \pnum -\tcode{strided_slice} has the data members and special members specified above. -It has no base classes or members other than those specified. +\tcode{extent_slice} and \tcode{range_slice} +have the data members and special members specified above. +They have no base classes or members other than those specified. \pnum \mandates -\tcode{OffsetType}, \tcode{ExtentType}, and \tcode{StrideType} +\tcode{OffsetType}, \tcode{ExtentType}, +\tcode{FirstType}, \tcode{LastType}, and \tcode{StrideType} are signed or unsigned integer types, or model \exposconcept{integral-constant-like}. \begin{note} -\tcode{strided_slice\{.offset = 1, .extent = 10, .stride = 3\}} -indicates the indices \tcode{1}, \tcode{4}, \tcode{7}, and \tcode{10}. +Both \tcode{extent_slice\{.offset = 1, .extent = 4, .stride = 3\}} and +\tcode{range_slice\{.first = 1, .last = 11, .stride = 3\}} +indicate the indices \tcode{1}, \tcode{4}, \tcode{7}, and \tcode{10}. Indices are selected from the half-open interval \range{1}{1 + 10}. \end{note} @@ -25756,14 +25795,26 @@ \begin{itemdecl} template - concept @\defexposconcept{is-strided-slice}@ = @\seebelow;@ + concept @\defexposconcept{is-extent-slice}@ = @\seebelow;@ +\end{itemdecl} + +\begin{itemdescr} +\pnum +The concept \tcode{\exposconcept{is-extent-slice}} +is satisfied and modeled if and only +if \tcode{T} is a specialization of \tcode{extent_slice}. +\end{itemdescr} + +\begin{itemdecl} +template + concept @\defexposconcept{is-range-slice}@ = @\seebelow;@ \end{itemdecl} \begin{itemdescr} \pnum -The concept \tcode{\exposconcept{is-strided-slice}} +The concept \tcode{\exposconcept{is-range-slice}} is satisfied and modeled if and only -if \tcode{T} is a specialization of \tcode{strided_slice}. +if \tcode{T} is a specialization of \tcode{range_slice}. \end{itemdescr} \indexlibraryglobal{\exposid{canonical-index}}% @@ -25796,6 +25847,53 @@ \end{itemize} \end{itemdescr} +\begin{itemdecl} +template + constexpr auto @\exposid{canonical-range-slice}@(OffsetType offset, SpanType span, StrideTypes... strides); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let +\begin{itemize} +\item + \tcode{StrideType} denote + \tcode{constant_wrapper} + if \tcode{StrideTypes} is an empty pack or + \tcode{SpanType} denotes \tcode{constant_wrapper}, otherwise + \tcode{StrideTypes...[0]}; +\item + \tcode{stride} be + \tcode{StrideType()} if \tcode{StrideType} + is a specialization of \tcode{constant_wrapper}, otherwise + \tcode{IndexType(1)} if \tcode{span == 0} is \tcode{true}, otherwise + \tcode{strides...[0]}; +\item + \exposid{extent-value} be \tcode{1 + (span - 1) / stride} + if \tcode{span != 0} is \tcode{true}, and + \tcode{0} otherwise; and +\item + let \tcode{extent} be \tcode{cw} + if both \tcode{SpanType} and \tcode{StrideType} + are specializations of \tcode{constant_wrapper}, and + \tcode{IndexType(\exposid{extent-value})} otherwise. +\end{itemize} + +\pnum +\mandates +\tcode{sizeof...(StrideTypes) <= 1} is \tcode{true}, and +if \tcode{StrideType} is a specialization of \tcode{con\-stant_wrapper}, +then \tcode{StrideType::value > 0} is \tcode{true}. + +\pnum +\expects +\tcode{stride > 0} is \tcode{true}. + +\pnum +\returns +\tcode{extent_slice\{.offset = offset, .extent = extent, .stride = stride\}}. +\end{itemdescr} + \indexlibraryglobal{\exposid{canonical-slice}} \begin{itemdecl} template @@ -25815,42 +25913,37 @@ return static_cast(std::move(s)); } else if constexpr (is_convertible_v) { return @\exposid{canonical-index}@(std::move(s)); -} else if constexpr (@\exposconcept{is-strided-slice}@) { - auto c_extent = @\exposid{canonical-index}@(std::move(s.extent)); - auto c_offset = @\exposid{canonical-index}@(std::move(s.offset)); - if constexpr (is_same_v>) { - return strided_slice{ - .offset = c_offset, - .extent = c_extent, - .stride = cw - }; - } else { - return strided_slice{ - .offset = c_offset, - .extent = c_extent, - .stride = @\exposid{canonical-index}@(std::move(s.stride)) - }; - } +} else if constexpr (@\exposconcept{is-extent-slice}@) { + return extent_slice{ + .offset = @\exposid{canonical-index}@(std::move(s.extent)), + .extent = @\exposid{canonical-index}@(std::move(s.offset)), + .stride = @\exposid{canonical-index}@(std::move(s.stride)) + }; +} else if constexpr (@\exposconcept{is-range-slice}@) { + auto c_first = @\exposid{canonical-index}@(std::move(s.first)); + auto c_last = @\exposid{canonical-index}@(std::move(s.last)); + return @\exposid{canonical-slice-range}@( + c_first, + @\exposid{canonical-index}@(c_last - c_first), + @\exposid{canonical-index}@(std::move(s.stride))); } else { auto [s_first, s_last] = std::move(s); auto c_first = @\exposid{canonical-index}@(std::move(s_first)); auto c_last = @\exposid{canonical-index}@(std::move(s_last)); - return strided_slice{ - .offset = c_first, - .extent = @\exposid{canonical-index}@(c_last - c_first), - .stride = cw - }; + return @\exposid{canonical-slice-range}@( + c_first, + @\exposid{canonical-index}@(c_last - c_first)); } \end{codeblock} \end{itemdescr} \rSec4[mdspan.sub.canonical]{\tcode{submdspan} slice canonicalization} -\indexlibraryglobal{submdspan_canonicalize_slices}% +\indexlibraryglobal{canonical_slices}% \begin{itemdecl} template - constexpr auto submdspan_canonicalize_slices(const extents& src, - SliceSpecifiers... slices); + constexpr auto canonical_slices(const extents& src, + SliceSpecifiers... slices); \end{itemdecl} \begin{itemdescr} @@ -25882,20 +25975,20 @@ \tcode{make_tuple(\exposid{canonical-slice}(slices)...)}. \end{itemdescr} -\rSec4[mdspan.sub.extents]{\tcode{submdspan_extents} function} +\rSec4[mdspan.sub.extents]{\tcode{subextents} function} -\indexlibraryglobal{submdspan_extents}% +\indexlibraryglobal{subextents}% \begin{itemdecl} template - constexpr auto submdspan_extents(const extents& src, - SliceSpecifiers... raw_slices); + constexpr auto subextents(const extents& src, + SliceSpecifiers... raw_slices); \end{itemdecl} \begin{itemdescr} \pnum Let \tcode{slices} be the pack introduced by the following declaration: \begin{codeblock} -auto [...slices] = submdspan_canonicalize_slices(src, raw_slices...); +auto [...slices] = canonical_slices(src, raw_slices...); \end{codeblock} \pnum @@ -25917,7 +26010,7 @@ \pnum \expects For each rank index $k$ of \tcode{src}, -\tcode{slices...[k]} is a valid \tcode{submdspan} slice +\tcode{slices...[$k$]} is a valid \tcode{submdspan} slice for the $k^\text{th}$ extent of \tcode{src}. \pnum @@ -25929,7 +26022,7 @@ \tcode{\placeholder{MAP_RANK}(slices, Extents::rank())}; and \item -for each rank index $k$ of \tcode{Extents} such that +for each rank index $k$ of \tcode{extents} such that the type of \tcode{slices...[$k$]} is not a collapsing slice type, \tcode{SubExt\-ents::static_extent(\placeholder{MAP_RANK}(slices, $k$))} equals the following, where $\Sigma_k$ @@ -25938,20 +26031,13 @@ \begin{itemize} \item \tcode{Extents::static_extent($k$)} - if $\Sigma_k$ denotes the \tcode{full_extent_t}; + if $\Sigma_k$ denotes \tcode{full_extent_t}; otherwise \item - \tcode{0}, - if $\Sigma_k$ is a specialization of \tcode{strided_slice} and - \tcode{$\Sigma_k$::extent_type} denotes \tcode{constant_wrapper}; - otherwise - - \item - \tcode{1 + (($\Sigma_k$::extent_type::value - 1) / $\Sigma_k$::stride_type::value)}, - if $\Sigma_k$ is a specialization of \tcode{strided_slice} whose - \tcode{extent_type} and \tcode{stride_type} - denote specializations of \tcode{constant_wrapper}; + \tcode{$\Sigma_k$::extent_type::value} + if $\Sigma_k$ is a specialization of \tcode{extent_slice} whose + \tcode{extent_type} denotes a specialization of \tcode{constant_wrapper}; \item otherwise, @@ -25969,8 +26055,8 @@ where $\sigma_k$ denotes \tcode{slices...[$k$]}: \begin{itemize} \item - \tcode{$\sigma_k$.extent == 0 ? 0 : 1 + ($\sigma_k$.extent - 1) / $\sigma_k$.stride} - if the type of $\sigma_k$ is a specialization of \tcode{strided_slice}, + \tcode{$\sigma_k$.extent} + if the type of $\sigma_k$ is a specialization of \tcode{extent_slice}, \item otherwise, $U - L$, where \range{$L$}{$U$} is the \tcode{submdspan} slice range @@ -25988,16 +26074,16 @@ \item \tcode{M} denote a layout mapping class; \item - \tcode{IT} denote \tcode{M::extent_type::index_type}; + \tcode{IT} denote \tcode{M::extents_type::index_type}; \item \tcode{m} denote a value of type (possibly const) \tcode{M}; \item - \tcode{M_rank} be equal to \tcode{M::extent_type::rank()}; + \tcode{M_rank} be equal to \tcode{M::extents_type::rank()}; \item \tcode{valid_slices} denote a pack of (possibly const) objects for which \tcode{sizeof...(valid_slices) == M_rank} is \tcode{true} and, for each rank index $i$ of \tcode{m.extents()}, - \tcode{valid_slices...[i]} is a valid \tcode{submdspan} slice + \tcode{valid_slices...[$i$]} is a valid \tcode{submdspan} slice for the $i^\text{th}$ extent of \tcode{m.extents()}; \item \tcode{invalid_slices} denote a pack of objects @@ -26008,11 +26094,12 @@ \item \tcode{IT}, \item \tcode{full_extent_t}, \item a specialization of \tcode{constant_wrapper}, or - \item a specialization of \tcode{strided_slice}. + \item a specialization of \tcode{extent_slice}. \end{itemize} \end{itemize} \pnum +\indexlibraryglobal{submdspan_mapping}% For the purpose of this section, the meaning of \tcode{submdspan_mapping} is established as if by performing argument-dependent lookup only\iref{basic.lookup.argdep}. @@ -26034,7 +26121,7 @@ \begin{itemdescr} \pnum \result -A type SMR that is a specialization of type submdspan_mapping_result for some type SM such that +A type \tcode{SMR} that is a specialization of type \tcode{submdspan_mapping_result} for some type \tcode{SM} such that \begin{itemize} \item \tcode{SM} meets the layout mapping requirements\iref{mdspan.layout.policy.reqmts}, \item \tcode{SM::extents_type} is a specialization of \tcode{extents}, @@ -26048,7 +26135,7 @@ An object \tcode{smr} of type \tcode{SMR} such that \begin{itemize} \item - \tcode{smr.mapping.extents() == submdspan_extents(m.extents(), valid_slices...)} + \tcode{smr.mapping.extents() == subextents(m.extents(), valid_slices...)} is \tcode{true};\newline and \item for each integer pack \tcode{i} @@ -26105,7 +26192,7 @@ \pnum \constraints -\tcode{sizeof...(SpliceSpecifiers)} equals \tcode{extents_type::rank()}. +\tcode{sizeof...(SliceSpecifiers)} equals \tcode{extents_type::rank()}. \pnum \mandates @@ -26121,7 +26208,7 @@ \pnum Let \tcode{sub_ext} be -the result of \tcode{submdspan_extents(extents(), slices...)} and +the result of \tcode{subextents(extents(), slices...)} and let \tcode{SubExtents} be \tcode{decl\-type(sub_ext)}. \pnum @@ -26133,8 +26220,8 @@ \begin{itemize} \item \tcode{stride(k) * s.stride} -if the type of \tcode{s} is a specialization of \tcode{strided_slice} and -\tcode{s.stride < s.ex\-tent} is \tcode{true}, +if the type of \tcode{s} is a specialization of \tcode{extent_slice} and +\tcode{s.extent > 1} is \tcode{true}, where \tcode{s} is \tcode{slices...[$k$]}; \item otherwise, \tcode{stride($k$)}. @@ -26184,14 +26271,14 @@ \begin{itemize} \item for each $k$ in the range \range{0}{SubExtents::rank() - 1}, - \tcode{SpliceSpecifiers...[$k$]} denotes \tcode{full_extent_t}; and + \tcode{SliceSpecifiers...[$k$]} denotes \tcode{full_extent_t}; and \item for $k$ equal to \tcode{SubExtents::rank() - 1}, - \tcode{SpliceSpecifiers...[$k$]} is a unit-stride slice type; + \tcode{SliceSpecifiers...[$k$]} is a unit-stride slice type; \end{itemize} \begin{note} If the above conditions are true, -all \tcode{SpliceSpecifiers...[$k$]} with $k$ larger than \tcode{SubExtents\brk{}::rank\brk{}() - 1} +all \tcode{SliceSpecifiers...[$k$]} with $k$ larger than \tcode{SubExtents\brk{}::rank\brk{}() - 1} are convertible to \tcode{index_type}. \end{note} \item @@ -26202,7 +26289,7 @@ \end{codeblock} if for a value $u$ for which $u+1$ is the smallest value $p$ larger than zero -for which \tcode{SliceSpecifiers...\brk{}[\brk{}p]} is a unit-stride slice type, +for which \tcode{SliceSpecifiers...\brk{}[\brk{}$p$]} is a unit-stride slice type, the following conditions are met: \begin{itemize} \item @@ -26279,7 +26366,7 @@ \end{codeblock} if for a value $u$ for which $\exposid{rank_} - u - 2$ is the largest value $p$ smaller than \tcode{\exposid{rank_} - 1} -for which \tcode{SliceSpecifiers...[p]} is a unit-stride slice type, +for which \tcode{SliceSpecifiers...[$p$]} is a unit-stride slice type, the following conditions are met: \begin{itemize} \item @@ -26288,7 +26375,7 @@ \item for each $k$ in the range \range{\exposid{rank_} - SubExtents::rank() - $u$ + 1}{\exposid{rank_} - $u$ - 1},\newline -\tcode{SliceSpecifiers...[p]} denotes \tcode{full_extent_t}; and +\tcode{SliceSpecifiers...[$p$]} denotes \tcode{full_extent_t}; and \item for $k$ equal to \tcode{\exposid{rank_} - SubExtents::rank() - $u$}, \tcode{SliceSpecifiers...[$k$]} is a unit-stride slice type; @@ -26449,7 +26536,7 @@ \end{codeblock} if for a value $u$ for which \tcode{\exposid{rank_} - $u$ - 2} -is the largest value p smaller than \tcode{\exposid{rank_} - 1} +is the largest value $p$ smaller than \tcode{\exposid{rank_} - 1} for which \tcode{SliceSpecifiers...[$p$]} is a unit-stride slice type, the following conditions are met: \begin{itemize} @@ -26502,7 +26589,7 @@ \pnum Let \tcode{slices} be the pack introduced by the following declaration: \begin{codeblock} -auto [...slices] = submdspan_canonicalize_slices(src, raw_slices...); +auto [...slices] = canonical_slices(src, raw_slices...); \end{codeblock} \pnum diff --git a/source/declarations.tex b/source/declarations.tex index 510def3e41..0bf9b574ea 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -328,7 +328,7 @@ In a \grammarterm{static_assert-declaration}, the \grammarterm{constant-expression} $E$ is contextually converted to \keyword{bool} and -the converted expression shall be a constant expression\iref{expr.const}. +the converted expression shall be a constant expression\iref{expr.const.const}. If the value of the expression $E$ when so converted is \tcode{true} or the expression is evaluated in the context of a template definition, the declaration has no effect and @@ -393,11 +393,11 @@ \begin{codeblock} [] static consteval -> void @\grammarterm{compound-statement}@ () \end{codeblock} -$E$ shall be a constant expression\iref{expr.const}. +$E$ shall be a constant expression\iref{expr.const.const}. \begin{note} The evaluation of the expression corresponding to a \grammarterm{consteval-block-declaration}\iref{lex.phases} -can produce injected declarations as side effects. +can produce injected declarations\iref{expr.const.reflect} as side effects. \end{note} \begin{example} \begin{codeblock} @@ -532,10 +532,10 @@ \grammarterm{storage-class-specifier} appears in a \grammarterm{decl-specifier-seq}, there can be no \tcode{typedef} specifier in the same \grammarterm{decl-specifier-seq} and -the \grammarterm{init-declarator-list} or \grammarterm{member-declarator-list} -of the declaration shall not be -empty (except for an anonymous union declared in a namespace scope\iref{class.union.anon}). The -\grammarterm{storage-class-specifier} applies to the name declared by each +the \grammarterm{init-declarator-list} of the \grammarterm{simple-declaration} or +the \grammarterm{member-declarator-list} of the \grammarterm{member-declaration} +shall not be empty (except for an anonymous union declared in a namespace scope\iref{class.union.anon}). +The \grammarterm{storage-class-specifier} applies to the name declared by each \grammarterm{init-declarator} in the list and not to any names declared by other specifiers. \begin{note} @@ -720,7 +720,7 @@ \pnum In an \grammarterm{explicit-specifier}, the \grammarterm{constant-expression}, if supplied, shall be a -contextually converted constant expression of type \tcode{bool}\iref{expr.const}. +contextually converted constant expression of type \tcode{bool}\iref{expr.const.const}. The \grammarterm{explicit-specifier} \keyword{explicit} without a \grammarterm{constant-expression} is equivalent to the \grammarterm{explicit-specifier} \tcode{explicit(true)}. @@ -918,7 +918,7 @@ : x(a), y(x) // OK, definition { square(x); } constexpr pixel small(2); // error: \tcode{square} not defined, so \tcode{small(2)} - // not constant\iref{expr.const} so \keyword{constexpr} not satisfied + // not constant\iref{expr.const.core} so \keyword{constexpr} not satisfied constexpr void square(int &x) { // OK, definition x *= x; @@ -938,7 +938,7 @@ a \defnx{constexpr function}{specifier!\idxcode{constexpr}!function}. \begin{note} A function declared with the \keyword{consteval} specifier -is an immediate function\iref{expr.const}. +is an immediate function\iref{expr.const.imm}. \end{note} A destructor, an allocation function, or a deallocation function shall not be declared with the \keyword{consteval} specifier. @@ -992,7 +992,7 @@ \begin{itemize} \item an invocation of a constexpr function -can appear in a constant expression\iref{expr.const} and +can appear in a constant expression\iref{expr.const.core} and \item copy elision is not performed in a constant expression\iref{class.copy.elision}. \end{itemize} @@ -1026,7 +1026,7 @@ Such an object shall have literal type and shall be initialized. -A \keyword{constexpr} variable shall be constant-initializable\iref{expr.const}. +A \keyword{constexpr} variable shall be constant-initializable\iref{expr.const.init}. A \keyword{constexpr} variable that is an object, as well as any temporary to which a \keyword{constexpr} reference is bound, shall have constant destruction. @@ -1064,7 +1064,7 @@ If the specifier is applied to any declaration of a variable, it shall be applied to the initializing declaration. No diagnostic is required if no \keyword{constinit} declaration -is reachable at the point of the initializing declaration. +is reachable at the point of the initializing declaration\ifndrdef{dcl.constinit.specifier.not.reachable}. \pnum If a variable declared with the \keyword{constinit} specifier has @@ -1123,7 +1123,7 @@ \end{note} \pnum -The inline specifier indicates to +The \keyword{inline} specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. An implementation is not required to perform this inline substitution at @@ -1139,7 +1139,7 @@ is declared inline in one definition domain, an inline declaration of it shall be reachable from the end of every definition domain in which it is declared; -no diagnostic is required. +no diagnostic is required\ifndrdef{dcl.inline.missing.on.definition}. \begin{note} A call to an inline function or a use of an inline variable can be encountered before its definition becomes reachable in a translation unit. @@ -1258,9 +1258,10 @@ There are two \grammarterm{cv-qualifier}{s}, \keyword{const} and \tcode{volatile}. Each \grammarterm{cv-qualifier} shall appear at most once in a \grammarterm{cv-qualifier-seq}. If a \grammarterm{cv-qualifier} appears in a -\grammarterm{decl-specifier-seq}, the \grammarterm{init-declarator-list} -or \grammarterm{member-declarator-list} of -the declaration shall not be empty. +\grammarterm{decl-specifier-seq}, +the \grammarterm{init-declarator-list} of the \grammarterm{simple-declaration} or +the \grammarterm{member-declarator-list} of the \grammarterm{member-declaration} +shall not be empty. \begin{note} \ref{basic.type.qualifier} and \ref{dcl.fct} describe how cv-qualifiers affect object and function types. @@ -1274,7 +1275,7 @@ \pnum \begin{note} Declaring a variable \keyword{const} can affect its linkage\iref{dcl.stc} -and its usability in constant expressions\iref{expr.const}. As +and its usability in constant expressions\iref{expr.const.init}. As described in~\ref{dcl.init}, the definition of an object or subobject of const-qualified type must specify an initializer or be subject to default-initialization. @@ -1295,7 +1296,7 @@ \indextext{const object!undefined change to}% Any attempt to modify\iref{expr.assign,expr.post.incr,expr.pre.incr} a const object\iref{basic.type.qualifier} during its -lifetime\iref{basic.life} results in undefined behavior. +lifetime\iref{basic.life} results in undefined behavior\ubdef{dcl.type.cv.modify.const.obj}. \begin{example} \begin{codeblock} const int ci = 3; // cv-qualified (initialized as required) @@ -1339,7 +1340,7 @@ \impldef{semantics of an access through a volatile glvalue}. If an attempt is made to access an object defined with a volatile-qualified type through the use of a non-volatile glvalue, -the behavior is undefined. +the behavior is undefined\ubdef{dcl.type.cv.access.volatile}. \pnum \indextext{type specifier!\idxcode{volatile}}% @@ -1444,8 +1445,14 @@ if any, shall be non-dependent and the \grammarterm{template-name} or \grammarterm{splice-specifier} shall designate a deducible template. -A \defnadj{deducible}{template} is either a class template or -is an alias template whose \grammarterm{defining-type-id} is of the form +A \defnadj{deducible}{template} is +\begin{itemize} +\item +a class template, +\item +a type template template parameter, or +\item +an alias template \tcode{A} whose \grammarterm{defining-type-id} is of the form \begin{ncsimplebnf} \opt{\keyword{typename}} \opt{nested-name-specifier} \opt{\keyword{template}} simple-template-id @@ -1453,7 +1460,9 @@ where the \grammarterm{nested-name-specifier} (if any) is non-dependent and the \grammarterm{template-name} of the \grammarterm{simple-template-id} -names a deducible template. +names a deducible template +other than a type template template parameter of \tcode{A}. +\end{itemize} \begin{note} An injected-class-name is never interpreted as a \grammarterm{template-name} in contexts where class template argument deduction would be performed\iref{temp.local}. @@ -1537,11 +1546,11 @@ \pnum The \grammarterm{typedef-name} $P$ in a \grammarterm{pack-index-specifier} -shall denote a pack. +shall be an \grammarterm{identifier} that denotes a pack. \pnum The \grammarterm{constant-expression} shall be -a converted constant expression\iref{expr.const} of type \tcode{std::size_t} +a converted constant expression\iref{expr.const.const} of type \tcode{std::size_t} whose value $V$, termed the index, is such that $0 \le V < \tcode{sizeof...($P$)}$. @@ -1755,7 +1764,7 @@ \pnum If the operand of a \grammarterm{decltype-specifier} is a prvalue -and is not a (possibly parenthesized) immediate invocation\iref{expr.const}, +and is not a (possibly parenthesized) immediate invocation\iref{expr.const.imm}, the temporary materialization conversion is not applied\iref{conv.rval} and no result object is provided for the prvalue. The type of the prvalue may be incomplete or an abstract class type. @@ -2409,8 +2418,10 @@ \end{note} \pnum -Each \grammarterm{init-declarator} or \grammarterm{member-declarator} -in a declaration is analyzed separately as if it were in a declaration by itself. +Each \grammarterm{init-declarator} of a \grammarterm{simple-declaration} +or \grammarterm{member-declarator} of a \grammarterm{member-declaration} +is analyzed separately as if it were in a +\grammarterm{simple-declaration} or \grammarterm{member-declaration} by itself. \begin{note} A declaration with several declarators is usually equivalent to the corresponding sequence of declarations each with a single declarator. That is, @@ -2713,19 +2724,19 @@ \begin{codeblock} template struct X {}; template struct Y {}; -X a; // type-id +X a; // \grammarterm{type-id} X b; // expression (ill-formed) -Y c; // type-id (ill-formed) +Y c; // \grammarterm{type-id} (ill-formed) Y d; // expression void foo(signed char a) { - sizeof(int()); // type-id (ill-formed) + sizeof(int()); // \grammarterm{type-id} (ill-formed) sizeof(int(a)); // expression - sizeof(int(unsigned(a))); // type-id (ill-formed) + sizeof(int(unsigned(a))); // \grammarterm{type-id} (ill-formed) - (int())+1; // type-id (ill-formed) + (int())+1; // \grammarterm{type-id} (ill-formed) (int(a))+1; // expression - (int(unsigned(a)))+1; // type-id (ill-formed) + (int(unsigned(a)))+1; // \grammarterm{type-id} (ill-formed) } typedef struct BB { int C[2]; } *B, C; @@ -2945,7 +2956,7 @@ specifier or an \grammarterm{explicit-specifier} applies directly to each \grammarterm{declarator-id} -in a declaration; +in a \grammarterm{simple-declaration} or \grammarterm{member-declaration}; the type specified for each \grammarterm{declarator-id} depends on both the \grammarterm{decl-specifier-seq} and its \grammarterm{declarator}. @@ -3274,11 +3285,11 @@ the converted initializer is a glvalue whose type is not call-compatible\iref{expr.call} with the type of the function's definition -results in undefined behavior. +results in undefined behavior\ubdef{dcl.ref.incompatible.function}. Attempting to bind a reference to an object where the converted initializer is a glvalue through which the object is not type-accessible\iref{basic.lval} -results in undefined behavior. +results in undefined behavior\ubdef{dcl.ref.incompatible.type}. \begin{note} \indextext{reference!null}% The object designated by such a glvalue can be @@ -3292,7 +3303,7 @@ \end{note} The behavior of an evaluation of a reference\iref{expr.prim.id, expr.ref} that does not happen after\iref{intro.races} the initialization of the reference -is undefined. +is undefined\ubdef{dcl.ref.uninitialized.reference}. \begin{example} \begin{codeblock} int &f(int&); @@ -3470,7 +3481,7 @@ the type of the \grammarterm{declarator-id} in \tcode{D} is ``\placeholder{derived-declarator-type-list} array of \tcode{N} \tcode{T}''. The \grammarterm{constant-expression} -shall be a converted constant expression of type \tcode{std::size_t}\iref{expr.const}. +shall be a converted constant expression of type \tcode{std::size_t}\iref{expr.const.const}. \indextext{bound, of array}% Its value \tcode{N} specifies the \defnx{array bound}{array!bound}, i.e., the number of elements in the array; @@ -4364,7 +4375,8 @@ \end{example} For a given inline function defined in different translation units, the accumulated sets of default arguments at the end of the -translation units shall be the same; no diagnostic is required. +translation units shall be the same; +no diagnostic is required\ifndrdef{dcl.fct.default.inline.same.defaults}. If a friend declaration $D$ specifies a default argument expression, that declaration shall be a definition and there shall be no other declaration of the function or function template @@ -4381,7 +4393,7 @@ The names in the default argument are looked up, and the semantic constraints are checked, at the point where the default argument appears, except that -an immediate invocation\iref{expr.const} that +an immediate invocation\iref{expr.const.imm} that is a potentially-evaluated subexpression\iref{intro.execution} of the \grammarterm{initializer-clause} in a \grammarterm{parameter-declaration} is neither evaluated @@ -4476,7 +4488,7 @@ A default argument is evaluated each time the function is called with no argument for the corresponding parameter. \indextext{argument!scope of default}% -A parameter shall not appear as a potentially-evaluated expression +A parameter shall not appear as a potentially evaluated expression in a default argument. \indextext{argument and name hiding!default}% \begin{note} @@ -4669,7 +4681,8 @@ a declaration $F_2$ is a first declaration of \tcode{f} in another translation unit, $F_1$ and $F_2$ shall specify the same -\grammarterm{function-contract-specifier-seq}, no diagnostic required. +\grammarterm{function-contract-specifier-seq}, +no diagnostic required\ifndrdef{dcl.contract.func.mismatched.contract.specifiers}. \pnum A \grammarterm{function-contract-specifier-seq} $S_1$ @@ -5412,7 +5425,7 @@ \end{itemize} \pnum -An immediate invocation\iref{expr.const} that is not evaluated where +An immediate invocation\iref{expr.const.imm} that is not evaluated where it appears\iref{dcl.fct.default,class.mem.general} is evaluated and checked for whether it is a constant expression at the point where @@ -7092,7 +7105,7 @@ A non-user-provided defaulted function (i.e., implicitly declared or explicitly defaulted in the class) that is not defined as deleted is implicitly defined when it is odr-used\iref{basic.def.odr} -or needed for constant evaluation\iref{expr.const}. +or needed for constant evaluation\iref{expr.const.defns}. \begin{note} The implicit definition of a non-user-provided defaulted function does not bind any names. @@ -7144,7 +7157,7 @@ This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the function. It applies even for references in expressions that are not -potentially-evaluated. For an overload set, only the +potentially evaluated. For an overload set, only the function selected by overload resolution is referenced. The implicit odr-use\iref{term.odr.use} of a virtual function does not, by itself, constitute a reference. @@ -7387,7 +7400,7 @@ The evaluation that invoked a resumption member function is called the \defnx{resumer}{coroutine!resumer}. Invoking a resumption member function for a coroutine -that is not suspended results in undefined behavior. +that is not suspended results in undefined behavior\ubdef{dcl.fct.def.coroutine.resume.not.suspended}. \pnum An implementation may need to allocate additional storage for a coroutine. @@ -7481,7 +7494,7 @@ The storage for the coroutine state is released by calling a non-array deallocation function\iref{basic.stc.dynamic.deallocation}. If \tcode{destroy} is called for a coroutine that is not suspended, the -program has undefined behavior. +program has undefined behavior\ubdef{dcl.fct.def.coroutine.destroy.not.suspended}. \pnum The deallocation function's name is looked up by searching for it in the scope of the promise type. @@ -7578,7 +7591,7 @@ shall be such that it would be valid as a redeclaration of the declaration in that header; \end{itemize} -no diagnostic is required. +no diagnostic is required\ifndrdef{dcl.fct.def.replace.bad.replacement}. \begin{note} The one-definition rule\iref{basic.def.odr} applies to the definitions of a replaceable function @@ -7724,7 +7737,7 @@ whose value is non-negative; the structured binding size of \tcode{E} is equal to that value. Let \tcode{i} be an index prvalue of type \tcode{std::size_t} -corresponding to $\tcode{v}_i$. +corresponding to $\textrm{SB}_i$. If a search for the name \tcode{get} in the scope of \tcode{E}\iref{class.member.lookup} finds at least one declaration @@ -7741,10 +7754,10 @@ is an lvalue reference and an xvalue otherwise. Given the type $\tcode{T}_i$ designated by \tcode{std::tuple_element::type} and -the type $\tcode{U}_i$ designated by -either \tcode{$\tcode{T}_i$\&} or \tcode{$\tcode{T}_i$\&\&}, -where $\tcode{U}_i$ is an lvalue reference if -the initializer is an lvalue and an rvalue reference otherwise, +the type $\tcode{U}_i$ defined +as $\tcode{T}_i$ if the initializer is a prvalue, +as ``lvalue reference to $\tcode{T}_i$'' if the initializer is an lvalue, or +as ``rvalue reference to $\tcode{T}_i$'' otherwise, variables are introduced with unique names $\tcode{r}_i$ as follows: \begin{ncbnf} @@ -7969,7 +7982,7 @@ type and the \grammarterm{constant-expression} in the \grammarterm{enumerator-definition} shall be a converted constant expression of the underlying -type\iref{expr.const}. +type\iref{expr.const.const}. If the underlying type is not fixed, the type of each enumerator prior to the closing brace is determined as @@ -7979,7 +7992,7 @@ \item If an initializer is specified for an enumerator, the \grammarterm{constant-expression} shall be an integral constant -expression\iref{expr.const}. If the expression has +expression\iref{expr.const.const}. If the expression has unscoped enumeration type, the enumerator has the underlying type of that enumeration type, otherwise it has the same type as the expression. @@ -8803,14 +8816,14 @@ \grammarterm{using-declaration} cannot refer to a destructor for a base class. \end{note} -If a constructor or assignment operator brought from a base class into a derived class -has the signature of a copy/move constructor or assignment operator -for the derived class\iref{class.copy.ctor,class.copy.assign}, -the \grammarterm{using-declaration} does not by itself -suppress the implicit declaration of the derived class member; -the member from the base class is hidden or overridden -by the implicitly-declared copy/move constructor or assignment operator -of the derived class, as described below. +\begin{note} +A \grammarterm{using-declarator} that +names a member function of a base class +does not suppress the implicit declaration of a special member function +in the derived class, +even if their signatures are the +same\iref{class.default.ctor, class.copy.ctor, class.copy.assign}. +\end{note} \pnum A \grammarterm{using-declaration} shall not name a \grammarterm{template-id}. @@ -9299,7 +9312,7 @@ \pnum If two declarations of an entity give it different language linkages, the program is ill-formed; no diagnostic is required if neither declaration -is reachable from the other. +is reachable from the other\ifndrdef{dcl.link.mismatched.language.linkage}. \indextext{consistency!linkage specification}% A redeclaration of an entity without a linkage specification inherits the language linkage of the entity and (if applicable) its type. @@ -9512,6 +9525,13 @@ \grammarterm{attribute-token}. The \grammarterm{attribute-token} determines additional requirements on the \grammarterm{attribute-argument-clause} (if any). +\pnum +\begin{note} +Unless otherwise specified, +an \grammarterm{attribute-token} specified in this document cannot be used +as a macro name\iref{cpp.replace.general}. +\end{note} + \pnum An \grammarterm{annotation} followed by an ellipsis is a pack expansion\iref{temp.variadic}. @@ -9650,7 +9670,7 @@ \grammarterm{alignment-specifier}{}, every defining declaration of that entity shall specify an equivalent alignment. -No diagnostic is required if declarations of an entity have +No diagnostic is required\ifndrdef{dcl.align.diff.translation.units} if declarations of an entity have different \grammarterm{alignment-specifier}{s} in different translation units. \begin{example} @@ -9704,7 +9724,7 @@ at the point where the assumption appears, the assumption has no effect. Otherwise, -evaluation of the assumption has runtime-undefined behavior. +evaluation of the assumption has runtime-undefined behavior\ubdef{dcl.attr.assume.false}. \pnum \begin{note} @@ -9880,7 +9900,7 @@ in one translation unit and the same function is declared without the \tcode{indeterminate} attribute on the same parameter in its first declaration in another translation unit, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{dcl.attr.indet.mismatched.declarations}. \pnum \begin{note} @@ -10081,7 +10101,7 @@ \pnum \recommended Appearance of a nodiscard call as -a potentially-evaluated discarded-value expression\iref{expr.prop} +a potentially evaluated discarded-value expression\iref{expr.prop} of non-void type is discouraged unless explicitly cast to \keyword{void}. Implementations should issue a warning in such cases. @@ -10136,12 +10156,12 @@ specify the \tcode{noreturn} attribute if any declaration of that function specifies the \tcode{noreturn} attribute. If a function is declared with the \tcode{noreturn} attribute in one translation unit and the same function is declared without the \tcode{noreturn} attribute in another -translation unit, the program is ill-formed, no diagnostic required. +translation unit, the program is ill-formed, no diagnostic required\ifndrdef{dcl.attr.noreturn.trans.unit.mismatch}. \pnum If a function \tcode{f} is invoked where \tcode{f} was previously declared with the \tcode{noreturn} attribute and that invocation eventually returns, -the behavior is runtime-undefined. +the behavior is runtime-undefined\ubdef{dcl.attr.noreturn.eventually.returns}. \begin{note} The function can terminate by throwing an exception. @@ -10221,14 +10241,45 @@ \pnum An annotation may be applied to a \grammarterm{base-specifier} or -to any declaration of a +to a declaration $D$ of a type, type alias, variable, function, +function parameter of non-\tcode{void} type, namespace, enumerator, or -non-static data member. +non-static data member, +unless +\begin{itemize} +\item the host scope of $X$ differs from its target scope or +\item $X$ is a non-defining friend declaration, +\end{itemize} +where $X$ is +\begin{itemize} +\item +$D'$ if $D$ is a function parameter declaration in +a function declarator\iref{dcl.fct} of a function declaration $D'$ and +\item $D$ otherwise. +\end{itemize} +\begin{note} +An annotation on a \grammarterm{parameter-declaration} in a function definition +applies to both the function parameter and the variable. +\begin{example} +\begin{codeblock} +void f([[=1]] int x); +void f([[=2]] int y) { + constexpr auto rp = parameters_of(@\reflexpr{f}@)[0]; + constexpr auto ry = variable_of(rp); + static_assert(ry == ^^y); + + static_assert(annotations_of(rp).size() == 2); // both \tcode{[1, 2]} + static_assert(annotations_of(ry).size() == 1); // just \tcode{[2]} + static_assert(annotations_of(rp)[1] == annotations_of(ry)[0]); +} +\end{codeblock} +\end{example} +\end{note} \pnum Let $E$ be the expression @@ -10237,11 +10288,8 @@ the result of $E$ is the \defnadj{underlying}{constant} of the annotation. \pnum -Each \grammarterm{annotation} produces a unique annotation. - -\pnum -Substituting into an \grammarterm{annotation} -is not in the immediate context. +Each \grammarterm{annotation} or instantiation thereof +produces a unique annotation. \begin{example} \begin{codeblock} [[=1]] void f(); @@ -10255,6 +10303,16 @@ \end{example} \begin{example} \begin{codeblock} +template int x [[=1]]; +static_assert(annotations_of(^^x<0>) != annotations_of(^^x<1>)); // OK +\end{codeblock} +\end{example} + +\pnum +Substituting into an \grammarterm{annotation} +is not in the immediate context. +\begin{example} +\begin{codeblock} template [[=T::type()]] void f(T t); diff --git a/source/diagnostics.tex b/source/diagnostics.tex index be2b863f7d..d842475bd9 100644 --- a/source/diagnostics.tex +++ b/source/diagnostics.tex @@ -495,8 +495,11 @@ \pnum If \mname{VA_ARGS} does not expand to -an \grammarterm{assignment-expression}, +a well-formed \grammarterm{assignment-expression}, the program is ill-formed. +If such an \grammarterm{assignment-expression} is ill-formed when +treated as an unevaluated operand\iref{expr.await, expr.yield}, +the program is ill-formed, no diagnostic required. \pnum The macro \tcode{assert} is redefined according to @@ -656,80 +659,80 @@ struct @\libglobal{is_error_condition_enum}@ : public false_type {}; enum class @\libglobal{errc}@ { // freestanding - address_family_not_supported, // \tcode{EAFNOSUPPORT} - address_in_use, // \tcode{EADDRINUSE} - address_not_available, // \tcode{EADDRNOTAVAIL} - already_connected, // \tcode{EISCONN} - argument_list_too_long, // \tcode{E2BIG} - argument_out_of_domain, // \tcode{EDOM} - bad_address, // \tcode{EFAULT} - bad_file_descriptor, // \tcode{EBADF} - bad_message, // \tcode{EBADMSG} - broken_pipe, // \tcode{EPIPE} - connection_aborted, // \tcode{ECONNABORTED} - connection_already_in_progress, // \tcode{EALREADY} - connection_refused, // \tcode{ECONNREFUSED} - connection_reset, // \tcode{ECONNRESET} - cross_device_link, // \tcode{EXDEV} - destination_address_required, // \tcode{EDESTADDRREQ} - device_or_resource_busy, // \tcode{EBUSY} - directory_not_empty, // \tcode{ENOTEMPTY} - executable_format_error, // \tcode{ENOEXEC} - file_exists, // \tcode{EEXIST} - file_too_large, // \tcode{EFBIG} - filename_too_long, // \tcode{ENAMETOOLONG} - function_not_supported, // \tcode{ENOSYS} - host_unreachable, // \tcode{EHOSTUNREACH} - identifier_removed, // \tcode{EIDRM} - illegal_byte_sequence, // \tcode{EILSEQ} - inappropriate_io_control_operation, // \tcode{ENOTTY} - interrupted, // \tcode{EINTR} - invalid_argument, // \tcode{EINVAL} - invalid_seek, // \tcode{ESPIPE} - io_error, // \tcode{EIO} - is_a_directory, // \tcode{EISDIR} - message_size, // \tcode{EMSGSIZE} - network_down, // \tcode{ENETDOWN} - network_reset, // \tcode{ENETRESET} - network_unreachable, // \tcode{ENETUNREACH} - no_buffer_space, // \tcode{ENOBUFS} - no_child_process, // \tcode{ECHILD} - no_link, // \tcode{ENOLINK} - no_lock_available, // \tcode{ENOLCK} - no_message, // \tcode{ENOMSG} - no_protocol_option, // \tcode{ENOPROTOOPT} - no_space_on_device, // \tcode{ENOSPC} - no_such_device_or_address, // \tcode{ENXIO} - no_such_device, // \tcode{ENODEV} - no_such_file_or_directory, // \tcode{ENOENT} - no_such_process, // \tcode{ESRCH} - not_a_directory, // \tcode{ENOTDIR} - not_a_socket, // \tcode{ENOTSOCK} - not_connected, // \tcode{ENOTCONN} - not_enough_memory, // \tcode{ENOMEM} - not_supported, // \tcode{ENOTSUP} - operation_canceled, // \tcode{ECANCELED} - operation_in_progress, // \tcode{EINPROGRESS} - operation_not_permitted, // \tcode{EPERM} - operation_not_supported, // \tcode{EOPNOTSUPP} - operation_would_block, // \tcode{EWOULDBLOCK} - owner_dead, // \tcode{EOWNERDEAD} - permission_denied, // \tcode{EACCES} - protocol_error, // \tcode{EPROTO} - protocol_not_supported, // \tcode{EPROTONOSUPPORT} - read_only_file_system, // \tcode{EROFS} - resource_deadlock_would_occur, // \tcode{EDEADLK} - resource_unavailable_try_again, // \tcode{EAGAIN} - result_out_of_range, // \tcode{ERANGE} - state_not_recoverable, // \tcode{ENOTRECOVERABLE} - text_file_busy, // \tcode{ETXTBSY} - timed_out, // \tcode{ETIMEDOUT} - too_many_files_open_in_system, // \tcode{ENFILE} - too_many_files_open, // \tcode{EMFILE} - too_many_links, // \tcode{EMLINK} - too_many_symbolic_link_levels, // \tcode{ELOOP} - value_too_large, // \tcode{EOVERFLOW} - wrong_protocol_type, // \tcode{EPROTOTYPE} + @\libmember{address_family_not_supported}{errc}@, // \tcode{EAFNOSUPPORT} + @\libmember{address_in_use}{errc}@, // \tcode{EADDRINUSE} + @\libmember{address_not_available}{errc}@, // \tcode{EADDRNOTAVAIL} + @\libmember{already_connected}{errc}@, // \tcode{EISCONN} + @\libmember{argument_list_too_long}{errc}@, // \tcode{E2BIG} + @\libmember{argument_out_of_domain}{errc}@, // \tcode{EDOM} + @\libmember{bad_address}{errc}@, // \tcode{EFAULT} + @\libmember{bad_file_descriptor}{errc}@, // \tcode{EBADF} + @\libmember{bad_message}{errc}@, // \tcode{EBADMSG} + @\libmember{broken_pipe}{errc}@, // \tcode{EPIPE} + @\libmember{connection_aborted}{errc}@, // \tcode{ECONNABORTED} + @\libmember{connection_already_in_progress}{errc}@, // \tcode{EALREADY} + @\libmember{connection_refused}{errc}@, // \tcode{ECONNREFUSED} + @\libmember{connection_reset}{errc}@, // \tcode{ECONNRESET} + @\libmember{cross_device_link}{errc}@, // \tcode{EXDEV} + @\libmember{destination_address_required}{errc}@, // \tcode{EDESTADDRREQ} + @\libmember{device_or_resource_busy}{errc}@, // \tcode{EBUSY} + @\libmember{directory_not_empty}{errc}@, // \tcode{ENOTEMPTY} + @\libmember{executable_format_error}{errc}@, // \tcode{ENOEXEC} + @\libmember{file_exists}{errc}@, // \tcode{EEXIST} + @\libmember{file_too_large}{errc}@, // \tcode{EFBIG} + @\libmember{filename_too_long}{errc}@, // \tcode{ENAMETOOLONG} + @\libmember{function_not_supported}{errc}@, // \tcode{ENOSYS} + @\libmember{host_unreachable}{errc}@, // \tcode{EHOSTUNREACH} + @\libmember{identifier_removed}{errc}@, // \tcode{EIDRM} + @\libmember{illegal_byte_sequence}{errc}@, // \tcode{EILSEQ} + @\libmember{inappropriate_io_control_operation}{errc}@, // \tcode{ENOTTY} + @\libmember{interrupted}{errc}@, // \tcode{EINTR} + @\libmember{invalid_argument}{errc}@, // \tcode{EINVAL} + @\libmember{invalid_seek}{errc}@, // \tcode{ESPIPE} + @\libmember{io_error}{errc}@, // \tcode{EIO} + @\libmember{is_a_directory}{errc}@, // \tcode{EISDIR} + @\libmember{message_size}{errc}@, // \tcode{EMSGSIZE} + @\libmember{network_down}{errc}@, // \tcode{ENETDOWN} + @\libmember{network_reset}{errc}@, // \tcode{ENETRESET} + @\libmember{network_unreachable}{errc}@, // \tcode{ENETUNREACH} + @\libmember{no_buffer_space}{errc}@, // \tcode{ENOBUFS} + @\libmember{no_child_process}{errc}@, // \tcode{ECHILD} + @\libmember{no_link}{errc}@, // \tcode{ENOLINK} + @\libmember{no_lock_available}{errc}@, // \tcode{ENOLCK} + @\libmember{no_message}{errc}@, // \tcode{ENOMSG} + @\libmember{no_protocol_option}{errc}@, // \tcode{ENOPROTOOPT} + @\libmember{no_space_on_device}{errc}@, // \tcode{ENOSPC} + @\libmember{no_such_device_or_address}{errc}@, // \tcode{ENXIO} + @\libmember{no_such_device}{errc}@, // \tcode{ENODEV} + @\libmember{no_such_file_or_directory}{errc}@, // \tcode{ENOENT} + @\libmember{no_such_process}{errc}@, // \tcode{ESRCH} + @\libmember{not_a_directory}{errc}@, // \tcode{ENOTDIR} + @\libmember{not_a_socket}{errc}@, // \tcode{ENOTSOCK} + @\libmember{not_connected}{errc}@, // \tcode{ENOTCONN} + @\libmember{not_enough_memory}{errc}@, // \tcode{ENOMEM} + @\libmember{not_supported}{errc}@, // \tcode{ENOTSUP} + @\libmember{operation_canceled}{errc}@, // \tcode{ECANCELED} + @\libmember{operation_in_progress}{errc}@, // \tcode{EINPROGRESS} + @\libmember{operation_not_permitted}{errc}@, // \tcode{EPERM} + @\libmember{operation_not_supported}{errc}@, // \tcode{EOPNOTSUPP} + @\libmember{operation_would_block}{errc}@, // \tcode{EWOULDBLOCK} + @\libmember{owner_dead}{errc}@, // \tcode{EOWNERDEAD} + @\libmember{permission_denied}{errc}@, // \tcode{EACCES} + @\libmember{protocol_error}{errc}@, // \tcode{EPROTO} + @\libmember{protocol_not_supported}{errc}@, // \tcode{EPROTONOSUPPORT} + @\libmember{read_only_file_system}{errc}@, // \tcode{EROFS} + @\libmember{resource_deadlock_would_occur}{errc}@, // \tcode{EDEADLK} + @\libmember{resource_unavailable_try_again}{errc}@, // \tcode{EAGAIN} + @\libmember{result_out_of_range}{errc}@, // \tcode{ERANGE} + @\libmember{state_not_recoverable}{errc}@, // \tcode{ENOTRECOVERABLE} + @\libmember{text_file_busy}{errc}@, // \tcode{ETXTBSY} + @\libmember{timed_out}{errc}@, // \tcode{ETIMEDOUT} + @\libmember{too_many_files_open_in_system}{errc}@, // \tcode{ENFILE} + @\libmember{too_many_files_open}{errc}@, // \tcode{EMFILE} + @\libmember{too_many_links}{errc}@, // \tcode{EMLINK} + @\libmember{too_many_symbolic_link_levels}{errc}@, // \tcode{ELOOP} + @\libmember{value_too_large}{errc}@, // \tcode{EOVERFLOW} + @\libmember{wrong_protocol_type}{errc}@, // \tcode{EPROTOTYPE} }; template<> struct is_error_condition_enum : true_type {}; @@ -760,7 +763,7 @@ template constexpr bool @\libglobal{is_error_code_enum_v}@ = is_error_code_enum::value; template - constexpr bool is_error_condition_enum_v = is_error_condition_enum::value; + constexpr bool @\libglobal{is_error_condition_enum_v}@ = is_error_condition_enum::value; } \end{codeblock} @@ -2289,8 +2292,8 @@ \indexlibrarymember{swap}{basic_stacktrace}% \begin{itemdecl} template -void swap(basic_stacktrace& a, basic_stacktrace& b) - noexcept(noexcept(a.swap(b))); + void swap(basic_stacktrace& a, basic_stacktrace& b) + noexcept(noexcept(a.swap(b))); \end{itemdecl} \begin{itemdescr} @@ -2319,7 +2322,7 @@ \indexlibrarymember{to_string}{basic_stacktrace}% \begin{itemdecl} template -string to_string(const basic_stacktrace& st); + string to_string(const basic_stacktrace& st); \end{itemdecl} \begin{itemdescr} diff --git a/source/exceptions.tex b/source/exceptions.tex index 2a4d6d7bd5..2747ac462d 100644 --- a/source/exceptions.tex +++ b/source/exceptions.tex @@ -177,7 +177,7 @@ try : i(f(ii)), d(id) { // constructor statements } catch (...) { - // handles exceptions thrown from the ctor-initializer and from the constructor statements + // handles exceptions thrown from the \grammarterm{ctor-initializer} and from the constructor statements } \end{codeblock} \end{example} @@ -556,9 +556,9 @@ \item% a standard pointer conversion\iref{conv.ptr} not involving conversions -to pointers to private or protected or ambiguous classes +to pointers to private or protected or ambiguous classes, \item% -a function pointer conversion\iref{conv.fctptr} +a function pointer conversion\iref{conv.fctptr}, \item% a qualification conversion\iref{conv.qual}, or @@ -690,7 +690,7 @@ Referring to any non-static member or base class of an object in the handler for a \grammarterm{function-try-block} -of a constructor or destructor for that object results in undefined behavior. +of a constructor or destructor for that object results in undefined behavior\ubdef{except.handle.handler.ctor.dtor}. \pnum Exceptions thrown in destructors of objects with static storage duration or in @@ -781,7 +781,7 @@ \indextext{exception specification!noexcept!constant expression and}% In a \grammarterm{noexcept-specifier}, the \grammarterm{constant-expression}, if supplied, shall be a contextually converted constant expression -of type \keyword{bool}\iref{expr.const}; +of type \keyword{bool}\iref{expr.const.const}; that constant expression is the exception specification of the function type in which the \grammarterm{noexcept-specifier} appears. A \tcode{(} token that follows \keyword{noexcept} is part of the @@ -887,7 +887,7 @@ or \item any of the immediate subexpressions\iref{intro.execution} -of $E$ is potentially-throwing. +of $E$ that is not an unevaluated operand is potentially-throwing. \end{itemize} \pnum @@ -996,7 +996,9 @@ declaration (e.g., an explicit specialization or an overriding virtual function); -\item the function is defined; or +\item the function is defined; + +\item the function is represented by a reflection; or \item the exception specification is needed for a defaulted function that calls the function. @@ -1009,10 +1011,7 @@ \end{note} \end{itemize} The exception specification of a defaulted -function is evaluated as described above only when needed; similarly, the -\grammarterm{noexcept-specifier} of a specialization -of a templated function -is instantiated only when needed. +function is evaluated as described above only when needed. % \indextext{exception specification|)} diff --git a/source/exec.tex b/source/exec.tex index ddc8be2be3..61e8379bd6 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -463,19 +463,25 @@ // \ref{exec.queries}, queries struct @\libglobal{get_domain_t}@ { @\unspec@ }; struct @\libglobal{get_scheduler_t}@ { @\unspec@ }; + struct @\libglobal{get_start_scheduler_t}@ { @\unspec@ }; struct @\libglobal{get_delegation_scheduler_t}@ { @\unspec@ }; struct @\libglobal{get_forward_progress_guarantee_t}@ { @\unspec@ }; template struct @\libglobal{get_completion_scheduler_t}@ { @\unspec@ }; + template + struct @\libglobal{get_completion_domain_t}@ { @\unspec@ }; struct get_await_completion_adaptor_t { @\unspec@ }; inline constexpr get_domain_t @\libglobal{get_domain}@{}; inline constexpr get_scheduler_t @\libglobal{get_scheduler}@{}; + inline constexpr get_start_scheduler_t @\libglobal{get_start_scheduler}@{}; inline constexpr get_delegation_scheduler_t @\libglobal{get_delegation_scheduler}@{}; enum class forward_progress_guarantee; inline constexpr get_forward_progress_guarantee_t @\libglobal{get_forward_progress_guarantee}@{}; template constexpr get_completion_scheduler_t @\libglobal{get_completion_scheduler}@{}; + template + constexpr get_completion_domain_t @\libglobal{get_completion_domain}@{}; inline constexpr get_await_completion_adaptor_t get_await_completion_adaptor{}; struct @\libglobal{get_env_t}@ { @\unspec@ }; @@ -484,23 +490,30 @@ template using @\libglobal{env_of_t}@ = decltype(get_env(declval())); + // \ref{exec.domain.indeterminate}, execution domains + template + struct indeterminate_domain; + // \ref{exec.domain.default}, execution domains struct default_domain; // \ref{exec.sched}, schedulers - struct @\libglobal{scheduler_t}@ {}; + struct @\libglobal{scheduler_tag}@ {}; template concept @\libconcept{scheduler}@ = @\seebelow@; // \ref{exec.recv}, receivers - struct @\libglobal{receiver_t}@ {}; + struct @\libglobal{receiver_tag}@ {}; template concept @\libconcept{receiver}@ = @\seebelow@; template - concept @\libconcept{receiver_of}@ = @\seebelow@; + concept @\exposconceptnc{receiver-of}@ = @\seebelownc@; // \expos + + template + concept @\libconcept{inlinable_receiver}@ = @\seebelow@; struct @\libglobal{set_value_t}@ { @\unspec@ }; struct @\libglobal{set_error_t}@ { @\unspec@ }; @@ -511,7 +524,7 @@ inline constexpr set_stopped_t @\libglobal{set_stopped}@{}; // \ref{exec.opstate}, operation states - struct @\libglobal{operation_state_t}@ {}; + struct @\libglobal{operation_state_tag}@ {}; template concept @\libconcept{operation_state}@ = @\seebelow@; @@ -520,7 +533,7 @@ inline constexpr start_t @\libglobal{start}@{}; // \ref{exec.snd}, senders - struct @\libglobal{sender_t}@ {}; + struct @\libglobal{sender_tag}@ {}; template inline constexpr bool enable_sender = @\seebelow@; @@ -535,7 +548,7 @@ concept @\libconcept{dependent_sender}@ = @\seebelow@; template - concept @\libconcept{sender_to}@ = @\seebelow@; + concept @\exposconceptnc{sender-to}@ = @\seebelownc@; // \expos template struct @\exposidnc{type-list}@; // \expos @@ -565,21 +578,15 @@ using @\exposidnc{single-sender-value-type}@ = @\seebelownc@; // \expos template - concept @\exposconcept{single-sender}@ = @\seebelow@; // \expos + concept @\exposconceptnc{single-sender}@ = @\seebelownc@; // \expos template<@\libconcept{sender}@ Sndr> using tag_of_t = @\seebelow@; // \ref{exec.snd.transform}, sender transformations - template - requires (sizeof...(Env) <= 1) - constexpr @\libconcept{sender}@ decltype(auto) transform_sender( - Domain dom, Sndr&& sndr, const Env&... env) noexcept(@\seebelow@); - - // \ref{exec.snd.transform.env}, environment transformations - template - constexpr @\exposconcept{queryable}@ decltype(auto) transform_env( - Domain dom, Sndr&& sndr, Env&& env) noexcept; + template<@\libconcept{sender}@ Sndr, @\exposconcept{queryable}@ Env> + constexpr decltype(auto) transform_sender(Sndr&& sndr, + const Env& env) noexcept(@\seebelow@); // \ref{exec.snd.apply}, sender algorithm application template @@ -711,9 +718,9 @@ template<@\exposconcept{class-type}@ Promise> struct with_awaitable_senders; - // \ref{exec.affine.on}, coroutine utility \tcode{affine_on} - struct @\libglobal{affine_on_t}@ { @\unspec@ }; - inline constexpr affine_on_t @\libglobal{affine_on}@{}; + // \ref{exec.affine}, coroutine utility \tcode{affine} + struct @\libglobal{affine_t}@ { @\unspec@ }; + inline constexpr affine_t @\libglobal{affine}@{}; // \ref{exec.inline.scheduler}, inline scheduler class @\libglobal{inline_scheduler}@; @@ -729,14 +736,6 @@ template with_error(E) -> with_error; - template<@\libconcept{scheduler}@ Sch> - struct change_coroutine_scheduler { - using type = remove_cvref_t; - type scheduler; - }; - template<@\libconcept{scheduler}@ Sch> - change_coroutine_scheduler(Sch) -> change_coroutine_scheduler; - // \ref{exec.task}, class template \tcode{task} template class @\libglobal{task}@; @@ -757,8 +756,8 @@ class @\libglobal{parallel_scheduler}@; parallel_scheduler get_parallel_scheduler(); - // \ref{exec.sysctxrepl}, namespace \tcode{system_context_replaceability} - namespace @\libglobal{system_context_replaceability}@ { + // \ref{exec.parschedrepl}, namespace \tcode{parallel_scheduler_replacement} + namespace @\libglobal{parallel_scheduler_replacement}@ { struct receiver_proxy; struct bulk_item_receiver_proxy; struct parallel_scheduler_backend; @@ -829,6 +828,26 @@ \rSec1[exec.queries]{Queries} +\rSec2[exec.queries.expos]{Query utilities} + +\pnum +Subclause \ref{exec.queries} makes use of the following exposition-only entities. + +\pnum +For subexpressions \tcode{q} and \tcode{tag} and pack \tcode{args}, +let \tcode{\exposid{TRY-QUERY}(q, tag, args...)} be expression-equivalent to +\tcode{\exposid{AS-CONST}(q).query(tag, args...)} +if that expression is well-formed, and +\tcode{\exposid{AS-CONST}(q).query(tag)} otherwise +except that \tcode{args...} is evaluated. + +\pnum +For subexpressions \tcode{q} and \tcode{tag} and pack \tcode{args}, +let \tcode{\exposid{HIDE-SCHED}(q)} be an object \tcode{o} such that +\tcode{o.query(\brk{}tag, args...)} is ill-formed when the decayed type of \tcode{tag} is +\tcode{get_scheduler_t} or \tcode{get_domain_t}, and +\tcode{q.query(tag, args...)} otherwise. + \rSec2[exec.fwd.env]{\tcode{forwarding_query}} \pnum @@ -937,7 +956,14 @@ The name \tcode{get_domain} denotes a query object. For a subexpression \tcode{env}, \tcode{get_domain(env)} is expression-equivalent to -\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(env).query(get_domain))}. +\tcode{\exposid{MANDATE-NOTHROW}(D())}, +where \tcode{D} is the type of the first +of the following expressions that is well-formed: +\begin{itemize} +\item \tcode{auto(\exposid{AS-CONST}(env).query(get_domain))}. +\item \tcode{get_completion_domain(get_scheduler(env), \exposid{HIDE-SCHED}(env))}. +\item \tcode{default_domain()}, except that \tcode{env} is evaluated. +\end{itemize} \pnum \tcode{forwarding_query(execution::get_domain)} is @@ -952,7 +978,9 @@ The name \tcode{get_scheduler} denotes a query object. For a subexpression \tcode{env}, \tcode{get_scheduler(env)} is expression-equivalent to -\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(env).query(get_scheduler))}. +\tcode{get_completion_scheduler( +\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(env)\brk{}.query(get_scheduler)), +\exposid{HIDE-SCHED}(env))}. \mandates If the expression above is well-formed, @@ -962,6 +990,34 @@ \tcode{forwarding_query(execution::get_scheduler)} is a core constant expression and has value \tcode{true}. +\rSec2[exec.get.start.scheduler]{\tcode{execution::get_start_scheduler}} + +\pnum +\tcode{get_start_scheduler} asks a queryable object +for the scheduler an operation will be or was started on. + +\pnum +The name \tcode{get_start_scheduler} denotes a query object. +For a subexpression \tcode{env}, +\tcode{get_start_scheduler(\brk{}env)} is expression-equivalent to +\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(env).query(get_start_scheduler))}. + +\mandates +If the expression above is well-formed, +its type satisfies \libconcept{scheduler}. + +\pnum +\tcode{forwarding_query(execution::get_start_scheduler)} +is a core constant expression and has value \tcode{true}. + +\pnum +Given subexpressions \tcode{sndr} and \tcode{rcvr} +such that \tcode{\exposid{sender-to}} is \tcode{true} +and the expression \tcode{get_start_scheduler(get_env(rcvr))} is well-formed, +an operation state that is the result of calling \tcode{connect(sndr, rcvr)} +shall, if it is started, be started on an execution agent +associated with the scheduler \tcode{get_start_scheduler(get_env(rcvr))}. + \rSec2[exec.get.delegation.scheduler]{\tcode{execution::get_delegation_scheduler}} \pnum @@ -1007,16 +1063,12 @@ \tcode{get_forward_progress_guarantee} is ill-formed. Otherwise, \tcode{get_forward_progress_guarantee(sch)} is expression-equivalent to: -\begin{itemize} -\item -\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(sch).query(get_forward_progress_guarantee))}, -if that expression is well-formed. +\begin{codeblock} +@\exposid{MANDATE-NOTHROW}@(@\exposid{AS-CONST}@(sch).query(get_forward_progress_guarantee)) +\end{codeblock} \mandates The type of the expression above is \tcode{forward_progress_guarantee}. -\item -Otherwise, \tcode{forward_progress_guarantee::weakly_parallel}. -\end{itemize} \pnum If \tcode{get_forward_progress_guarantee(sch)} for some scheduler \tcode{sch} @@ -1030,34 +1082,72 @@ \rSec2[exec.get.compl.sched]{\tcode{execution::get_completion_scheduler}} \pnum -\tcode{get_completion_scheduler<\exposid{completion-tag>}} obtains +The name \tcode{get_completion_scheduler} denotes a query object template. + +\pnum +Let \exposid{completion-fn} be a completion function\iref{exec.async.ops}; +let \exposid{completion-fn-tag} be +the associated completion tag of \exposid{completion-fn}; +let \tcode{args} and \tcode{envs} be packs of subexpressions; and +let \tcode{sndr} be a subexpression +such that \tcode{\libconcept{sender}} is \tcode{true} and +\tcode{get_completion_scheduler<\exposid{completion-fn-tag}>(get_env(sndr), envs...)} +is well-formed and denotes a scheduler \tcode{sch}. + +\pnum +\tcode{get_completion_scheduler<\exposid{completion-fn-tag>}} obtains the completion scheduler associated with a completion tag from a sender's attributes. \pnum -The name \tcode{get_completion_scheduler} denotes a query object template. -For a subexpression \tcode{q}, -the expression \tcode{get_completion_scheduler<\exposid{completion-tag}>(q)} -is ill-formed if \exposid{completion-tag} is not one of +For subexpression \tcode{sch1} and pack \tcode{envs}, +let \tcode{sch2} be +\tcode{\exposid{TRY-QUERY}(sch1, get_completion_scheduler, envs...)} and +let \tcode{\exposid{RECURSE-QUERY}(sch1, envs...)} be +expression-equivalent to \tcode{sch1} +if \tcode{sch2} is ill-formed or +if \tcode{sch1} and \tcode{sch2} have the same type and compare equal; +otherwise, \tcode{\exposid{RECURSE-QUERY}(sch2, envs...)}. + +\pnum +For a subexpression \tcode{q} and pack \tcode{envs}, +the expression \tcode{get_completion_scheduler<\exposid{completion-fn-tag}>(q, envs...)} +is ill-formed if \exposid{completion-fn-tag} is not one of \tcode{set_value_t}, \tcode{set_error_t}, or \tcode{set_stopped_t}. -Otherwise, \tcode{get_completion_scheduler<\exposid{completion-tag}>(q)} -is expression-equivalent to +Otherwise, \tcode{get_completion_scheduler<\exposid{completion-fn-tag}>(q, envs...)} +is expression-equivalent to: +\begin{itemize} +\item \begin{codeblock} -@\exposid{MANDATE-NOTHROW}@(@\exposid{AS-CONST}@(q).query(get_completion_scheduler<@\exposid{completion-tag}@>)) +@\exposid{MANDATE-NOTHROW}@(@\exposid{RECURSE-QUERY}@( + @\exposid{TRY-QUERY}@(q, get_completion_scheduler<@\exposid{completion-fn-tag}@>, envs...), envs...)) \end{codeblock} +if that expression is well-formed, +except that \tcode{envs...} is evaluated only once. +\item +Otherwise, \tcode{auto(q)} +if the type of \tcode{q} satisfies \libconcept{scheduler} and +\tcode{envs} is not an empty pack, +except that \tcode{envs...} is evaluated. +\item +Otherwise, \tcode{get_completion_scheduler<\exposid{completion-fn-tag}>(q, envs...)} +is ill-formed. +\end{itemize} \mandates -If the expression above is well-formed, +If \tcode{get_completion_scheduler<\exposid{completion-fn-tag}>(q, envs...)} +is well-formed, its type satisfies \libconcept{scheduler}. \pnum -Let \exposid{completion-fn} be a completion function\iref{exec.async.ops}; -let \exposid{completion-tag} be -the associated completion tag of \exposid{completion-fn}; -let \tcode{args} be a pack of subexpressions; and -let \tcode{sndr} be a subexpression -such that \tcode{\libconcept{sender}} is \tcode{true} and -\tcode{get_completion_scheduler<\exposid{completion-tag}>(get_env(sndr))} -is well-formed and denotes a scheduler \tcode{sch}. +For a type \tcode{Tag}, subexpression \tcode{sndr}, and pack \tcode{envs}, +let \tcode{CS} be +\tcode{completion_signatures_of_t, decltype((envs))...>}. +If both \tcode{get_completion_scheduler(get_env(\newline sndr), envs...)} and +\tcode{CS} are well-formed and +\tcode{CS().\exposid{count-of}(Tag()) == 0} is \tcode{true}, +the program is ill-formed. + +\pnum If an asynchronous operation created by connecting \tcode{sndr} with a receiver \tcode{rcvr} causes the evaluation of \tcode{\exposid{completion-fn}(rcvr, args...)}, @@ -1067,7 +1157,79 @@ \pnum The expression -\tcode{forwarding_query(get_completion_scheduler<\exposid{completion-tag}>)} +\tcode{forwarding_query(get_completion_scheduler<\exposid{completion-fn-tag}>)} +is a core constant expression and has value \tcode{true}. + +\rSec2[exec.get.compl.domain]{\tcode{execution::get_completion_domain}} + +\pnum +\tcode{get_completion_domain<\exposid{completion-tag}>} +obtains the completion domain associated with a completion tag +from a sender's attributes. + +\pnum +The name \tcode{get_completion_domain} denotes a query object template. +For a subexpression \tcode{attrs} and pack \tcode{envs}, +the expression \tcode{get_completion_domain<\exposid{completion-tag}>(attrs, envs...)} +is ill-formed if \exposid{completion-tag} is not one of +\tcode{void}, +\tcode{set_value_t}, +\tcode{set_error_t}, or +\tcode{set_stopped_t}. +Otherwise, it is expression-equivalent to +\tcode{\exposid{MANDATE-NOTHROW}(D())}, +where \tcode{D} is: +\begin{itemize} +\item +The type of +\tcode{\exposid{TRY-QUERY}(attrs, get_completion_domain<\exposid{completion-tag}>, envs...)} +if that expression is well-formed. +\item +Otherwise, the type of +\tcode{get_completion_domain(attrs, envs...)} +if \exposid{completion-tag} is \tcode{void}. +\item +Otherwise, the type of +\begin{codeblock} +@\exposidnc{TRY-QUERY}@(get_completion_scheduler(attrs, envs...), + get_completion_domain, envs...) +\end{codeblock} +if that expression is well-formed. +\item +Otherwise, \tcode{default_domain} if +\tcode{\libconcept{scheduler}} is \tcode{true} and +\tcode{envs} is not an empty pack. +\item +Otherwise, \tcode{get_completion_domain<\exposid{completion-tag}>(attrs, envs...)} +is ill-formed. +\end{itemize} + +\pnum +For a type \tcode{Tag}, subexpression \tcode{sndr}, and pack \tcode{envs}, +let \tcode{CS} be +\tcode{completion_signatures_of_t, decltype((envs))...>}. +If both \tcode{get_completion_domain(get_env(sndr), envs...)} and +\tcode{CS} are well-formed and +\tcode{CS().\exposid{count-of}(Tag()) == 0} is \tcode{true}, +the program is ill-formed. + +\pnum +Let \exposid{completion-fn} be a completion function\iref{exec.async.ops}; +let \exposid{completion-tag} be the associated completion tag of \exposid{completion-fn}; +let \tcode{args} and \tcode{envs} be packs of subexpressions; and +let \tcode{sndr} be a subexpression such that +\tcode{\libconcept{sender}} is \tcode{true} and +\tcode{get_completion_domain<\exposid{completion-tag}>(get_env(sndr), envs...)} +is well-formed and denotes a domain tag \tcode{D}. +If an asynchronous operation created by connecting +\tcode{sndr} with a receiver \tcode{rcvr} +causes the evaluation of \tcode{\exposid{completion-fn}(rcvr, args...)}, +the behavior is undefined +unless the evaluation happens on an execution agent of an execution resource +whose associated execution domain tag is \tcode{D}. + +The expression +\tcode{forwarding_query(get_completion_domain<\exposid{completion-tag}>)} is a core constant expression and has value \tcode{true}. \rSec2[exec.get.await.adapt]{\tcode{execution::get_await_completion_adaptor}} @@ -1103,13 +1265,11 @@ namespace std::execution { template concept @\deflibconcept{scheduler}@ = - @\libconcept{derived_from}@::scheduler_concept, scheduler_t> && + @\libconcept{derived_from}@::scheduler_concept, scheduler_tag> && @\exposconcept{queryable}@ && requires(Sch&& sch) { { schedule(std::forward(sch)) } -> @\libconcept{sender}@; - { auto(get_completion_scheduler( - get_env(schedule(std::forward(sch))))) } - -> @\libconcept{same_as}@>; + { get_forward_progress_guarantee(sch) } -> @\libconcept{same_as}@; } && @\libconcept{equality_comparable}@> && @\libconcept{copyable}@>; @@ -1144,21 +1304,51 @@ \pnum For a given scheduler expression \tcode{sch}, -the expression +if the expression \tcode{get_completion_scheduler(get_env(schedule(sch)))} -shall compare equal to \tcode{sch}. +is well-formed, +it shall compare equal to \tcode{sch}. \pnum For a given scheduler expression \tcode{sch}, -if the expression \tcode{get_domain(sch)} is well-formed, -then the expression \tcode{get_domain(get_env(schedule(sch)))} -is also well-formed and has the same type. +type \tcode{T}, and +pack of subexpressions \tcode{envs}, +the following expressions are either both ill-formed, or +both well-formed with the same type: +\begin{itemize} +\item \tcode{get_completion_domain(sch, envs...)} +\item \tcode{get_completion_domain(get_env(schedule(sch)), envs...)} +\end{itemize} +Likewise, the following expressions are either both ill-formed, or +both well-formed with the same type and value: +\begin{itemize} +\item \tcode{get_completion_scheduler(sch, envs...)} +\item \tcode{get_completion_scheduler(get_env(schedule(sch)), envs...)} +\end{itemize} \pnum A scheduler type's destructor shall not block pending completion of any receivers connected to the sender objects returned from \tcode{schedule}. +\pnum +The exposition-only \exposconcept{infallible-scheduler} concept +defines the requirements of a scheduler type +whose \tcode{schedule} asynchronous operation +can only complete with \tcode{set_value} unless stop can be requested: +\begin{codeblock} +template + concept @\defexposconcept{infallible-scheduler}@ = + @\libconcept{scheduler}@ && + (@\libconcept{same_as}@, + completion_signatures_of_t())), Env>> || + (!@\libconcept{unstoppable_token}@> && + (@\libconcept{same_as}@, + completion_signatures_of_t())), Env>> || + @\libconcept{same_as}@, + completion_signatures_of_t())), Env>>))); +\end{codeblock} + \rSec1[exec.recv]{Receivers} \rSec2[exec.recv.concepts]{Receiver concepts} @@ -1167,7 +1357,7 @@ A receiver represents the continuation of an asynchronous operation. The \libconcept{receiver} concept defines the requirements for a receiver type\iref{exec.async.ops}. -The \libconcept{receiver_of} concept defines +The exposition-only concept \exposconcept{receiver-of} defines the requirements for a receiver type that is usable as the first argument of a set of completion operations corresponding to a set of completion signatures. @@ -1177,7 +1367,7 @@ namespace std::execution { template concept @\deflibconcept{receiver}@ = - @\libconcept{derived_from}@::receiver_concept, receiver_t> && + @\libconcept{derived_from}@::receiver_concept, receiver_tag> && requires(const remove_cvref_t& rcvr) { { get_env(rcvr) } -> @\exposconcept{queryable}@; } && @@ -1201,7 +1391,7 @@ }; template - concept @\deflibconcept{receiver_of}@ = + concept @\defexposconcept{receiver-of}@ = @\libconcept{receiver}@ && @\exposconcept{has-completions}@; } \end{codeblock} @@ -1226,6 +1416,98 @@ must be destroyed before the invocation of the completion operation. \end{note} +\pnum +\begin{codeblock} +namespace std::execution { + template + concept @\deflibconcept{inlinable_receiver}@ = @\libconcept{receiver}@ && + requires (ChildOp* child) { + { remove_cvref_t::make_receiver_for(child) } noexcept + -> @\libconcept{same_as}@>; + }; +} +\end{codeblock} + +The \libconcept{inlinable_receiver} concept +defines the requirements for a receiver +that can be reconstructed on demand +from a pointer to the operation state object +created when the receiver was connected to a sender. +Given a receiver object \tcode{rcvr} of type \tcode{Rcvr} +which was connected to a sender producing +an operation state object \tcode{op} of type \tcode{Op}, +\tcode{Rcvr} models \tcode{\libconcept{inlinable_receiver}} +only if the expression \tcode{Rcvr::make_receiver_for(addressof(op))} +evaluates to a receiver +that is equal to \tcode{rcvr}\iref{concepts.equality}. +\begin{note} +Such a receiver does not need to be stored as a data member of \tcode{op} +as it can be recreated on demand. +\end{note} +\tcode{ChildOp} may be an incomplete type. + +\pnum +Given objects $O_0, \dotsc, O_n$, +$O_n$ is \defnadj{transitively}{constructed} from $O_0$ if +\begin{itemize} +\item +\tcode{remove_cvref_t} +denotes the same type as +\tcode{remove_cvref_t} and +\item +either +\begin{itemize} +\item +$O_1$ was initialized by decay-copying a reference to $O_0$, or +\item +$n > 1$ and $O_{n-1}$ is transitively constructed from $O_0$ and +$O_n$ was initialized from +a non-const, non-volatile rvalue reference to $O_{n-1}$. +\end{itemize} +\end{itemize} + +\pnum +Let $E$ be some well-formed expression \tcode{connect(sndr, rcvr)}. +$E$ \defn{inlines the receiver} \tcode{rcvr} +if the lifetimes of all objects transitively constructed from +\tcode{rcvr} during the evaluation of $E$ +end within the evaluation of $E$. +\begin{note} +This means such an expression does not store the receiver in the operation state. +\end{note} + +\pnum +Let $E$ be some well-formed expression \tcode{connect(sndr, rcvr)} where +\begin{itemize} +\item +\tcode{sndr} denotes a sender type defined by this document and +\item +$E$ inlines the receiver \tcode{rcvr}. +\end{itemize} +Then, let \tcode{op} be the result of the evaluation of $E$, and +wherever the specification of the operation associated with \tcode{op} +contains a glvalue +which would denote an object transitively constructed from \tcode{rcvr}, +that glvalue instead denotes the result of applying +the temporary materialization conversion to the expression +\tcode{remove_cvref_t::make_receiver_for(addressof(op))}. + +\pnum +Let \tcode{StdRcvr} be a receiver type defined by this document. +Given some operation state type \tcode{Op}, +it is unspecified +whether \tcode{StdRcvr} models \tcode{\libconcept{inlinable_receiver}}. + +\pnum +Let \tcode{StdOp} be some operation state type defined by this document, +and let \tcode{Sndr} and \tcode{Rcvr} be types such that +\tcode{is_same_v, StdOp>} is \tcode{true}. +If \tcode{Rcvr} models \tcode{\libconcept{inlinable_receiver}} +then it is implementation-defined whether, +given an object \tcode{rcvr} of type \tcode{Rcvr}, +the \tcode{connect} operation which produces an object of type \tcode{StdOp} +inlines the receiver \tcode{rcvr}. + \rSec2[exec.set.value]{\tcode{execution::set_value}} \pnum @@ -1238,6 +1520,9 @@ Otherwise, it is expression-equivalent to \tcode{\exposid{MANDATE-NOTHROW}(rcvr.set_value(vs...))}. +\mandates +If the expression above is well-formed, its type is \tcode{void}. + \rSec2[exec.set.error]{\tcode{execution::set_error}} \pnum @@ -1249,6 +1534,9 @@ Otherwise, it is expression-equivalent to \tcode{\exposid{MANDATE-NOTHROW}(rcvr.set_error(err))}. +\mandates +If the expression above is well-formed, its type is \tcode{void}. + \rSec2[exec.set.stopped]{\tcode{execution::set_stopped}} \pnum @@ -1260,6 +1548,9 @@ Otherwise, it is expression-equivalent to \tcode{\exposid{MANDATE-NOTHROW}(rcvr.set_stopped())}. +\mandates +If the expression above is well-formed, its type is \tcode{void}. + \rSec1[exec.opstate]{Operation states} \rSec2[exec.opstate.general]{General} @@ -1271,7 +1562,7 @@ namespace std::execution { template concept @\deflibconcept{operation_state}@ = - @\libconcept{derived_from}@ && + @\libconcept{derived_from}@ && requires (O& o) { start(o); }; @@ -1307,6 +1598,9 @@ Otherwise, it is expression-equivalent to \tcode{\exposid{MANDATE-NOTHROW}(op.start())}. +\mandates +If the expression above is well-formed, its type is \tcode{void}. + \pnum If \tcode{op.start()} does not start\iref{exec.async.ops} the asynchronous operation associated with the operation state \tcode{op}, @@ -1325,13 +1619,15 @@ let \tcode{Sndr} be \tcode{decltype((sndr))}. Let \tcode{rcvr} be a receiver of type \tcode{Rcvr} with associated environment \tcode{env} of type \tcode{Env} -such that \tcode{\libconcept{sender_to}} is \tcode{true}. +such that \tcode{\exposconcept{sender-to}} is \tcode{true}. For the default implementation of the algorithm that produced \tcode{sndr}, connecting \tcode{sndr} to \tcode{rcvr} and starting the resulting operation state\iref{exec.async.ops} necessarily results in the potential evaluation\iref{basic.def.odr} of a set of completion operations whose first argument is a subexpression equal to \tcode{rcvr}. + +\pnum Let \tcode{Sigs} be a pack of completion signatures corresponding to this set of completion operations, and let \tcode{CS} be @@ -1343,6 +1639,57 @@ If none of the types in \tcode{Sigs} are dependent on the type \tcode{Env}, then the expression \tcode{get_completion_signatures()} is well-formed and its type is \tcode{CS}. + +\pnum +Each completion operation can potentially be evaluated +on one of several different execution agents +as determined by the semantics of the algorithm, +the environment of the receiver, and +the completions of any child senders. +For a completion tag \tcode{T}, +let $\tcode{Ds}_{\tcode{T}}$ be a pack comprised of the set of domain tags +associated with the execution agents that could potentially evaluate +any of the operation's completions with tag \tcode{T}. +If there are no potentially evaluated completion operations +with tag type \tcode{T}, +then \tcode{get_completion_domain(get_env(sndr), env)} is ill-formed; +otherwise, it has type +\tcode{\exposid{COMMON-DOMAIN}<$\tcode{Ds}_{\tcode{T}}$...>}\iref{exec.snd.expos}. +\begin{example} +Let \tcode{sndr2} be the sender \tcode{then(sndr, fn)}. +\tcode{sndr2} has the same \tcode{set_value} completion domain tag as \tcode{sndr}, +but if \tcode{fn}'s evaluation is potentially throwing, +\tcode{sndr}'s \tcode{set_error} completion domain tag would be +the \exposid{COMMON-DOMAIN} of \tcode{sndr}'s value and error completion domain tags, +in accordance with the semantics of the \tcode{then} algorithm\iref{exec.then}. +\end{example} + +\pnum +If \tcode{sndr} can determine that all of its completion operations +with tag \tcode{T} happen on execution agents +associated with a particular scheduler \tcode{sch} +(as determined by the semantics of the algorithm, +the environment of the receiver, and +the completion schedulers of any child senders), +then \tcode{get_completion_scheduler(get_env(sndr), env)} +is well-formed and has the type and value of \tcode{sch}; +otherwise, it is ill-formed. +\begin{example} +Let \tcode{sndr2} be the sender from the example above. +The \tcode{set_value} completion scheduler of \tcode{sndr2} is +the \tcode{set_value} completion scheduler of \tcode{sndr}, if any. +But \tcode{sndr2} can only report a \tcode{set_error} completion scheduler +when invocations of \tcode{fn} are not potentially throwing or +when \tcode{sndr} has no \tcode{set_error} completions. +When \tcode{fn} can throw, +\tcode{sndr2} could complete with \tcode{set_error} either +by forwarding an error completion from \tcode{sndr} or +by completing with the exception thrown by \tcode{fn}, +which would happen on an agent associated with \tcode{sndr}'s +\tcode{set_value} completion scheduler. +\end{example} + +\pnum If a user-provided implementation of the algorithm that produced \tcode{sndr} is selected instead of the default: @@ -1376,6 +1723,26 @@ \rSec2[exec.snd.expos]{Exposition-only entities} +\pnum +Given an expression \tcode{sndr}, +whose type is any sender type defined in the standard library, +it is unspecified +whether the expression \tcode{sndr.affine()} is well-formed. +If that expression is well-formed, +then the evaluation thereof meets the semantic requirements of +the \tcode{affine}\iref{exec.affine} algorithm. + +\pnum +Given an expression \tcode{sndr}, +whose type is any sender type defined in the standard library, +and an expression \tcode{p}, +whose type is a promise type, +it is unspecified +whether the expression \tcode{sndr.as_awaitable(p)} is well-formed. +If that expression is well-formed, +then the evaluation thereof meets the semantic requirements of +the \tcode{as_awaitable}\iref{exec.as.awaitable} algorithm. + \pnum Subclause \ref{exec.snd} makes use of the following exposition-only entities. @@ -1394,13 +1761,15 @@ \tcode{decltype(\exposid{FWD-ENV}(declval()))}. \pnum -For a query object \tcode{q} and a subexpression \tcode{v}, +For a query object \tcode{q}, +a subexpression \tcode{v}, and +a pack of subexpressions \tcode{args}, \tcode{\exposid{MAKE-ENV}(q, v)} is an expression \tcode{env} whose type satisfies \exposconcept{queryable} -such that the result of \tcode{env.query(q)} has +such that the result of \tcode{env.query(q, args...)} has a value equal to \tcode{v}\iref{concepts.equality}. Unless otherwise stated, -the object to which \tcode{env.query(q)} refers remains valid +the object to which \tcode{env.query(q, args...)} refers remains valid while \tcode{env} remains valid. \pnum @@ -1426,20 +1795,31 @@ with different types and value categories in different contexts for the same arguments. +\pnum +For a pack of subexpressions \tcode{domains}, +\tcode{\exposid{COMMON-DOMAIN}(domains...)} is expression-equivalent to +\tcode{common_type_t()} +if that expression is well-formed, and +\tcode{indeterminate_domain<\brk{}Ds...>()} otherwise, +where \tcode{Ds} is the pack of types consisting of +\tcode{decltype(auto(domains))...} with duplicate types removed. + +\pnum +For a type \tcode{Tag}, subexpression \tcode{sndr}, and pack \tcode{envs}, +\tcode{\exposid{COMPL-DOMAIN}(Tag, sndr, envs)} +is expression-equivalent to \tcode{D()}, +where \tcode{D} is +the type of \tcode{get_completion_domain(get_env(sndr), envs...)} +if that expression is well-formed or \tcode{envs} is an empty pack, and +\tcode{indeterminate_domain()} otherwise. + \pnum For a scheduler \tcode{sch}, -\tcode{\exposid{SCHED-ATTRS}(sch)} is an expression \tcode{o1} -whose type satisfies \exposconcept{queryable} -such that \tcode{o1.query(get_completion_scheduler)} is -an expression with the same type and value as \tcode{sch} -where \tcode{Tag} is one of \tcode{set_value_t} or \tcode{set_stopped_t}, and -such that \tcode{o1.query(get_domain)} is expression-equivalent to -\tcode{sch.query(get_domain)}. -\tcode{\exposid{SCHED-ENV}(sch)} is an expression \tcode{o2} +\tcode{\exposid{SCHED-ENV}(sch)} is an expression \tcode{o} whose type satisfies \exposconcept{queryable} -such that \tcode{o2.query(get_scheduler)} is a prvalue +such that \tcode{o.query(\brk{}get_start_scheduler)} is a prvalue with the same type and value as \tcode{sch}, and -such that \tcode{o2.query(get_domain)} is expression-equivalent to +such that \tcode{o.query(get_domain)} is expression-equivalent to \tcode{sch.query(get_domain)}. \pnum @@ -1463,31 +1843,6 @@ \end{codeblock} except that \tcode{rcvr} is evaluated only once. -\begin{itemdecl} -template - constexpr auto @\exposid{completion-domain}@(const Sndr& sndr) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\tcode{\exposid{COMPL-DOMAIN}(T)} is the type of the expression -\tcode{get_domain(get_completion_scheduler(get_env(sndr)))}. - -\pnum -\effects -If all of the types -\tcode{\exposid{COMPL-DOMAIN}(set_value_t)}, -\tcode{\exposid{COMPL-DOMAIN}(set_error_t)}, and\linebreak -\tcode{\exposid{COMPL-DOMAIN}(set_stopped_t)} are ill-formed, -\tcode{completion-domain(sndr)} is -a default-constructed prvalue of type \tcode{Default}. -Otherwise, if they all share a common type\iref{meta.trans.other} -(ignoring those types that are ill-formed), -then \tcode{\exposid{completion-domain}(sndr)} is -a default-constructed prvalue of that type. -Otherwise, \tcode{\exposid{completion-domain}(sndr)} is ill-formed. -\end{itemdescr} - \begin{itemdecl} template constexpr decltype(auto) @\exposid{query-with-default}@( @@ -1509,77 +1864,6 @@ The expression in the noexcept clause is \tcode{noexcept(e)}. \end{itemdescr} -\begin{itemdecl} -template - constexpr auto @\exposid{get-domain-early}@(const Sndr& sndr) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -return Domain(); -\end{codeblock} -where \tcode{Domain} is -the decayed type of the first of the following expressions that is well-formed: -\begin{itemize} -\item \tcode{get_domain(get_env(sndr))} -\item \tcode{\exposid{completion-domain}(sndr)} -\item \tcode{default_domain()} -\end{itemize} -\end{itemdescr} - -\begin{itemdecl} -template - constexpr auto @\exposid{get-domain-late}@(const Sndr& sndr, const Env& env) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{itemize} -\item -If \tcode{\exposconcept{sender-for}} is \tcode{true}, then -\begin{codeblock} -return Domain(); -\end{codeblock} -where \tcode{Domain} is the type of the following expression: -\begin{codeblock} -[] { - auto [_, sch, _] = sndr; - return @\exposid{query-with-default}@(get_domain, sch, default_domain()); -}(); -\end{codeblock} -\begin{note} -The \tcode{continues_on} algorithm works -in tandem with \tcode{schedule_from}\iref{exec.schedule.from} -to give scheduler authors a way to customize both -how to transition onto (\tcode{continues_on}) and off of (\tcode{schedule_from}) -a given execution context. -Thus, \tcode{continues_on} ignores the domain of the predecessor and -uses the domain of the destination scheduler to select a customization, -a property that is unique to \tcode{continues_on}. -That is why it is given special treatment here. -\end{note} -\item -Otherwise, -\begin{codeblock} -return Domain(); -\end{codeblock} -where \tcode{Domain} is the first of the following expressions -that is well-formed and whose type is not \tcode{void}: -\begin{itemize} -\item \tcode{get_domain(get_env(sndr))} -\item \tcode{\exposid{completion-domain}(sndr)} -\item \tcode{get_domain(env)} -\item \tcode{get_domain(get_scheduler(env))} -\item \tcode{default_domain()} -\end{itemize} -\end{itemize} -\end{itemdescr} - \pnum \begin{codeblock} template<@\exposconcept{callable}@ Fun> @@ -1732,26 +2016,9 @@ that models \libconcept{semiregular}. \end{itemdescr} +\pnum \begin{codeblock} namespace std::execution { - template - concept @\defexposconceptnc{completion-tag}@ = // \expos - @\libconcept{same_as}@ || @\libconcept{same_as}@ || @\libconcept{same_as}@; - - struct @\exposidnc{default-impls}@ { // \expos - static constexpr auto @\exposidnc{get-attrs}@ = @\seebelownc@; // \expos - static constexpr auto @\exposidnc{get-env}@ = @\seebelownc@; // \expos - static constexpr auto @\exposidnc{get-state}@ = @\seebelownc@; // \expos - static constexpr auto @\exposidnc{start}@ = @\seebelownc@; // \expos - static constexpr auto @\exposidnc{complete}@ = @\seebelownc@; // \expos - - template - static consteval void @\exposidnc{check-types}@(); // \expos - }; - - template - struct @\exposidnc{impls-for}@ : @\exposidnc{default-impls}@ {}; // \expos - template // \expos using @\exposid{state-type}@ = decay_t<@\exposid{call-result-t}@< decltype(@\exposid{impls-for}@>::@\exposid{get-state}@), Sndr, Rcvr&>>; @@ -1779,30 +2046,46 @@ Rcvr @\exposidnc{rcvr}@; // \expos @\exposidnc{state-type}@ @\exposidnc{state}@; // \expos }; +} +\end{codeblock} +\pnum +The expression in the \tcode{noexcept} clause of +the constructor of \exposid{basic-state} is +\begin{codeblock} +is_nothrow_move_constructible_v && +@\exposconcept{nothrow-callable}@>::@\exposid{get-state}@), Sndr, Rcvr&> && +(@\libconcept{same_as}@<@\exposid{state-type}@, @\exposid{get-state-result}@> || + is_nothrow_constructible_v<@\exposid{state-type}@, @\exposid{get-state-result}@>) +\end{codeblock} +where \exposid{get-state-result} is +\begin{codeblock} +@\exposid{call-result-t}@>::@\exposid{get-state}@), Sndr, Rcvr&>. +\end{codeblock} + +\pnum +\begin{codeblock} +namespace std::execution { template requires @\exposconcept{valid-specialization}@<@\exposid{env-type}@, Index, Sndr, Rcvr> struct @\exposidnc{basic-receiver}@ { // \expos - using receiver_concept = receiver_t; + using receiver_concept = receiver_tag; using @\exposidnc{tag-t}@ = tag_of_t; // \expos using @\exposidnc{state-t}@ = @\exposidnc{state-type}@; // \expos static constexpr const auto& @\exposidnc{complete}@ = @\exposidnc{impls-for}@<@\exposidnc{tag-t}@>::@\exposidnc{complete}@; // \expos template - requires @\exposconcept{callable}@ void set_value(Args&&... args) && noexcept { @\exposid{complete}@(Index(), @\exposidnc{op}@->@\exposid{state}@, @\exposidnc{op}@->@\exposid{rcvr}@, set_value_t(), std::forward(args)...); } template - requires @\exposconcept{callable}@ void set_error(Error&& err) && noexcept { @\exposid{complete}@(Index(), @\exposidnc{op}@->@\exposid{state}@, @\exposidnc{op}@->@\exposid{rcvr}@, set_error_t(), std::forward(err)); } void set_stopped() && noexcept - requires @\exposconcept{callable}@ { @\exposid{complete}@(Index(), @\exposidnc{op}@->@\exposid{state}@, @\exposidnc{op}@->@\exposid{rcvr}@, set_stopped_t()); } @@ -1812,77 +2095,19 @@ @\exposidnc{basic-state}@* @\exposidnc{op}@; // \expos }; +} +\end{codeblock} +\begin{codeblock} +namespace std::execution { constexpr auto @\exposidnc{connect-all}@ = @\seebelownc@; // \expos template using @\exposidnc{connect-all-result}@ = @\exposidnc{call-result-t}@< // \expos decltype(@\exposid{connect-all}@), @\exposid{basic-state}@*, Sndr, @\exposid{indices-for}@>; - - template - requires @\exposconcept{valid-specialization}@<@\exposid{state-type}@, Sndr, Rcvr> && - @\exposconcept{valid-specialization}@<@\exposid{connect-all-result}@, Sndr, Rcvr> - struct @\exposidnc{basic-operation}@ : @\exposidnc{basic-state}@ { // \expos - using operation_state_concept = operation_state_t; - using @\exposidnc{tag-t}@ = tag_of_t; // \expos - - @\exposidnc{connect-all-result}@ @\exposidnc{inner-ops}@; // \expos - - @\exposidnc{basic-operation}@(Sndr&& sndr, Rcvr&& rcvr) noexcept(@\seebelownc@) // \expos - : @\exposid{basic-state}@(std::forward(sndr), std::move(rcvr)), - @\exposid{inner-ops}@(@\exposid{connect-all}@(this, std::forward(sndr), @\exposid{indices-for}@())) - {} - - void start() & noexcept { - auto& [...ops] = @\exposid{inner-ops}@; - @\exposid{impls-for}@<@\exposid{tag-t}@>::@\exposid{start}@(this->@\exposid{state}@, this->@\exposid{rcvr}@, ops...); - } - }; - - template - struct @\exposidnc{basic-sender}@ : @\exposidnc{product-type}@ { // \expos - using sender_concept = sender_t; - using @\exposidnc{indices-for}@ = index_sequence_for; // \expos - - decltype(auto) get_env() const noexcept { - auto& [_, data, ...child] = *this; - return @\exposid{impls-for}@::@\exposid{get-attrs}@(data, child...); - } - - template<@\exposconcept{decays-to}@<@\exposid{basic-sender}@> Self, @\libconcept{receiver}@ Rcvr> - auto connect(this Self&& self, Rcvr rcvr) noexcept(@\seebelow@) - -> @\exposid{basic-operation}@ { - return {std::forward(self), std::move(rcvr)}; - } - - template<@\exposconcept{decays-to}@<@\exposid{basic-sender}@> Self, class... Env> - static constexpr auto get_completion_signatures(); - }; } \end{codeblock} -\pnum -It is unspecified whether a specialization of \exposid{basic-sender} -is an aggregate. - -\pnum -An expression of type \exposid{basic-sender} is usable as -the initializer of a structured binding declaration\iref{dcl.struct.bind}. - -\pnum -The expression in the \tcode{noexcept} clause of -the constructor of \exposid{basic-state} is -\begin{codeblock} -is_nothrow_move_constructible_v && -@\exposconcept{nothrow-callable}@>::@\exposid{get-state}@), Sndr, Rcvr&> && -(@\libconcept{same_as}@<@\exposid{state-type}@, @\exposid{get-state-result}@> || - is_nothrow_constructible_v<@\exposid{state-type}@, @\exposid{get-state-result}@>) -\end{codeblock} -where \exposid{get-state-result} is -\begin{codeblock} -@\exposid{call-result-t}@>::@\exposid{get-state}@), Sndr, Rcvr&>. -\end{codeblock} - \pnum The object \exposid{connect-all} is initialized with a callable object equivalent to the following lambda: @@ -1897,17 +2122,42 @@ } \end{itemdecl} -\begin{itemdescr} -\pnum -\constraints -The expression in the \tcode{return} statement is well-formed. +\begin{itemdescr} +\pnum +\constraints +The expression in the \tcode{return} statement is well-formed. + +\pnum +\remarks +The expression in the \tcode{noexcept} clause is \tcode{true} +if the \tcode{return} statement is not potentially throwing; +otherwise, \tcode{false}. +\end{itemdescr} + +\pnum +\begin{codeblock} +namespace std::execution { + template + requires @\exposconcept{valid-specialization}@<@\exposid{state-type}@, Sndr, Rcvr> && + @\exposconcept{valid-specialization}@<@\exposid{connect-all-result}@, Sndr, Rcvr> + struct @\exposidnc{basic-operation}@ : @\exposidnc{basic-state}@ { // \expos + using operation_state_concept = operation_state_tag; + using @\exposidnc{tag-t}@ = tag_of_t; // \expos + + @\exposidnc{connect-all-result}@ @\exposidnc{inner-ops}@; // \expos -\pnum -\remarks -The expression in the \tcode{noexcept} clause is \tcode{true} -if the \tcode{return} statement is not potentially throwing; -otherwise, \tcode{false}. -\end{itemdescr} + @\exposidnc{basic-operation}@(Sndr&& sndr, Rcvr&& rcvr) noexcept(@\seebelownc@) // \expos + : @\exposid{basic-state}@(std::forward(sndr), std::move(rcvr)), + @\exposid{inner-ops}@(@\exposid{connect-all}@(this, std::forward(sndr), @\exposid{indices-for}@())) + {} + + void start() & noexcept { + auto& [...ops] = @\exposid{inner-ops}@; + @\exposid{impls-for}@<@\exposid{tag-t}@>::@\exposid{start}@(this->@\exposid{state}@, this->@\exposid{rcvr}@, ops...); + } + }; +} +\end{codeblock} \pnum The expression in the \tcode{noexcept} clause of @@ -1918,21 +2168,20 @@ \end{codeblock} \pnum -The expression in the \tcode{noexcept} clause of -the \tcode{connect} member function of \exposid{basic-sender} is: \begin{codeblock} -is_nothrow_constructible_v<@\exposid{basic-operation}@, Self, Rcvr> -\end{codeblock} +namespace std::execution { + struct @\exposidnc{default-impls}@ { // \expos + static constexpr auto @\exposidnc{get-env}@ = @\seebelownc@; // \expos + static constexpr auto @\exposidnc{get-state}@ = @\seebelownc@; // \expos + static constexpr auto @\exposidnc{start}@ = @\seebelownc@; // \expos + static constexpr auto @\exposidnc{complete}@ = @\seebelownc@; // \expos -\pnum -The member \tcode{\exposid{default-impls}::\exposid{get-attrs}} -is initialized with a callable object equivalent to the following lambda: -\begin{codeblock} -[](const auto&, const auto&... child) noexcept -> decltype(auto) { - if constexpr (sizeof...(child) == 1) - return (@\exposid{FWD-ENV}@(get_env(child)), ...); - else - return env<>(); + template + static consteval void @\exposidnc{check-types}@(); // \expos + }; + + template + struct @\exposidnc{impls-for}@ : @\exposidnc{default-impls}@ {}; // \expos } \end{codeblock} @@ -2011,6 +2260,46 @@ \end{note} \end{itemdescr} +\pnum +\begin{codeblock} +namespace std::execution { + template + struct @\exposidnc{basic-sender}@ : @\exposidnc{product-type}@ { // \expos + using sender_concept = sender_tag; + using @\exposidnc{indices-for}@ = index_sequence_for; // \expos + + decltype(auto) get_env() const noexcept { + auto& [_, data, ...child] = *this; + return @\exposid{impls-for}@::@\exposid{get-attrs}@(data, child...); + } + + template<@\exposconcept{decays-to}@<@\exposid{basic-sender}@> Self, @\libconcept{receiver}@ Rcvr> + auto connect(this Self&& self, Rcvr rcvr) noexcept(@\seebelow@) + -> @\exposid{basic-operation}@ { + return {std::forward(self), std::move(rcvr)}; + } + + template<@\exposconcept{decays-to}@<@\exposid{basic-sender}@> Self, class... Env> + static constexpr auto get_completion_signatures(); + }; +} +\end{codeblock} + +\pnum +It is unspecified whether a specialization of \exposid{basic-sender} +is an aggregate. + +\pnum +An expression of type \exposid{basic-sender} is usable as +the initializer of a structured binding declaration\iref{dcl.struct.bind}. + +\pnum +The expression in the \tcode{noexcept} clause of +the \tcode{connect} member function of \exposid{basic-sender} is: +\begin{codeblock} +is_nothrow_constructible_v<@\exposid{basic-operation}@, Self, Rcvr> +\end{codeblock} + \indexlibrarymember{get_completion_signatures}{\exposid{basic-sender}}% \begin{itemdecl} template @@ -2071,7 +2360,7 @@ %%FIXME: Should this be in a namespace? \begin{codeblock} struct @\exposid{not-a-sender}@ { - using sender_concept = sender_t; + using sender_concept = sender_tag; template static consteval auto get_completion_signatures() -> completion_signatures<> { @@ -2080,6 +2369,19 @@ }; \end{codeblock} +\pnum +\indexlibraryglobal{\exposid{not-a-scheduler}}% +\indexlibrarymember{schedule}{\exposid{not-a-sender}}% +\begin{codeblock} +struct @\exposid{not-a-scheduler}@ { + using scheduler_concept = scheduler_tag; + + constexpr auto schedule() const noexcept { + return @\exposid{not-a-sender}@(); + } +}; +\end{codeblock} + \pnum \indexlibraryglobal{\exposid{decay-copyable-result-datums}} %%FIXME: Should this be in a namespace? @@ -2117,14 +2419,56 @@ otherwise if \tcode{P} is a specialization of \exposid{product-type}, returns an object of type \tcode{P} whose elements are initialized using \begin{codeblock} -make_obj_using_allocator(std::forward_like(e), @\exposid{alloc}@) +make_obj_using_allocator(@\exposid{alloc}@, std::forward_like(e)) \end{codeblock} where \tcode{e} is the corresponding element of \tcode{obj}, \item -otherwise, returns \tcode{make_obj_using_allocator

(std::forward(obj), \exposid{alloc})}. +otherwise, returns \tcode{make_obj_using_allocator

(\exposid{alloc}, std::forward(obj))}. \end{itemize} \end{itemdescr} +\indexlibraryglobal{\exposid{call-with-default}} +\begin{itemdecl} +template + constexpr decltype(auto) @\exposid{call-with-default}@( + Fn&& fn, Default&& value, Args&&... args) noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{expr} be the expression +\tcode{std::forward(fn)(std::forward(args)...)} +if that expression is well-formed; +otherwise, it is \tcode{static_cast(std::forward(value))}. + +\pnum +\returns +\tcode{expr}. + +\pnum +\remarks +The expression in the \tcode{noexcept} clause is \tcode{noexcept(expr)}. +\end{itemdescr} + +\pnum +\indexlibraryglobal{\exposid{inline-attrs}}% +\begin{codeblock} +template +struct @\exposid{inline-attrs}@ { + @\seebelow@ +}; +\end{codeblock} + +\pnum +For a subexpression \tcode{env}, +\tcode{\exposid{inline-attrs}{}.query(get_completion_scheduler, env)} +is expres\-sion-equivalent to \tcode{get_scheduler(env)}. + +\pnum +For a subexpression \tcode{env}, +\tcode{\exposid{inline-attrs}{}.query(get_completion_domain, env)} +is expression-equivalent to \tcode{get_domain(env)}. + \rSec2[exec.snd.concepts]{Sender concepts} \pnum @@ -2133,7 +2477,7 @@ The \libconcept{sender_in} concept defines the requirements for a sender type that can create asynchronous operations given an associated environment type. -The \libconcept{sender_to} concept defines +The exposition-only concept \exposconcept{sender-to} defines the requirements for a sender type that can connect with a specific receiver type. The \tcode{get_env} customization point object is used to access @@ -2149,7 +2493,7 @@ template concept @\defexposconcept{is-sender}@ = // \expos - @\libconcept{derived_from}@; + @\libconcept{derived_from}@; template concept @\defexposconcept{enable-sender}@ = // \expos @@ -2188,9 +2532,9 @@ @\libconcept{sender}@ && bool_constant<@\exposid{is-dependent-sender-helper}@()>::value; template - concept @\deflibconcept{sender_to}@ = + concept @\defexposconcept{sender-to}@ = @\libconcept{sender_in}@> && - @\libconcept{receiver_of}@>> && + @\exposconcept{receiver-of}@>> && requires (Sndr&& sndr, Rcvr&& rcvr) { connect(std::forward(sndr), std::forward(rcvr)); }; @@ -2226,7 +2570,7 @@ model \libconcept{sender}, and \tcode{false} for types that do not. Such specializations shall -be usable in constant expressions\iref{expr.const} and +be usable in constant expressions\iref{expr.const.init} and have type \tcode{const bool}. \pnum @@ -2423,75 +2767,103 @@ its members need not be defined. \end{note} -\rSec2[exec.domain.default]{\tcode{execution::default_domain}} +\rSec2[exec.domain.indeterminate]{\tcode{execution::indeterminate_domain}} \pnum +\indexlibraryglobal{indeterminate_domain}% +\indexlibraryctor{indeterminate_domain}% \begin{codeblock} namespace std::execution { - struct @\libglobal{default_domain}@ { - template<@\libconcept{sender}@ Sndr, @\exposconcept{queryable}@... Env> - requires (sizeof...(Env) <= 1) - static constexpr @\libconcept{sender}@ decltype(auto) transform_sender(Sndr&& sndr, const Env&... env) - noexcept(@\seebelow@); - - template<@\libconcept{sender}@ Sndr, @\exposconcept{queryable}@ Env> - static constexpr @\exposconcept{queryable}@ decltype(auto) transform_env(Sndr&& sndr, Env&& env) noexcept; + template + struct indeterminate_domain { + indeterminate_domain() = default; + constexpr indeterminate_domain(auto&&) noexcept {} - template - static constexpr decltype(auto) apply_sender(Tag, Sndr&& sndr, Args&&... args) + template + static constexpr decltype(auto) transform_sender(Tag, Sndr&& sndr, const Env& env) noexcept(@\seebelow@); }; } \end{codeblock} -\indexlibrarymember{transform_sender}{default_domain}% +\indexlibrarymember{transform_sender}{indeterminate_domain}% \begin{itemdecl} -template<@\libconcept{sender}@ Sndr, @\exposconcept{queryable}@... Env> - requires (sizeof...(Env) <= 1) -constexpr @\libconcept{sender}@ decltype(auto) transform_sender(Sndr&& sndr, const Env&... env) - noexcept(@\seebelow@); +template + static constexpr decltype(auto) transform_sender(Tag, Sndr&& sndr, const Env& env) + noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} \pnum -Let \tcode{e} be the expression +\mandates +For each type \tcode{D} in \tcode{Domains...}, +the expression \begin{codeblock} -tag_of_t().transform_sender(std::forward(sndr), env...) +D().transform_sender(Tag(), std::forward(sndr), env) \end{codeblock} -if that expression is well-formed; -otherwise, \tcode{std::forward(sndr)}. +is either ill-formed or has the same decayed type as +\tcode{default_domain().transform_sender(Tag(), std::forward(sndr), env)}. \pnum \returns -\tcode{e}. +\tcode{default_domain().transform_sender(Tag(), std::forward(sndr), env)}. \pnum \remarks -The exception specification is equivalent to \tcode{noexcept(e)}. +For a pack of types \tcode{Ds}, +\begin{codeblock} +common_type_t, indeterminate_domain> +\end{codeblock} +is \tcode{indeterminate_domain} +where \tcode{Us} is a pack that contains each type in +\tcode{Domains..., Ds...} except with duplicate types removed. +For a type \tcode{D} that is not a specialization of \tcode{indeterminate_domain}, +\tcode{common_type_t, D>} +is \tcode{D} if \tcode{Domains} is an empty pack, and +\tcode{common_type_t, indeterminate_domain>} +otherwise. \end{itemdescr} -\indexlibrarymember{transform_env}{default_domain}% +\rSec2[exec.domain.default]{\tcode{execution::default_domain}} + +\pnum +\begin{codeblock} +namespace std::execution { + struct @\libglobal{default_domain}@ { + template + static constexpr decltype(auto) transform_sender(Tag, Sndr&& sndr, const Env& env) + noexcept(@\seebelow@); + + template + static constexpr decltype(auto) apply_sender(Tag, Sndr&& sndr, Args&&... args) + noexcept(@\seebelow@); + }; +} +\end{codeblock} + +\indexlibrarymember{transform_sender}{default_domain}% \begin{itemdecl} -template<@\libconcept{sender}@ Sndr, @\exposconcept{queryable}@ Env> - constexpr @\exposconcept{queryable}@ decltype(auto) transform_env(Sndr&& sndr, Env&& env) noexcept; +template +constexpr @\libconcept{sender}@ decltype(auto) transform_sender(Tag, Sndr&& sndr, const Env& env) + noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} \pnum Let \tcode{e} be the expression \begin{codeblock} -tag_of_t().transform_env(std::forward(sndr), std::forward(env)) +tag_of_t().transform_sender(Tag(), std::forward(sndr), env) \end{codeblock} if that expression is well-formed; -otherwise, \tcode{\exposid{FWD-ENV}(std::forward(env))}. - -\pnum -\mandates -\tcode{noexcept(e)} is \tcode{true}. +otherwise, \tcode{static_cast(std::forward(sndr))}. \pnum \returns \tcode{e}. + +\pnum +\remarks +The exception specification is equivalent to \tcode{noexcept(e)}. \end{itemdescr} \indexlibrarymember{apply_sender}{default_domain}% @@ -2526,67 +2898,63 @@ \indexlibraryglobal{transform_sender}% \begin{itemdecl} namespace std::execution { - template - requires (sizeof...(Env) <= 1) - constexpr @\libconcept{sender}@ decltype(auto) transform_sender(Domain dom, Sndr&& sndr, const Env&... env) + template<@\libconcept{sender}@ Sndr, @\exposconcept{queryable}@ Env> + constexpr decltype(auto) transform_sender(Sndr&& sndr, const Env& env) noexcept(@\seebelow@); } \end{itemdecl} \begin{itemdescr} \pnum -Let \exposid{transformed-sndr} be the expression +For a subexpression \tcode{s}, +let \exposid{start-domain} be +\tcode{D()} where \tcode{D} is the decayed type of \tcode{get_domain(env)} +if that expression is well-formed, and +\tcode{default_domain} otherwise. + +\pnum +Let \tcode{\exposid{completion-domain}(s)} be +\tcode{D()} where \tcode{D} is the decayed type of +\tcode{get_completion_domain<>(get_env(s), env)} +if that is well-formed; +otherwise, \tcode{D} is \tcode{default_domain}. + +\pnum +Let \tcode{\exposid{transformed-sndr}(dom, tag, s)} be the expression \begin{codeblock} -dom.transform_sender(std::forward(sndr), env...) +dom.transform_sender(tag, s, env) \end{codeblock} if that expression is well-formed; otherwise, \begin{codeblock} -default_domain().transform_sender(std::forward(sndr), env...) +default_domain().transform_sender(tag, s, env) \end{codeblock} -Let \exposid{final-sndr} be the expression \exposid{transformed-sndr} -if \exposid{transformed-sndr} and \exposid{sndr} +Let \tcode{\exposid{transform-recurse}(dom, tag, s)} be +the expression \tcode{\exposid{transformed-sndr}(dom, tag, s)} +if\newline \tcode{\exposid{transformed-sndr}(dom, tag, s)} and \exposid{s} have the same type ignoring cv-qualifiers; otherwise, it is -the expression \tcode{transform_sender(dom, \exposid{transformed-sndr}, env...)}. - -\pnum -\returns -\exposid{final-sndr}. - -\pnum -\remarks -The exception specification is equivalent to -\tcode{noexcept(\exposid{final-sndr})}. -\end{itemdescr} +the expression \tcode{\exposid{transform-recurse}(dom2, tag2, s2)}, where +\tcode{s2} is \tcode{\exposid{transformed-sender}(dom, tag, s)} and +\tcode{dom2} is \exposid{start-domain} if \tcode{tag} is \tcode{start}, and +\tcode{\exposid{completion-domain}(s2)} otherwise. -\rSec2[exec.snd.transform.env]{\tcode{execution::transform_env}} - -\indexlibraryglobal{transform_env}% -\begin{itemdecl} -namespace std::execution { - template - constexpr @\exposconcept{queryable}@ decltype(auto) transform_env(Domain dom, Sndr&& sndr, Env&& env) noexcept; -} -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{e} be the expression +Let \exposid{tmp-sndr} be the expression \begin{codeblock} -dom.transform_env(std::forward(sndr), std::forward(env)) +@\exposid{transform-recurse}@(@\exposid{completion-domain}@(sndr), set_value, sndr) \end{codeblock} -if that expression is well-formed; otherwise, +and let \exposid{final-sndr} be the expression \begin{codeblock} -default_domain().transform_env(std::forward(sndr), std::forward(env)) +@\exposid{transform-recurse}@(@\exposid{start-domain}@, start, @\exposid{tmp-sndr}@) \end{codeblock} \pnum -\mandates -\tcode{noexcept(e)} is \tcode{true}. +\returns +\exposid{final-sndr}. \pnum -\returns -\tcode{e}. +\remarks +The exception specification is equivalent to +\tcode{noexcept(\exposid{final-sndr})}. \end{itemdescr} \rSec2[exec.snd.apply]{\tcode{execution::apply_sender}} @@ -2655,7 +3023,6 @@ where $s$ is the following expression: \begin{codeblock} transform_sender( - @\exposid{get-domain-late}@(declval(), declval()...), declval(), declval()...) \end{codeblock} @@ -2711,7 +3078,8 @@ \tcode{completion_signatures_of_t} and \tcode{completion_signatures_of_t} are both well-formed, -they shall denote the same type. +the former shall be a superset of the latter, +with the difference corresponding to error or stopped completion operations. \pnum Let \tcode{rcvr} be an rvalue @@ -2743,9 +3111,7 @@ let \tcode{Sndr} be \tcode{decltype((sndr))} and \tcode{Rcvr} be \tcode{decltype((rcvr))}, let \tcode{new_sndr} be the expression -\begin{codeblock} -transform_sender(decltype(@\exposid{get-domain-late}@(sndr, get_env(rcvr))){}, sndr, get_env(rcvr)) -\end{codeblock} +\tcode{transform_sender(\newline sndr, get_env(rcvr))} and let \tcode{DS} and \tcode{DR} be \tcode{decay_t} and \tcode{decay_t}, respectively. @@ -2788,7 +3154,7 @@ \begin{codeblock} namespace std::execution { struct @\exposid{operation-state-task}@ { // \expos - using operation_state_concept = operation_state_t; + using operation_state_concept = operation_state_tag; using promise_type = @\exposid{connect-awaitable-promise}@; explicit @\exposid{operation-state-task}@(coroutine_handle<> h) noexcept : coro(h) {} @@ -2833,7 +3199,7 @@ return awaiter{fn}; } - @\exposid{operation-state-task}@ @\exposid{connect-awaitable}@(DS sndr, DR rcvr) requires @\libconcept{receiver_of}@ { + @\exposid{operation-state-task}@ @\exposid{connect-awaitable}@(DS sndr, DR rcvr) requires @\exposconcept{receiver-of}@ { exception_ptr ep; try { if constexpr (@\libconcept{same_as}@) { @@ -2885,7 +3251,7 @@ \item \tcode{\libconcept{sender_in}>} \item -\tcode{\libconcept{receiver_of}>>} +\tcode{\exposconcept{receiver-of}>>} \end{itemize} \rSec2[exec.factories]{Sender factories} @@ -2906,14 +3272,6 @@ \mandates The type of \tcode{sch.schedule()} satisfies \libconcept{sender}. -\pnum -If the expression -\begin{codeblock} -get_completion_scheduler(get_env(sch.schedule())) == sch -\end{codeblock} -is ill-formed or evaluates to \tcode{false}, -the behavior of calling \tcode{schedule(sch)} is undefined. - \rSec3[exec.just]{\tcode{execution::just}, \tcode{execution::just_error}, \tcode{execution::just_stopped}} \pnum @@ -3037,10 +3395,18 @@ \item A parent sender\iref{exec.async.ops} with a single child sender \tcode{sndr} has an associated attribute object equal to -\tcode{\exposid{FWD-ENV}(get_env(sndr))}\iref{exec.fwd.env}. +\tcode{\exposid{FWD-ENV}(get_env(sndr))}\iref{exec.fwd.env} +except that the +\tcode{get_completion_scheduler<\exposid{completion-tag}>} and +\tcode{get_completion_domain<\exposid{completion-tag}>} +queries are handled as described in \ref{exec.snd.general}. \item A parent sender with more than one child sender has -an associated attributes object equal to \tcode{env<>\{\}}. +an associated attributes object equal to \tcode{env<>\{\}} +except that the +\tcode{get_completion_scheduler<\exposid{completion-tag}>} and +\tcode{get_completion_domain<\exposid{comple\-tion-tag}>} +queries are handled as described in \ref{exec.snd.general}. \item When a parent sender is connected to a receiver \tcode{rcvr}, any receiver used to connect a child sender has @@ -3071,7 +3437,7 @@ \rSec3[exec.adapt.obj]{Closure objects} -\indexlibrarymisc{\idxcode{operator|}}{pipeable sender adaptor closure objects}% +\indexlibrarymisc{\idxcode{operator"|}}{pipeable sender adaptor closure objects}% \pnum A \defnadj{pipeable}{sender adaptor closure object} is a function object that accepts one or more \libconcept{sender} arguments and returns a \libconcept{sender}. @@ -3099,7 +3465,7 @@ direct-non-list-initialized with \tcode{c}. \item Its call pattern is \tcode{d2(c2(arg))}, -where arg is the argument used in a function call expression of \tcode{e}. +where \tcode{arg} is the argument used in a function call expression of \tcode{e}. \end{itemize} The expression \tcode{c | d} is well-formed if and only if the initializations of the state entities\iref{func.def} of \tcode{e} @@ -3256,38 +3622,24 @@ \pnum Otherwise, the expression \tcode{starts_on(sch, sndr)} is expression-equivalent to: -\begin{codeblock} -transform_sender( - @\exposid{query-with-default}@(get_domain, sch, default_domain()), - @\exposid{make-sender}@(starts_on, sch, sndr)) -\end{codeblock} -except that \tcode{sch} is evaluated only once. +\tcode{\exposid{make-sender}(starts_on, sch, sndr)}. \pnum Let \tcode{out_sndr} and \tcode{env} be subexpressions such that \tcode{OutSndr} is \tcode{decltype((out_sndr))}. If \tcode{\exposconcept{sender-for}} is \tcode{false}, -then the expressions \tcode{starts_on.transform_env(out_sndr, env)} and\linebreak -\tcode{starts_on.transform_sender(out_sndr, env)} are ill-formed; otherwise -\begin{itemize} -\item -\tcode{starts_on.transform_env(out_sndr, env)} is equivalent to: -\begin{codeblock} -auto&& [_, sch, _] = out_sndr; -return @\exposid{JOIN-ENV}@(@\exposid{SCHED-ENV}@(sch), @\exposid{FWD-ENV}@(env)); -\end{codeblock} -\item -\tcode{starts_on.transform_sender(out_sndr, env)} is equivalent to: +then the expression +\tcode{starts_on.transform_sender(set_value, out_sndr, env)} is ill-formed; otherwise +\tcode{starts_on.transform_sender(set_value, out_sndr, env)} is equivalent to: \begin{codeblock} auto&& [_, sch, sndr] = out_sndr; return let_value( - schedule(sch), + continues_on(just(), sch), [sndr = std::forward_like(sndr)]() mutable noexcept(is_nothrow_move_constructible_v>) { return std::move(sndr); }); \end{codeblock} -\end{itemize} \pnum Let \tcode{out_sndr} be a subexpression denoting @@ -3307,111 +3659,31 @@ \rSec3[exec.continues.on]{\tcode{execution::continues_on}} \pnum -\tcode{continues_on} adapts a sender into one -that completes on the specified scheduler. - -\pnum -The name \tcode{continues_on} denotes a pipeable sender adaptor object. -For subexpressions \tcode{sch} and \tcode{sndr}, -if \tcode{decltype((sch))} does not satisfy \libconcept{scheduler}, or -\tcode{decltype((sndr))} does not satisfy \libconcept{sender}, -\tcode{continues_on(sndr, sch)} is ill-formed. - -\pnum -Otherwise, -the expression \tcode{continues_on(sndr, sch)} is expression-equivalent to: -\begin{codeblock} -transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(continues_on, sch, sndr)) -\end{codeblock} -except that \tcode{sndr} is evaluated only once. - -\pnum -The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos} -is specialized for \tcode{continues_on_t} as follows: -\begin{codeblock} -namespace std::execution { - template<> - struct @\exposid{impls-for}@ : @\exposid{default-impls}@ { - static constexpr auto @\exposid{get-attrs}@ = - [](const auto& data, const auto& child) noexcept -> decltype(auto) { - return @\exposid{JOIN-ENV}@(@\exposid{SCHED-ATTRS}@(data), @\exposid{FWD-ENV}@(get_env(child))); - }; - }; -} -\end{codeblock} - -\pnum -Let \tcode{sndr} and \tcode{env} be subexpressions -such that \tcode{Sndr} is \tcode{decltype((sndr))}. -If \tcode{\exposconcept{sender-for}} is \tcode{false}, -then -the expression \tcode{continues_on.transform_sender(sndr, env)} is ill-formed; -otherwise, it is equal to: -\begin{codeblock} -auto [_, data, child] = sndr; -return schedule_from(std::move(data), std::move(child)); -\end{codeblock} -\begin{note} -This causes the \tcode{continues_on(sndr, sch)} sender to become -\tcode{schedule_from(sch, sndr)} when it is connected with a receiver -whose execution domain does not customize \tcode{continues_on}. -\end{note} - -\pnum -Let \tcode{out_sndr} be a subexpression denoting -a sender returned from \tcode{continues_on(sndr, sch)} or one equal to such, and -let \tcode{OutSndr} be the type \tcode{decltype((out_sndr))}. -Let \tcode{out_rcvr} be a subexpression denoting a receiver -that has an environment of type \tcode{Env} -such that \tcode{\libconcept{sender_in}} is \tcode{true}. -Let \tcode{op} be an lvalue referring to the operation state -that results from connecting \tcode{out_sndr} with \tcode{out_rcvr}. -Calling \tcode{start(op)} shall -start \tcode{sndr} on the current execution agent and -execute completion operations on \tcode{out_rcvr} -on an execution agent of the execution resource associated with \tcode{sch}. -If scheduling onto \tcode{sch} fails, -an error completion on \tcode{out_rcvr} shall be executed -on an unspecified execution agent. - -\rSec3[exec.schedule.from]{\tcode{execution::schedule_from}} - -\pnum -\tcode{schedule_from} schedules work dependent on the completion of a sender +\tcode{continues_on} schedules work dependent on the completion of a sender onto a scheduler's associated execution resource. -\begin{note} -\tcode{schedule_from} is not meant to be used in user code; -it is used in the implementation of \tcode{continues_on}. -\end{note} \pnum -The name \tcode{schedule_from} denotes a customization point object. +The name \tcode{continues_on} denotes a customization point object. For some subexpressions \tcode{sch} and \tcode{sndr}, let \tcode{Sch} be \tcode{decltype((sch))} and \tcode{Sndr} be \tcode{decltype((sndr))}. If \tcode{Sch} does not satisfy \libconcept{scheduler}, or \tcode{Sndr} does not satisfy \libconcept{sender}, -\tcode{schedule_from(sch, sndr)} is ill-formed. +\tcode{continues_on(sndr, sch)} is ill-formed. \pnum Otherwise, -the expression \tcode{schedule_from(sch, sndr)} is expression-equivalent to: -\begin{codeblock} -transform_sender( - @\exposid{query-with-default}@(get_domain, sch, default_domain()), - @\exposid{make-sender}@(schedule_from, sch, sndr)) -\end{codeblock} -except that \tcode{sch} is evaluated only once. +the expression \tcode{continues_on(sndr, sch)} is expression-equivalent to +\tcode{\exposid{make-sender}(continues_on, sch, schedule_from(sndr))}. \pnum The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos} -is specialized for \tcode{schedule_from_t} as follows: -\indexlibraryglobal{\exposid{impls-for}}% +is specialized for \tcode{continues_on_t} as follows: +\indexlibraryglobal{\exposid{impls-for}}% \begin{codeblock} namespace std::execution { template<> - struct @\exposid{impls-for}@ : @\exposid{default-impls}@ { - static constexpr auto @\exposid{get-attrs}@ = @\seebelow@; + struct @\exposid{impls-for}@ : @\exposid{default-impls}@ { static constexpr auto @\exposid{get-state}@ = @\seebelow@; static constexpr auto @\exposid{complete}@ = @\seebelow@; @@ -3422,21 +3694,11 @@ \end{codeblock} \pnum -The member \tcode{\exposid{impls-for}::\exposid{get-attrs}} -is initialized with a callable object equivalent to the following lambda: -\begin{codeblock} -[](const auto& data, const auto& child) noexcept -> decltype(auto) { - return @\exposid{JOIN-ENV}@(@\exposid{SCHED-ATTRS}@(data), @\exposid{FWD-ENV}@(get_env(child))); -} -\end{codeblock} - -\pnum -The member \tcode{\exposid{impls-for}::\exposid{get-state}} +The member \tcode{\exposid{impls-for}::\exposid{get-state}} is initialized with a callable object equivalent to the following lambda: \begin{codeblock} [](Sndr&& sndr, Rcvr& rcvr) noexcept(@\seebelow@) requires @\libconcept{sender_in}@<@\exposid{child-type}@, @\exposid{FWD-ENV-T}@(env_of_t)> { - auto& [_, sch, child] = sndr; using sched_t = decltype(auto(sch)); @@ -3503,7 +3765,7 @@ \begin{codeblock} namespace std::execution { struct @\exposid{receiver-type}@ { - using receiver_concept = receiver_t; + using receiver_concept = receiver_tag; @\exposid{state-type}@* @\exposid{state}@; // \expos void set_value() && noexcept { @@ -3540,7 +3802,7 @@ otherwise, \tcode{false}. \pnum -The member \tcode{\exposid{impls-for}::\exposid{complete}} +The member \tcode{\exposid{impls-for}::\exposid{complete}} is initialized with a callable object equivalent to the following lambda: \begin{codeblock} [](auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept @@ -3561,7 +3823,7 @@ \pnum Let \tcode{out_sndr} be a subexpression denoting -a sender returned from \tcode{schedule_from(sch, sndr)} or one equal to such, +a sender returned from \tcode{continues_on_t(sndr, sch)} or one equal to such, and let \tcode{OutSndr} be the type \tcode{decltype((out_sndr))}. Let \tcode{out_rcvr} be a subexpression denoting a receiver that has an environment of type \tcode{Env} @@ -3576,6 +3838,21 @@ an error completion on \tcode{out_rcvr} shall be executed on an unspecified execution agent. +\rSec3[exec.schedule.from]{\tcode{execution::schedule_from}} + +\pnum +The name \tcode{schedule_from} denotes a customization point object. +For some subexpression \tcode{sndr}, +if \tcode{decltype((\brk{}sndr))} does not satisfy \libconcept{sender}, +\tcode{schedule_from(sndr)} is ill-formed. +Otherwise, +the expression \tcode{schedule_from(sndr)} is expression-equivalent to +\tcode{\exposid{make-sender}(schedule_from, \{\}, sndr)}. +\begin{note} +\tcode{schedule_from} is used by schedulers to control +how to transition off of their schedulers' associated execution contexts. +\end{note} + \rSec3[exec.on]{\tcode{execution::on}} \pnum @@ -3617,13 +3894,8 @@ \pnum Otherwise, if \tcode{decltype((sndr))} satisfies \libconcept{sender}, -the expression \tcode{on(sch, sndr)} is expression-equivalent to: -\begin{codeblock} -transform_sender( - @\exposid{query-with-default}@(get_domain, sch, default_domain()), - @\exposid{make-sender}@(on, sch, sndr)) -\end{codeblock} -except that \tcode{sch} is evaluated only once. +the expression \tcode{on(sch, sndr)} is expression-equivalent to +\tcode{\exposid{make-sender}(on, sch, sndr)}. \pnum For subexpressions \tcode{sndr}, \tcode{sch}, and \tcode{closure}, if @@ -3636,73 +3908,33 @@ \tcode{closure} is not a pipeable sender adaptor closure object\iref{exec.adapt.obj}, \end{itemize} the expression \tcode{on(sndr, sch, closure)} is ill-formed; -otherwise, it is expression-equivalent to: -\begin{codeblock} -transform_sender( - @\exposid{get-domain-early}@(sndr), - @\exposid{make-sender}@(on, @\exposid{product-type}@{sch, closure}, sndr)) -\end{codeblock} -except that \tcode{sndr} is evaluated only once. +otherwise, it is expression-equivalent to +\tcode{\exposid{make-sender}(\brk{}on, \exposid{product-type}{sch, closure}, sndr)}. \pnum Let \tcode{out_sndr} and \tcode{env} be subexpressions, let \tcode{OutSndr} be \tcode{decltype((out_sndr))}, and let \tcode{Env} be \tcode{decltype((\linebreak env))}. If \tcode{\exposconcept{sender-for}} is \tcode{false}, -then the expressions \tcode{on.transform_env(out_sndr, env)} and -\tcode{on.transform_sender(out_sndr, env)} are ill-formed. - -\pnum -Otherwise: -Let \exposid{not-a-scheduler} be an unspecified empty class type. - -\pnum -The expression \tcode{on.transform_env(out_sndr, env)} -has effects equivalent to: -\begin{codeblock} -auto&& [_, data, _] = out_sndr; -if constexpr (@\libconcept{scheduler}@) { - return @\exposid{JOIN-ENV}@(@\exposid{SCHED-ENV}@(std::forward_like(data)), @\exposid{FWD-ENV}@(std::forward(env))); -} else { - return std::forward(env); -} -\end{codeblock} +then the expression \tcode{on.transform_sender(out_sndr, env)} is ill-formed. \pnum -The expression \tcode{on.transform_sender(out_sndr, env)} +Otherwise, the expression \tcode{on.transform_sender(set_value, out_sndr, env)} has effects equivalent to: \begin{codeblock} auto&& [_, data, child] = out_sndr; if constexpr (@\libconcept{scheduler}@) { - auto orig_sch = - @\exposid{query-with-default}@(get_scheduler, env, @\exposid{not-a-scheduler}@()); - - if constexpr (@\libconcept{same_as}@) { - return @\exposid{not-a-sender}@{}; - } else { - return continues_on( - starts_on(std::forward_like(data), std::forward_like(child)), - std::move(orig_sch)); - } + auto orig_sch = @\exposid{call-with-default}@(get_start_scheduler, @\exposid{not-a-scheduler}@(), env); + return continues_on( + starts_on(std::forward_like(data), std::forward_like(child)), + std::move(orig_sch)); } else { auto& [sch, closure] = data; - auto orig_sch = @\exposid{query-with-default}@( - get_completion_scheduler, - get_env(child), - @\exposid{query-with-default}@(get_scheduler, env, @\exposid{not-a-scheduler}@())); - - if constexpr (@\libconcept{same_as}@) { - return @\exposid{not-a-sender}@{}; - } else { - return write_env( - continues_on( - std::forward_like(closure)( - continues_on( - write_env(std::forward_like(child), @\exposid{SCHED-ENV}@(orig_sch)), - sch)), - orig_sch), - @\exposid{SCHED-ENV}@(sch)); - } + auto orig_sch = @\exposid{call-with-default}@( + get_completion_scheduler, @\exposid{not-a-scheduler}@(), get_env(child), env); + return continues_on( + std::forward_like(closure)(continues_on(std::forward_like(child), sch)), + orig_sch); } \end{codeblock} @@ -3718,7 +3950,8 @@ Calling \tcode{start(op)} shall \begin{itemize} \item -remember the current scheduler, \tcode{get_scheduler(get_env(rcvr))}; +remember the current scheduler, +which is obtained by \tcode{get_start_scheduler(get_env(rcvr))}; \item start \tcode{sndr} on an execution agent belonging to \tcode{sch}'s associated execution resource; @@ -3746,11 +3979,8 @@ \begin{itemize} \item remember the current scheduler, -which is the first of the following expressions that is well-formed: -\begin{itemize} -\item \tcode{get_completion_scheduler(get_env(sndr))} -\item \tcode{get_scheduler(get_env(rcvr))}; -\end{itemize} +which is +\tcode{get_completion_scheduler(get_env(\newline sndr), get_env(out_rcvr))}; \item start \tcode{sndr} on the current execution agent; \item @@ -3793,11 +4023,8 @@ \pnum Otherwise, -the expression \tcode{\exposid{then-cpo}(sndr, f)} is expression-equivalent to: -\begin{codeblock} -transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(@\exposid{then-cpo}@, f, sndr)) -\end{codeblock} -except that \tcode{sndr} is evaluated only once. +the expression \tcode{\exposid{then-cpo}(sndr, f)} is expression-equivalent to +\tcode{\exposid{make-sender}(\exposid{then-cpo}, f, sndr)}. \pnum For \tcode{then}, \tcode{upon_error}, and \tcode{upon_stopped}, @@ -3875,14 +4102,16 @@ \tcode{set_value}, \tcode{set_error}, and \tcode{set_stopped}, respectively. Let the expression \exposid{let-cpo} be one of \tcode{let_value}, \tcode{let_error}, or \tcode{let_stopped}. -For a subexpression \tcode{sndr}, -let \tcode{\exposid{let-env}(sndr)} be expression-equivalent to +Let \exposid{let-tag} denote a unique, empty class type for each of +\tcode{let_value}, \tcode{let_error}, and \tcode{let_stopped}. +For subexpressions \tcode{sndr} and \tcode{env}, +let \tcode{\exposid{let-env}(sndr, env)} be expression-equivalent to the first well-formed expression below: \begin{itemize} \item -\tcode{\exposid{SCHED-ENV}(get_completion_scheduler<\exposid{decayed-typeof}<\exposid{set-cpo}>>(get_env(sndr)))} +\tcode{\exposid{SCHED-ENV}(get_completion_scheduler<\exposid{decayed-typeof}<\exposid{set-cpo}>>(get_env(sndr),\newline \exposid{FWD-ENV}(env)))} \item -\tcode{\exposid{MAKE-ENV}(get_domain, get_domain(get_env(sndr)))} +\tcode{\exposid{MAKE-ENV}(get_domain, get_completion_domain<\exposid{decayed-typeof}<\exposid{set-cpo}>>(get_env(sndr),\newline \exposid{FWD-ENV}(env)))} \item \tcode{(void(sndr), env<>\{\})} \end{itemize} @@ -3900,25 +4129,37 @@ \pnum Otherwise, -the expression \tcode{\exposid{let-cpo}(sndr, f)} is expression-equivalent to: +the expression \tcode{\exposid{let-cpo}(sndr, f)} is expression-equivalent to +\tcode{\exposid{make-sender}(\exposid{let-cpo}, f, sndr)}. + +\pnum +Let \exposid{let-data} denote the following exposition-only class template: +\begin{codeblock} +template +struct @\exposid{let-data}@ { + Sndr @\exposid{sndr}@; // \expos + Fn @\exposid{fn}@; // \expos +}; +\end{codeblock} + +\pnum +Then let the expression \tcode{\exposid{let-cpo}.transform_sender(s, es...)} +be expression-equivalent to: \begin{codeblock} -transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(@\exposid{let-cpo}@, f, sndr)) +@\exposid{make-sender}@(@\exposid{let-tag}@{}, @\exposid{let-data}@{s.template @\exposid{get}@<2>(), s.template @\exposid{get}@<1>()}) \end{codeblock} -except that \tcode{sndr} is evaluated only once. +except that \tcode{s} is evaluated only once. \pnum The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos} -is specialized for \exposid{let-cpo} as follows: +is specialized for \exposid{let-tag} as follows: \indexlibraryglobal{\exposid{impls-for}<\exposid{decayed-typeof}<\exposid{let-cpo}>>} \begin{codeblock} namespace std::execution { - template - void @\exposid{let-bind}@(State& state, Rcvr& rcvr, Args&&... args); // \expos - template<> - struct @\exposid{impls-for}@<@\exposid{decayed-typeof}@<@\exposid{let-cpo}@>> : @\exposid{default-impls}@ { + struct @\exposid{impls-for}@<@\exposid{let-tag}@> : @\exposid{default-impls}@ { static constexpr auto @\exposid{get-state}@ = @\seebelow@; - static constexpr auto @\exposid{complete}@ = @\seebelow@; + static constexpr auto @\exposid{start}@ = @\seebelow@; template static consteval void @\exposid{check-types}@(); @@ -3932,7 +4173,7 @@ namespace std::execution { template struct @\exposid{receiver2}@ { - using receiver_concept = receiver_t; + using receiver_concept = receiver_tag; template void set_value(Args&&... args) && noexcept { @@ -3963,15 +4204,15 @@ \item \tcode{decltype(e)} models \exposconcept{queryable} and \item -given a query object \tcode{q}, -the expression \tcode{e.query(q)} is expression-equivalent -to \tcode{\exposid{env}.query(q)} if that expression is valid; +given a query object \tcode{q} and a pack of subexpressions \tcode{args}, +the expression \tcode{e.query(q, args...)} is expression-equivalent +to \tcode{\exposid{env}.query(q, args...)} if that expression is valid; otherwise, if the type of \tcode{q} satisfies \exposconcept{forwarding-query}, -\tcode{e.query(q)} is expression-equivalent -to \tcode{get_env(\exposid{rcvr}).query(q)}; +\tcode{e.query(q, args...)} is expression-equivalent +to \tcode{get_env(\exposid{rcvr}).query\newline (q, args...)}; otherwise, -\tcode{e.query(q)} is ill-formed. +\tcode{e.query(q, args...)} is ill-formed. \end{itemize} \indexlibrarymember{\exposid{check-types}}{\exposid{impls-for}<\exposid{decayed-typeof}<\exposid{let-cpo}>>} @@ -4003,28 +4244,98 @@ \tcode{sizeof...(Env) == 0 || \libconcept{sender_in}\&...>, \placeholder{env-t}\linebreak{}...>} \end{itemize} where \tcode{\placeholder{env-t}} is the pack -\tcode{decltype(\exposid{let-cpo}.transform_env(declval(), declval()))}. +\tcode{decltype(\exposid{JOIN-ENV}(\exposid{let-env}(declval<\exposid{child-type}>(), declval<\brk{}Env>()), \exposid{FWD-ENV}(declval())))}. \end{itemdescr} \pnum -\tcode{\exposid{impls-for}<\exposid{decayed-typeof}<\exposid{let-cpo}>>::\exposid{get-state}} +Let \exposid{let-state} denote the following exposition-only class template: +\begin{codeblock} +template +struct @\exposid{let-state}@ { + using @\exposidnc{env_t}@ = decltype(@\exposidnc{let-env}@(declval()), get_env(declval())); // \expos + Fn @\exposidnc{fn}@; // \expos + env_t @\exposidnc{env}@; // \expos + ArgsVariant @\exposidnc{args}@; // \expos + OpsVariant @\exposidnc{ops}@; // \expos + + template + constexpr void @\exposid{impl}@(Rcvr& rcvr, Tag tag, Ts&&... ts) noexcept // \expos + { + using args_t = @\exposid{decayed-tuple}@; + using receiver_type = @\exposid{receiver2}@; + using sender_type = apply_result_t; + if constexpr (is_same_v) { + try { + auto& tuple = @\exposid{args}@.template emplace(std::forward(ts)...); + @\exposid{ops}@.template emplace(); + auto&& sndr = apply(std::move(@\exposid{fn}@), tuple); + using op_t = connect_result_t; + auto mkop2 = [&] { + return connect(std::forward(sndr), + receiver_type{@\exposid{rcvr}@, @\exposid{env}@}); + }; + auto& op = @\exposid{ops}@.template emplace(@\exposid{emplace-from}@{mkop2}); + start(op); + } catch (...) { + constexpr bool nothrow = + is_nothrow_constructible_v && + is_nothrow_applicable_v && + noexcept(connect(declval(), receiver_type{@\exposid{rcvr}@, @\exposid{env}@})); + if constexpr (!nothrow) { + set_error(std::move(@\exposid{rcvr}@), current_exception()); + } + } + } else { + tag(std::move(@\exposid{rcvr}@), std::forward(ts)...); + } + } + + struct @\exposid{receiver}@ { // \expos + @\exposid{let-state}@& state; // \expos + Rcvr& @\exposid{rcvr}@; // \expos + + using receiver_concept = receiver_tag; + + template + constexpr void set_value(Args&&... args) noexcept { + @\exposid{state}@.@\exposid{impl}@(@\exposid{rcvr}@, execution::set_value, std::forward(args)...); + } + template + constexpr void set_error(Args&&... args) noexcept { + @\exposid{state}@.@\exposid{impl}@(@\exposid{rcvr}@, execution::set_error, std::forward(args)...); + } + template + constexpr void set_stopped(Args&&... args) noexcept { + @\exposid{state}@.@\exposid{impl}@(@\exposid{rcvr}@, execution::set_stopped, std::forward(args)...); + } + + constexpr env_of_t get_env() const noexcept { + return execution::get_env(@\exposid{rcvr}@); + } + }; + + using @\exposidnc{op_t}@ = connect_result_t; // \expos + + constexpr @\exposidnc{let-state}@(Sndr&& sndr, Fn fn, Rcvr& rcvr) // \expos + : @\exposid{fn}@(std::move(fn)), @\exposid{env}@(@\exposid{let-env}@(sndr), get_env(rcvr)), + @\exposid{ops}@(in_place_type<@\exposid{op_t}@>, std::forward(sndr), @\exposid{receiver}@{*this, rcvr}) {} +}; +\end{codeblock} + +\pnum +\tcode{\exposid{impls-for}<\exposid{let-tag}>::\exposid{get-state}} is initialized with a callable object equivalent to the following: \begin{codeblock} [](Sndr&& sndr, Rcvr& rcvr) requires @\seebelow@ { - auto& [_, fn, child] = sndr; + auto& [_, data] = sndr; + auto& [child, fn] = data; + using child_t = decltype(std::forward_like(child)); using fn_t = decay_t; - using env_t = decltype(@\exposid{let-env}@(child)); using args_variant_t = @\seebelow@; - using ops2_variant_t = @\seebelow@; - - struct @\exposid{state-type}@ { - fn_t @\exposid{fn}@; // \expos - env_t @\exposid{env}@; // \expos - args_variant_t @\exposid{args}@; // \expos - ops2_variant_t @\exposid{ops2}@; // \expos - }; - return @\exposid{state-type}@{@\exposid{allocator-aware-forward}@(std::forward_like(fn), rcvr), - @\exposid{let-env}@(child), {}, {}}; + using ops_variant_t = @\seebelow@; + using state_t = @\exposid{let-state}@<@\exposid{decayed-typeof}@<@\exposid{set-cpo}@>, child_t, fn_t, Rcvr, + args_variant_t, ops_variant_t>; + return state_t(std::forward_like(child), std::forward_like(fn), @\exposid{rcvr}@); } \end{codeblock} @@ -4046,10 +4357,12 @@ let \exposid{as-sndr2} be an alias template such that \tcode{\exposid{as-sndr2}} denotes the type \tcode{\exposid{call-result-t}\&...>}. -Then \tcode{ops2_variant_t} denotes +Then \tcode{ops_variant_t} denotes the type \begin{codeblock} -variant, @\exposid{receiver2}@>...> +variant, + connect_result_t<@\exposid{as-sndr2}@, @\exposid{receiver2}@>...> \end{codeblock} except with duplicate types removed. @@ -4059,45 +4372,12 @@ the types \tcode{args_variant_t} and \tcode{ops2_variant_t} are well-formed. \pnum -The exposition-only function template \exposid{let-bind} -has effects equivalent to: -\begin{codeblock} -using args_t = @\exposid{decayed-tuple}@; -auto mkop2 = [&] { - return connect( - apply(std::move(state.fn), - state.args.template emplace(std::forward(args)...)), - @\exposid{receiver2}@{rcvr, std::move(state.env)}); -}; -start(state.ops2.template emplace(@\exposid{emplace-from}@{mkop2})); -\end{codeblock} - -\pnum -\tcode{\exposid{impls-for}<\exposid{decayed-typeof}<\exposid{let-cpo}>>::\exposid{complete}} +\tcode{\exposid{impls-for}<\exposid{let-tag}>::\exposid{start}} is initialized with a callable object equivalent to the following: \begin{codeblock} -[] - (auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept -> void { - if constexpr (@\libconcept{same_as}@>) { - @\exposid{TRY-EVAL}@(rcvr, @\exposid{let-bind}@(state, rcvr, std::forward(args)...)); - } else { - Tag()(std::move(rcvr), std::forward(args)...); - } - } -\end{codeblock} - -\pnum -Let \tcode{sndr} and \tcode{env} be subexpressions, and -let \tcode{Sndr} be \tcode{decltype((sndr))}. -If -\tcode{\exposconcept{sender-for}>} -is \tcode{false}, -then the expression \tcode{\exposid{let-cpo}.transform_env(sndr, env)} -is ill-formed. -Otherwise, it is equal to: -\begin{codeblock} -auto& [_, _, child] = sndr; -return @\exposid{JOIN-ENV}@(@\exposid{let-env}@(child), @\exposid{FWD-ENV}@(env)); +[](State& state, Rcvr&) noexcept { + start(get(state.@\exposid{ops}@)); +} \end{codeblock} \pnum @@ -4153,12 +4433,9 @@ Otherwise, the expression \tcode{\placeholder{bulk-algo}(sndr, policy, shape, f)} is expression-equivalent to: - \begin{codeblock} -transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@( - @\placeholder{bulk-algo}@, @\exposid{product-type}@<@\seebelow@, Shape, Func>{policy, shape, f}, sndr)) +@\exposid{make-sender}@(@\placeholder{bulk-algo}@, @\exposid{product-type}@<@\seebelow@, Shape, Func>{policy, shape, f}, sndr) \end{codeblock} -except that \tcode{sndr} is evaluated only once. The first template argument of \exposid{product-type} is \tcode{Policy} if \tcode{Policy} models \libconcept{copy_constructible}, and \tcode{const Policy\&} otherwise. @@ -4167,7 +4444,7 @@ Let \tcode{sndr} and \tcode{env} be subexpressions such that \tcode{Sndr} is \tcode{decltype((sndr))}. If \tcode{\exposconcept{sender-for}} is \tcode{false}, then -the expression \tcode{bulk.transform_sender(sndr, env)} is ill-formed; +the expression \tcode{bulk.transform_sender(set_value, sndr, env)} is ill-formed; otherwise, it is equivalent to: \begin{codeblock} auto [_, data, child] = sndr; @@ -4421,12 +4698,8 @@ \pnum The names \tcode{when_all} and \tcode{when_all_with_variant} denote customization point objects. -Let \tcode{sndrs} be a pack of subexpressions, -let \tcode{Sndrs} be a pack of the types \tcode{decltype((sndrs))...}, and -let \tcode{CD} be -the type \tcode{common_type_t}. -Let \tcode{CD2} be \tcode{CD} if \tcode{CD} is well-formed, and -\tcode{default_domain} otherwise. +Let \tcode{sndrs} be a pack of subexpressions and +let \tcode{Sndrs} be a pack of the types \tcode{decltype((sndrs))...}. The expressions \tcode{when_all(sndrs...)} and \tcode{when_all_with_variant(sndrs...)} are ill-formed if any of the following is \tcode{true}: @@ -4438,10 +4711,8 @@ \end{itemize} \pnum -The expression \tcode{when_all(sndrs...)} is expression-equivalent to: -\begin{codeblock} -transform_sender(CD2(), @\exposid{make-sender}@(when_all, {}, sndrs...)) -\end{codeblock} +The expression \tcode{when_all(sndrs...)} is expression-equivalent to +\tcode{\exposid{make-sender}(when_all, \{\}, sndrs...)}. \pnum The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos} @@ -4451,7 +4722,6 @@ namespace std::execution { template<> struct @\exposid{impls-for}@ : @\exposid{default-impls}@ { - static constexpr auto @\exposid{get-attrs}@ = @\seebelow@; static constexpr auto @\exposid{get-env}@ = @\seebelow@; static constexpr auto @\exposid{get-state}@ = @\seebelow@; static constexpr auto @\exposid{start}@ = @\seebelow@; @@ -4520,29 +4790,8 @@ }; (fn.template operator()<@\exposid{child-type}@>(), ...); \end{codeblock} - -\pnum -\throws -Any exception thrown as a result of evaluating the \Fundescx{Effects}, or -an exception of type -\tcode{\placeholder{unspecified-\brk{}exception}}\iref{exec.snd.general} -when \tcode{CD} is ill-formed. \end{itemdescr} -\pnum -The member \tcode{\exposid{impls-for}::\exposid{get-attrs}} -is initialized with a callable object -equivalent to the following lambda expression: -\begin{codeblock} -[](auto&&, auto&&... child) noexcept { - if constexpr (@\libconcept{same_as}@) { - return env<>(); - } else { - return @\exposid{MAKE-ENV}@(get_domain, CD()); - } -} -\end{codeblock} - \pnum The member \tcode{\exposid{impls-for}::\exposid{get-env}} is initialized with a callable object @@ -4735,17 +4984,15 @@ \pnum The expression \tcode{when_all_with_variant(sndrs...)} -is expression-equivalent to: -\begin{codeblock} -transform_sender(CD2(), @\exposid{make-sender}@(when_all_with_variant, {}, sndrs...)); -\end{codeblock} +is expression-equivalent to +\tcode{\exposid{make-sender}(when_all_with_variant, \{\}, sndrs...)}. \pnum Given subexpressions \tcode{sndr} and \tcode{env}, if \tcode{\exposconcept{sender-for}} is \tcode{false}, -then the expression \tcode{when_all_with_variant.transform_sender(sndr, env)} +then the expression \tcode{when_all_with_variant.transform_sender(set_value, sndr, env)} is ill-formed; otherwise, it is equivalent to: \begin{codeblock} @@ -4774,11 +5021,8 @@ \pnum Otherwise, the expression \tcode{into_variant(sndr)} -is expression-equivalent to: -\begin{codeblock} -transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(into_variant, {}, sndr)) -\end{codeblock} -except that \tcode{sndr} is only evaluated once. +is expression-equivalent to +\tcode{\exposid{make-sender}(into_variant, \{\}, sndr)}. \pnum The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos} @@ -4839,11 +5083,8 @@ \pnum The name \tcode{stopped_as_optional} denotes a pipeable sender adaptor object. For a subexpression \tcode{sndr}, let \tcode{Sndr} be \tcode{decltype((sndr))}. -The expression \tcode{stopped_as_optional(sndr)} is expression-equivalent to: -\begin{codeblock} -transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(stopped_as_optional, {}, sndr)) -\end{codeblock} -except that \tcode{sndr} is only evaluated once. +The expression \tcode{stopped_as_optional(sndr)} is expression-equivalent to +\tcode{\exposid{make-sender}(stopped_as_optional, \{\}, sndr)}. \pnum The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos} @@ -4872,10 +5113,10 @@ \tcode{Env} is \tcode{decltype((env))}. If \tcode{\exposconcept{sender-for}} is \tcode{false} -then the expression \tcode{stopped_as_optional.trans\-form_sender(sndr, env)} +then the expression \tcode{stopped_as_optional.trans\-form_sender(set_value, sndr, env)} is ill-formed; otherwise, -if \tcode{\libconcept{sender_in}<\exposid{child-type}, \exposid{FWD-ENV-T}(Env)>} +if \tcode{\libconcept{sender_in}<\exposid{child-type}, \exposid{FWD-\brk{}ENV-\brk{}T}(Env)>} is \tcode{false}, the expression \tcode{stopped_as_optional.transform_sender(sndr, env)} is equivalent to \tcode{\exposid{not-a-sen\-der}()}; @@ -4908,18 +5149,15 @@ if the type \tcode{Err} does not satisfy \exposconcept{movable-value}, \tcode{stopped_as_error(sndr, err)} is ill-formed. Otherwise, the expression \tcode{stopped_as_error(sndr, err)} -is expression-equivalent to: -\begin{codeblock} -transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(stopped_as_error, err, sndr)) -\end{codeblock} -except that \tcode{sndr} is only evaluated once. +is expression-equivalent to +\tcode{\exposid{make-sender}(stopped_as_error, err, sndr)}. \pnum Let \tcode{sndr} and \tcode{env} be subexpressions such that \tcode{Sndr} is \tcode{decltype((sndr))} and \tcode{Env} is \tcode{decltype((env))}. If \tcode{\exposconcept{sender-for}} is \tcode{false}, -then the expression \tcode{stopped_as_error.transform_sender(sndr, env)} +then the expression \tcode{stopped_as_error.transform_sender(set_value, sndr, env)} is ill-formed; otherwise, it is equivalent to: \begin{codeblock} @@ -5066,12 +5304,8 @@ \item Otherwise, the expression \tcode{associate(sndr, token)} -is expression-equivalent to: -\begin{codeblock} -transform_sender(@\exposid{get-domain-early}@(sndr), - @\exposid{make-sender}@(associate, @\exposid{associate-data}@(token, sndr))) -\end{codeblock} -except that \tcode{sndr} is evaluated only once. +is expression-equivalent to +\tcode{\exposid{make-sender}(asso\-ci\-ate, \exposid{associate-data}(token, sndr))}. \end{itemize} \pnum @@ -5282,6 +5516,18 @@ are not satisfied, the expression \tcode{spawn_future(sndr, token, env)} is ill-formed. +\pnum +Let \exposid{try-cancelable} be the exposition-only class: + +\indexlibraryglobal{execution::\exposid{try-cancelable}}% +\begin{codeblock} +namespace std::execution { + struct @\exposid{try-cancelable}@ { // \expos + virtual void @\exposid{try-cancel}@() noexcept = 0; // \expos + }; +} +\end{codeblock} + \pnum Let \exposid{spawn-future-state-base} be the exposition-only class template: @@ -5292,7 +5538,8 @@ struct @\exposid{spawn-future-state-base}@; // \expos template - struct @\exposid{spawn-future-state-base}@> { // \expos + struct @\exposid{spawn-future-state-base}@> // \expos + : @\exposid{try-cancelable}@ { using @\exposid{variant-t}@ = @\seebelow@; // \expos @\exposid{variant-t}@ @\exposid{result}@; // \expos virtual void @\exposid{complete}@() noexcept = 0; // \expos @@ -5334,7 +5581,7 @@ namespace std::execution { template struct @\exposid{spawn-future-receiver}@ { // \expos - using receiver_concept = receiver_t; + using receiver_concept = receiver_tag; @\exposid{spawn-future-state-base}@* @\exposid{state}@; // \expos @@ -5418,6 +5665,11 @@ void @\exposidnc{complete}@() noexcept override; // \expos void @\exposidnc{consume}@(@\libconcept{receiver}@ auto& rcvr) noexcept; // \expos void @\exposidnc{abandon}@() noexcept; // \expos + void @\exposidnc{try-cancel}@() noexcept override { // \expos + @\exposid{ssource}@.request_stop(); + @\exposid{try-set-stopped}@(); + } + void @\exposidnc{try-set-stopped}@() noexcept; // \expos private: using @\exposidnc{assoc-t}@ = // \expos @@ -5439,7 +5691,7 @@ \pnum For purposes of determining the existence of a data race, -\exposid{complete}, \exposid{consume}, and \exposid{abandon} +\exposid{complete}, \exposid{consume}, \exposid{try-set-stopped}, and \exposid{abandon} behave as atomic operations\iref{intro.multithread}. These operations on a single object of a type that is a specialization of \exposid{spawn-future-state} @@ -5456,13 +5708,18 @@ \begin{itemize} \item No effects if this invocation of \exposid{complete} happens before -an invocation of \exposid{consume} or \exposid{abandon} on \tcode{*this}; +an invocation of +\exposid{consume}, \exposid{try-set-\linebreak{}stopped}, or \exposid{abandon} +on \tcode{*this}; \item otherwise, if an invocation of \exposid{consume} on \tcode{*this} happens before -this invocation of \exposid{complete} then +this invocation of \exposid{complete} and +no invocation of \exposid{try-set-stopped} on \tcode{*this} happened before +this invocation of \tcode{complete} then there is a receiver, \tcode{rcvr}, registered and -that receiver is completed as if by \tcode{\exposid{consume}(rcvr)}; +that receiver is deregistered and completed +as if by \tcode{\exposid{consume}(rcvr)}; \item otherwise, \exposid{destroy} is invoked. @@ -5480,10 +5737,20 @@ \begin{itemize} \item If this invocation of \exposid{consume} happens before -an invocation of \exposid{complete} on \tcode{*this} then +an invocation of \exposid{complete} on \tcode{*this} and +no invocation of \exposid{try-set-stopped} on \tcode{*this} happened before +this invocation of \exposid{consume} then \tcode{rcvr} is registered to be completed when \exposid{complete} is subsequently invoked on \tcode{*this}; +\item +otherwise, +if this invocation of \exposid{consume} happens after +an invocation of \exposid{try-set-stopped} on \tcode{*this} and +no invocation of \exposid{complete} on \tcode{*this} happened before +this invocation of \exposid{consume} then +\tcode{rcvr} is completed as if by \tcode{set_stopped(std::move(rcvr))}; + \item otherwise, \tcode{rcvr} is completed as if by: @@ -5496,10 +5763,34 @@ }, std::move(tuple)); } }); +@\exposid{destroy}@(); \end{codeblock} \end{itemize} \end{itemdescr} +\indexlibrarymember{\exposid{try-set-stopped}}{execution::\exposid{spawn-future-state}}% +\begin{itemdecl} +void @\exposid{try-set-stopped}@() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +\begin{itemize} +\item +If an invocation of \exposid{consume} on \tcode{*this} happens before +this invocation of \exposid{try-set-stopped} and +no invocation of \exposid{complete} on \tcode{*this} happened before +this invocation of \exposid{try-set-stopped} then +there is a receiver, \tcode{rcvr}, registered and +that receiver is deregistered and completed as if by +\tcode{set_stopped(std::move(rcvr)), \exposid{destroy}()}; + +\item +otherwise, no effects. +\end{itemize} +\end{itemdescr} + \indexlibrarymember{\exposid{abandon}}{execution::\exposid{spawn-future-state}}% \begin{itemdecl} void @\exposid{abandon}@() noexcept; @@ -5542,6 +5833,87 @@ \end{codeblock} \end{itemdescr} +\pnum +Let \exposid{future-operation} be the exposition-only class template: + +\begin{codeblock} +namespace std::execution { + template + struct @\exposid{future-operation}@ { // \expos + struct @\exposid{callback}@ { // \expos + @\exposid{try-cancelable}@* @\exposid{state}@; // \expos + + void operator()() noexcept { + @\exposid{state}@->@\exposid{try-cancel}@(); + }; + }; + + using @\exposid{stop-token-t}@ = // \expos + stop_token_of_t>; + + using @\exposid{stop-callback-t}@ = // \expos + stop_callback_for_t<@\exposid{stop-token-t}@, @\exposid{callback}@>; + + struct @\exposid{rcvr-t}@ { // \expos + using receiver_concept = receiver_tag; + @\exposid{future-operation}@* @\exposid{op}@; // \expos + + template + void set_value(T&&... ts) && noexcept { + @\exposid{op}@->@\exposid{set-complete}@(std::forward(ts)...); + } + + template + void set_error(E&& e) && noexcept { + @\exposid{op}@->@\exposid{set-complete}@(std::forward(e)); + } + + void set_stopped() && noexcept { + @\exposid{op}@->@\exposid{set-complete}@(); + } + + env_of_t get_env() const noexcept { + return execution::get_env(@\exposid{op}@->@\exposid{rcvr}@); + } + }; + + Rcvr @\exposid{rcvr}@; // \expos + StatePtr @\exposid{state}@; // \expos + @\exposid{rcvr-t}@ @\exposid{inner}@; // \expos + optional<@\exposid{stop-callback-t}@> @\exposid{stopCallback}@; // \expos + + + @\exposid{future-operation}@(StatePtr state, Rcvr rcvr) noexcept // \expos + : @\exposid{rcvr}@(std::move(rcvr)), @\exposid{state}@(std::move(state)), @\exposid{inner}@(this) + {} + + @\exposid{future-operation}@(@\exposid{future-operation}@&&) = delete; + + void @\exposid{run}@() & noexcept { // \expos + constexpr bool nothrow = + is_nothrow_constructible_v<@\exposid{stop-callback-t}@, @\exposid{stop-token-t}@, @\exposid{callback}@>; + try { + @\exposid{stopCallback}@.emplace(get_stop_token(@\exposid{rcvr}@), @\exposid{callback}@(@\exposid{state}@.get())); + } + catch (...) { + if constexpr (!nothrow) { + set_error(std::move(@\exposid{rcvr}@), current_exception()); + return; + } + } + + @\exposid{state}@.release()->@\exposid{consume}@(@\exposid{inner}@); + } + + template + void @\exposid{set-complete}@(T&&... ts) noexcept { // \expos + @\exposid{stopCallback}@.reset(); + CPO{}(std::move(@\exposid{rcvr}@), std::forward(ts)...); + } + }; +} +\end{codeblock} + \pnum The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos} is specialized for \tcode{spawn_future_t} as follows: @@ -5552,6 +5924,7 @@ template<> struct @\exposid{impls-for}@ : @\exposid{default-impls}@ { static constexpr auto @\exposid{start}@ = @\seebelow@; // \expos + static constexpr auto @\exposid{get-state}@ = @\seebelow@; // \expos }; } \end{codeblock} @@ -5560,8 +5933,19 @@ The member \tcode{\exposid{impls-for}::\exposid{start}} is initialized with a callable object equivalent to the following lambda: \begin{codeblock} -[](auto& state, auto& rcvr) noexcept -> void { - state->@\exposid{consume}@(rcvr); +[](auto& state, auto&) noexcept -> void { + state.@\exposid{run}@(); +} +\end{codeblock} + +\pnum +The member \tcode{\exposid{impls-for}::\exposid{get-state}} +is initialized with a callable object equivalent to the following lambda: +\begin{codeblock} +[](Sndr sndr, Rcvr& rcvr) noexcept { + auto& [_, data] = sndr; + using state_ptr = remove_cvref_t; + return @\exposid{future-operation}@(std::move(data), std::move(rcvr)); } \end{codeblock} @@ -5642,6 +6026,10 @@ return @\exposid{loop}@->get_scheduler(); } + auto query(execution::get_start_scheduler_t) const noexcept { + return @\exposid{loop}@->get_scheduler(); + } + auto query(execution::get_delegation_scheduler_t) const noexcept { return @\exposid{loop}@->get_scheduler(); } @@ -5670,11 +6058,11 @@ The name \tcode{this_thread::sync_wait} denotes a customization point object. For a subexpression \tcode{sndr}, let \tcode{Sndr} be \tcode{decltype((sndr))}. The expression \tcode{this_thread::sync_wait(sndr)} -is expression-equivalent to the following, -except that \tcode{sndr} is evaluated only once: -\begin{codeblock} -apply_sender(@\exposid{get-domain-early}@(sndr), sync_wait, sndr) -\end{codeblock} +is equivalent to \tcode{apply_sender(Domain(), sync_wait, sndr)}, +where \tcode{Domain} is the type of +\tcode{get_completion_domain(get_env(sndr), \exposid{sync-wait-env}\{\})}. + +\pnum \mandates \begin{itemize} \item @@ -5700,7 +6088,7 @@ template struct @\exposid{sync-wait-receiver}@ { // \expos - using receiver_concept = execution::receiver_t; + using receiver_concept = execution::receiver_tag; @\exposidnc{sync-wait-state}@* @\exposid{state}@; // \expos template @@ -5762,7 +6150,7 @@ \pnum For a subexpression \tcode{sndr}, let \tcode{Sndr} be \tcode{decltype((sndr))}. -If \tcode{\libconcept{sender_to}>} +If \tcode{\exposconcept{sender-to}>} is \tcode{false}, the expression \tcode{sync_wait.apply_sender(sndr)} is ill-formed; otherwise, it is equivalent to: @@ -5814,11 +6202,12 @@ For a subexpression \tcode{sndr}, let \tcode{Sndr} be \tcode{decltype(into_variant(sndr))}. The expression \tcode{this_thread::sync_wait_with_variant(sndr)} -is expression-equivalent to the following, -except \tcode{sndr} is evaluated only once: -\begin{codeblock} -apply_sender(@\exposid{get-domain-early}@(sndr), sync_wait_with_variant, sndr) -\end{codeblock} +is equivalent to \tcode{apply_sender(Domain(), sync_wait_with_variant, sndr)}, +where \tcode{Domain} is the type of +\tcode{get_completion_domain(get_env(sndr), \exposid{sync-wait-env}\{\})}, +except \tcode{sndr} is evaluated only once. + +\pnum \mandates \begin{itemize} \item @@ -5909,7 +6298,7 @@ \begin{codeblock} namespace std::execution { struct @\exposid{spawn-receiver}@ { // \expos - using receiver_concept = receiver_t; + using receiver_concept = receiver_tag; @\exposid{spawn-state-base}@* @\exposid{state}@; // \expos void set_value() && noexcept { @\exposid{state}@->@\exposid{complete}@(); } @@ -6043,7 +6432,7 @@ \begin{example} \begin{codeblock} struct my_sender { - using sender_concept = sender_t; + using sender_concept = sender_tag; using completion_signatures = execution::completion_signatures< set_value_t(), @@ -6191,7 +6580,7 @@ QueryTag @\exposid{query_}@; // \expos ValueType @\exposid{value_}@; // \expos - constexpr const ValueType& query(QueryTag) const noexcept { + constexpr const ValueType& query(QueryTag, auto&&...) const noexcept { return @\exposid{value_}@; } }; @@ -6221,7 +6610,7 @@ \begin{example} \begin{codeblock} template<@\libconcept{sender}@ Sndr> -sender auto parameterize_work(Sndr sndr) { +@\libconcept{sender}@ auto parameterize_work(Sndr sndr) { // Make an environment such that \tcode{get_allocator(env)} returns a reference to a copy of \tcode{my_alloc\{\}}. auto e = prop(get_allocator, my_alloc{}); @@ -6245,8 +6634,8 @@ @\vdots@ Envs@$_{n-1}$@ @$\exposid{envs}_{n-1}$@; // \expos - template - constexpr decltype(auto) query(QueryTag q) const noexcept(@\seebelow@); + template + constexpr decltype(auto) query(QueryTag q, Args&&... args) const noexcept(@\seebelow@); }; template @@ -6289,38 +6678,40 @@ \indexlibrarymember{query}{env}% \begin{itemdecl} -template -constexpr decltype(auto) query(QueryTag q) const noexcept(@\seebelow@); +template +constexpr decltype(auto) query(QueryTag q, Args&&... args) const noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} \pnum Let \exposconcept{has-query} be the following exposition-only concept: \begin{codeblock} -template +template concept @\defexposconcept{has-query}@ = // \expos - requires (const Env& env) { - env.query(QueryTag()); + requires (const Env& env, Args&&... args) { + env.query(QueryTag(), std::forward(args)...); }; \end{codeblock} \pnum Let \exposid{fe} be the first element of $\exposid{envs}_0$, $\exposid{envs}_1$, $\dotsc$, $\exposid{envs}_{n-1}$ -such that the expression \tcode{\exposid{fe}.query(q)} is well-formed. +such that the expression +\tcode{\exposid{fe}.query(q, std::forward(args)...)} +is well-formed. \pnum \constraints -\tcode{(\exposconcept{has-query} || ...)} is \tcode{true}. +\tcode{(\exposconcept{has-query} || ...)} is \tcode{true}. \pnum \effects -Equivalent to: \tcode{return \exposid{fe}.query(q);} +Equivalent to: \tcode{return \exposid{fe}.query(q, std::forward(args)...);} \pnum \remarks The expression in the \tcode{noexcept} clause is equivalent -to \tcode{noexcept(\exposid{fe}.query(q))}. +to \tcode{noexcept(\exposid{fe}.query(q, std::for\-ward(args)...))}. \end{itemdescr} \rSec1[exec.ctx]{Execution contexts} @@ -6361,7 +6752,7 @@ class @\exposid{run-loop-scheduler}@; // \expos class @\exposid{run-loop-sender}@; // \expos struct @\exposid{run-loop-opstate-base}@ { // \expos - virtual void @\exposid{execute}@() = 0; // \expos + virtual void @\exposid{execute}@() noexcept = 0; // \expos run_loop* @\exposid{loop}@; // \expos @\exposid{run-loop-opstate-base}@* @\exposid{next}@; // \expos }; @@ -6369,8 +6760,8 @@ using @\exposid{run-loop-opstate}@ = @\unspec@; // \expos // \ref{exec.run.loop.members}, member functions - @\exposid{run-loop-opstate-base}@* @\exposid{pop-front}@(); // \expos - void @\exposid{push-back}@(@\exposid{run-loop-opstate-base}@*); // \expos + @\exposid{run-loop-opstate-base}@* @\exposid{pop-front}@() noexcept; // \expos + void @\exposid{push-back}@(@\exposid{run-loop-opstate-base}@*) noexcept; // \expos public: // \ref{exec.run.loop.ctor}, constructor and destructor @@ -6379,9 +6770,9 @@ ~run_loop(); // \ref{exec.run.loop.members}, member functions - @\exposid{run-loop-scheduler}@ get_scheduler(); - void run(); - void finish(); + @\exposid{run-loop-scheduler}@ get_scheduler() noexcept; + void run() noexcept; + void finish() noexcept; }; } \end{codeblock} @@ -6411,6 +6802,12 @@ has type \exposid{run-loop-\newline sender} and is not potentially-throwing if \exposid{sch} is not potentially-throwing. +\pnum +For type \exposid{set-tag} other than \tcode{set_error_t}, +the expression +\tcode{get_completion_scheduler<\exposid{set-tag}>(get_env(schedule(\exposid{sch}))) == \exposid{sch}} +evaluates to \tcode{true}. + \begin{itemdecl} class @\exposid{run-loop-sender}@; \end{itemdecl} @@ -6418,10 +6815,11 @@ \pnum \exposid{run-loop-sender} is an exposition-only type that satisfies \libconcept{sender}. -\tcode{completion_signatures_of_t<\exposid{run-\linebreak{}loop-sender}>} is -\begin{codeblock} -completion_signatures -\end{codeblock} +Let \tcode{E} be the type of an environment. +If \tcode{unstoppable_token>} is \tcode{true}, then +\tcode{completion_signatures_of_t<\exposid{run-loop-sen\-der}, E>} is +\tcode{completion_signatures}. +Otherwise, it is \tcode{completion_signatures}. \pnum An instance of \exposid{run-loop-sender} remains valid @@ -6430,7 +6828,7 @@ \pnum Let \exposid{sndr} be an expression of type \exposid{run-loop-sender}, let \exposid{rcvr} be an expression -such that \tcode{\libconcept{receiver_of}} is \tcode{true} +such that \tcode{\exposconcept{receiver-of}} is \tcode{true} where \tcode{CS} is the \tcode{completion_signatures} specialization above. Let \tcode{C} be either \tcode{set_value_t} or \tcode{set_stopped_t}. Then: @@ -6481,11 +6879,7 @@ \item The expression \tcode{start($o$)} is equivalent to: \begin{codeblock} -try { - @$o$@.@\exposid{loop}@->@\exposid{push-back}@(addressof(@$o$@)); -} catch(...) { - set_error(std::move(@\exposid{REC}@(@$o$@)), current_exception()); -} +@$o$@.@\exposid{loop}@->@\exposid{push-back}@(addressof(@$o$@)); \end{codeblock} \end{itemize} @@ -6520,7 +6914,7 @@ \rSec3[exec.run.loop.members]{Member functions} \begin{itemdecl} -@\exposid{run-loop-opstate-base}@* @\exposid{pop-front}@(); +@\exposid{run-loop-opstate-base}@* @\exposid{pop-front}@() noexcept; \end{itemdecl} \begin{itemdescr} @@ -6541,7 +6935,7 @@ \end{itemdescr} \begin{itemdecl} -void @\exposid{push-back}@(@\exposid{run-loop-opstate-base}@* item); +void @\exposid{push-back}@(@\exposid{run-loop-opstate-base}@* item) noexcept; \end{itemdecl} \begin{itemdescr} @@ -6558,7 +6952,7 @@ \indexlibrarymember{get_scheduler}{run_loop}% \begin{itemdecl} -@\exposid{run-loop-scheduler}@ get_scheduler(); +@\exposid{run-loop-scheduler}@ get_scheduler() noexcept; \end{itemdecl} \begin{itemdescr} @@ -6570,7 +6964,7 @@ \indexlibrarymember{run}{run_loop}% \begin{itemdecl} -void run(); +void run() noexcept; \end{itemdecl} \begin{itemdescr} @@ -6598,7 +6992,7 @@ \indexlibrarymember{finish}{run_loop}% \begin{itemdecl} -void finish(); +void finish() noexcept; \end{itemdecl} \begin{itemdescr} @@ -6630,7 +7024,7 @@ template concept @\defexposconcept{awaitable-sender}@ = @\exposconcept{single-sender}@> && - @\libconcept{sender_to}@::@\exposid{awaitable-receiver}@> && // \seebelow requires (Promise& p) { { p.unhandled_stopped() } -> @\libconcept{convertible_to}@>; @@ -6678,7 +7072,7 @@ \exposid{awaitable-receiver} is equivalent to: \begin{codeblock} struct @\exposid{awaitable-receiver}@ { - using receiver_concept = receiver_t; + using receiver_concept = receiver_tag; variant* @\exposidnc{result-ptr}@; // \expos coroutine_handle @\exposidnc{continuation}@; // \expos // \seebelow @@ -6689,31 +7083,42 @@ Let \tcode{rcvr} be an rvalue expression of type \exposid{awaitable-receiver}, let \tcode{crcvr} be a const lvalue that refers to \tcode{rcvr}, let \tcode{vs} be a pack of subexpressions, and -let \tcode{err} be an expression of type \tcode{Err}. Then: +let \tcode{err} be an expression of type \tcode{Err}. +Let \tcode{\placeholder{MAKE-NOEXCEPT}(expr)} +for some subexpression \tcode{expr} be expression-equivalent to +\tcode{[\&] noexcept -> decltype(auto) \{ return (expr); \}()}. +Then: \begin{itemize} \item -If \tcode{\libconcept{constructible_from}<\exposid{result-type}, decltype((vs))...>} -is satisfied, -the expression \tcode{set_value(\newline rcvr, vs...)} is equivalent to: +The expression \tcode{set_value(rcvr, vs...)} is equivalent to: \begin{codeblock} try { rcvr.@\exposid{result-ptr}@->template emplace<1>(vs...); } catch(...) { rcvr.@\exposid{result-ptr}@->template emplace<2>(current_exception()); } -rcvr.@\exposid{continuation}@.resume(); +@\placeholder{MAKE-NOEXCEPT}@(rcvr.@\exposid{continuation}@.resume()); \end{codeblock} -Otherwise, \tcode{set_value(rcvr, vs...)} is ill-formed. + +\mandates +\tcode{\libconcept{constructible_from}<\exposid{result-type}, decltype((vs))...>} +is satisfied. \item The expression \tcode{set_error(rcvr, err)} is equivalent to: \begin{codeblock} -rcvr.@\exposid{result-ptr}@->template emplace<2>(@\exposid{AS-EXCEPT-PTR}@(err)); // see \ref{exec.general} -rcvr.@\exposid{continuation}@.resume(); +try { + rcvr.@\exposid{result-ptr}@->template emplace<2>(@\exposid{AS-EXCEPT-PTR}@(err)); // see \ref{exec.general} +} catch(...) { + rcvr.@\exposid{result-ptr}@->template emplace<2>(current_exception()); +} +@\placeholder{MAKE-NOEXCEPT}@(rcvr.@\exposid{continuation}@.resume()); \end{codeblock} \item The expression \tcode{set_stopped(rcvr)} is equivalent to: \begin{codeblock} -static_cast>(rcvr.@\exposid{continuation}@.promise().unhandled_stopped()).resume(); +@\placeholder{MAKE-NOEXCEPT}@( + static_cast>( + rcvr.@\exposid{continuation}@.promise().unhandled_stopped()).resume()); \end{codeblock} \item For any expression \tcode{tag} @@ -6721,7 +7126,8 @@ for any pack of subexpressions \tcode{as}, \tcode{get_env(crcvr).query(tag, as...)} is expression-equivalent to: \begin{codeblock} -tag(get_env(as_const(crcvr.@\exposid{continuation}@.promise())), as...) +tag(get_env(as_const(@\placeholder{MAKE-NOEXCEPT}@(crcvr.@\exposid{continuation}@.promise()))), + as...) \end{codeblock} \end{itemize} @@ -6735,7 +7141,7 @@ Initializes \exposid{state} with \begin{codeblock} connect(std::forward(sndr), - @\exposid{awaitable-receiver}@{addressof(result), coroutine_handle::from_promise(p)}) + @\exposid{awaitable-receiver}@{addressof(@\exposid{result}@), coroutine_handle::from_promise(p)}) \end{codeblock} \end{itemdescr} @@ -6772,29 +7178,42 @@ \tcode{\exposconcept{is-awaitable}} is \tcode{true}, where \tcode{A} is the type of the expression above. \item +Otherwise, +\begin{codeblock} +@\exposid{adapt-for-await-completion}@(transform_sender(expr, get_env(p))).as_awaitable(p) +\end{codeblock} +if this expression is well-formed, +\tcode{\libconcept{sender_in}>} is \tcode{true}, and +\tcode{\exposid{single-sen\-der-value-type}>} +is well-formed, +except that \tcode{p} is only evaluated once. +\item Otherwise, \tcode{(void(p), expr)} if \tcode{decltype(\exposid{GET-AWAITER}(expr))} satisfies \tcode{\exposconcept{is-awaiter}}. -\item -Otherwise, \tcode{\exposid{sender-awaitable}\{\exposid{adapted-expr}, p\}} -if -\begin{codeblock} -@\exposid{has-queryable-await-completion-adaptor}@ -\end{codeblock} -and +\item +Otherwise, \begin{codeblock} -@\exposid{awaitable-sender}@ +@\exposid{sender-awaitable}@{@\exposid{adapt-for-await-completion}@(transform_sender(expr, get_env(p))), p} \end{codeblock} -are both satisfied, where \exposid{adapted-expr} is -\tcode{get_await_completion_adaptor(get_env(expr))(expr)}, -except that \tcode{expr} is evaluated only once. -\item -Otherwise, \tcode{\exposid{sender-awaitable}\{expr, p\}} -if \tcode{\exposconcept{awaitable-sender}} is \tcode{true}. +if \tcode{sender_in>} is \tcode{true} and +\tcode{\exposid{single-sender-value-type}>} +is well-formed, +except that \tcode{p} is only evaluated once. \item Otherwise, \tcode{(void(p), expr)}. \end{itemize} +\pnum +\tcode{\exposid{adapt-for-await-completion}(s)} is expression-equivalent to +\begin{itemize} +\item +\tcode{get_await_completion_adaptor(get_env(s))(s)} if that is well-formed, +except that \tcode{s} is evaluated only once, +\item +otherwise, \tcode{s}. +\end{itemize} + \rSec2[exec.with.awaitable.senders]{\tcode{execution::with_awaitable_senders}} \pnum @@ -6879,65 +7298,88 @@ \end{codeblock} \end{itemdescr} -\rSec2[exec.affine.on]{\tcode{execution::affine_on}} +\rSec2[exec.affine]{\tcode{execution::affine}} \pnum -\tcode{affine_on} adapts a sender into one that completes on -the specified scheduler. +\tcode{affine} adapts a sender into one that completes on +the receiver's scheduler. If the algorithm determines that the adapted sender already completes on the correct scheduler it can avoid any scheduling operation. \pnum -The name \tcode{affine_on} denotes a pipeable sender adaptor +The name \tcode{affine} denotes a pipeable sender adaptor object. -For subexpressions \tcode{sch} and \tcode{sndr}, if \tcode{decltype((sch))} -does not satisfy \libconcept{scheduler}, or \tcode{decltype((sndr))} -does not satisfy \libconcept{sender}, \tcode{affine_on(sndr, sch)} +For a subexpression \tcode{sndr}, if \tcode{decltype((\brk{}sndr))} +does not satisfy \libconcept{sender}, \tcode{affine(sndr)} is ill-formed. \pnum -Otherwise, the expression \tcode{affine_on(sndr, sch)} is -expression-equivalent to: -\begin{codeblock} -transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(affine_on, sch, sndr)) -\end{codeblock} -except that \tcode{sndr} is evaluated only once. +Otherwise, the expression \tcode{affine(sndr)} is +expression-equivalent to \tcode{\exposid{make-sender}(affine, env<>(), sndr)}. \pnum -The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos} -is specialized for \tcode{affine_on_t} as follows: +For a subexpression \tcode{sch} whose type models \libconcept{scheduler}, +let \tcode{\exposid{UNSTOPPABLE-SCHEDULER}(sch)} be an expression \tcode{e} +whose type models \libconcept{scheduler} such that: +\begin{itemize} +\item +\tcode{schedule(e)} is expression-equivalent to \tcode{unstoppable(schedule(sch))}. +\item +For any query object \tcode{q} and pack of subexpressions \tcode{args...}, +\tcode{e.query(q, args...)} is expression-equivalent to +\tcode{sch.query(q, args...)}. +\item +The expression \tcode{e == \exposid{UNSTOPPABLE-SCHEDULER}(other)} +is expression-equivalent to \tcode{sch == other}. +\end{itemize} +\pnum +Let \tcode{sndr} and \tcode{ev} be subexpressions +such that \tcode{Sndr} is \tcode{decltype((sndr))}. +If \tcode{\exposconcept{sender-for}} is \tcode{false}, +then the expression \tcode{affine.transform_sender(sndr, ev)} is ill-formed; +otherwise, it is equal to: \begin{codeblock} -namespace std::execution { - template<> - struct @\exposid{impls-for}@ : @\exposid{default-impls}@ { - static constexpr auto @\exposid{get-attrs}@ = - [](const auto& data, const auto& child) noexcept -> decltype(auto) { - return @\exposid{JOIN-ENV}@(@\exposid{SCHED-ATTRS}@(data), @\exposid{FWD-ENV}@(get_env(child))); - }; - }; +auto& [_, _, child] = sndr; +if constexpr (requires { std::forward_like(child).affine(); }) { + return std::forward_like(child).affine(); +} else { + return continues_on(std::forward_like(child), + @\exposidnc{UNSTOPPABLE-SCHEDULER}@(get_start_scheduler(ev))); } \end{codeblock} +\pnum +\recommended +Implementations should provide \tcode{affine} member functions +for senders that are known to resume on the scheduler where they were started. +Example senders for which that is the case are +\tcode{just}, +\tcode{just_error}, +\tcode{just_stopped}, +\tcode{read_env}, and +\tcode{write_env}. + \pnum Let \tcode{\placeholder{out_sndr}} be a subexpression denoting a sender -returned from \tcode{affine_on(sndr, sch)} or one equal to such, +returned from \tcode{affine(sndr)} or one equal to such, and let \tcode{\placeholder{OutSndr}} be the type \tcode{decltype((\placeholder{out_sndr}))}. Let \tcode{\placeholder{out_rcvr}} be a subexpression denoting a receiver that -has an environment of type \tcode{Env} such that \tcode{\libconcept{sender_in}<\placeholder{OutSndr}, Env>} -is \tcode{true}. +has an environment of type \tcode{Env}. +If \tcode{get_start_scheduler(get_env(\placeholder{out_rcvr}))} is ill-formed or +does not satisfy \tcode{\exposconcept{infallible-scheduler}}, +then evaluation of +the expression \tcode{get_completion_signatures()} +exits with an exception. Let \tcode{\placeholder{op}} be an lvalue referring to the operation state that results from connecting \tcode{\placeholder{out_sndr}} to \tcode{\placeholder{out_rcvr}}. Calling \tcode{start(\placeholder{op})} will start \tcode{sndr} on the current execution agent and execute completion operations on \tcode{\placeholder{out_rcvr}} on an execution agent of the execution resource associated with -\tcode{sch}. +\tcode{\placeholder{sch}}. If the current execution resource is the same as the execution -resource associated with \tcode{sch}, the completion operation on +resource associated with \tcode{\placeholder{sch}}, the completion operation on \tcode{\placeholder{out_rcvr}} may be called before \tcode{start(\placeholder{op})} completes. -If scheduling onto \tcode{sch} fails, an error completion on -\tcode{\placeholder{out_rcvr}} shall be executed on an unspecified execution -agent. \rSec2[exec.inline.scheduler]{\tcode{execution::inline_scheduler}} @@ -6950,7 +7392,7 @@ class @\exposidnc{inline-state}@; // \expos public: - using scheduler_concept = scheduler_t; + using scheduler_concept = scheduler_tag; constexpr @\exposid{inline-sender}@ schedule() noexcept { return {}; } constexpr bool operator==(const inline_scheduler&) const noexcept = default; @@ -6962,6 +7404,11 @@ \tcode{inline_scheduler} is a class that models \libconcept{scheduler}\iref{exec.sched}. All objects of type \tcode{inline_scheduler} are equal. +For a subexpression \tcode{sch} of type \tcode{inline_scheduler}, +a query object \tcode{q}, and +a pack of subexpressions \tcode{args}, +the expression \tcode{sch.query(q, args...)} is expression-equivalent to +\tcode{\exposid{inline-attrs}().query(q, args...)}. \pnum \exposid{inline-sender} is an exposition-only type that satisfies @@ -6972,19 +7419,12 @@ \pnum Let \tcode{sndr} be an expression of type \exposid{inline-sender}, let \tcode{rcvr} be an expression such that -\tcode{\libconcept{receiver_of}} is \tcode{true} +\tcode{\exposconcept{receiver-of}} is \tcode{true} where \tcode{CS} is \tcode{completion_signatures}, -then: -\begin{itemize} -\item the expression \tcode{connect(sndr, rcvr)} has +then the expression \tcode{connect(sndr, rcvr)} has type \tcode{\exposid{inline-state}>} and is potentially-throwing if and only if -\tcode{((void)sndr, auto(rcvr))} is potentially-throwing, and -\item the expression -\tcode{get_completion_scheduler(get_env(sndr))} has -type\brk{} \tcode{inline_\-sched\-ul\-er} and is potentially-throwing -if and only if \tcode{get_env(sndr)} is potentially-throwing. -\end{itemize} +\tcode{((void)sndr, auto(rcvr))} is potentially-throwing. \pnum Let \tcode{\placeholder{o}} be a non-\tcode{const} lvalue of type @@ -7004,33 +7444,31 @@ \begin{codeblock} namespace std::execution { class @\libglobal{task_scheduler}@ { - class @\exposidnc{ts-sender}@; // \expos + class @\exposid{ts-domain}@; // \expos - template<@\libconcept{receiver}@ R> - class @\exposidnc{state}@; // \expos + template<@\libconcept{scheduler}@ Sch> + class @\exposid{backend-for}@; // \expos public: - using scheduler_concept = scheduler_t; + using scheduler_concept = scheduler_tag; template> - requires (!@\libconcept{same_as}@>) - && @\libconcept{scheduler}@ + requires (!@\libconcept{same_as}@>) && @\libconcept{scheduler}@ explicit task_scheduler(Sch&& sch, Allocator alloc = {}); task_scheduler(const task_scheduler&) = default; task_scheduler& operator=(const task_scheduler&) = default; - @\exposid{ts-sender}@ schedule(); + @\seebelow@ schedule(); - friend bool operator==(const task_scheduler& lhs, const task_scheduler& rhs) - noexcept; + friend bool operator==(const task_scheduler& lhs, const task_scheduler& rhs) noexcept; template - requires (!@\libconcept{same_as}@) - && @\libconcept{scheduler}@ + requires (!@\libconcept{same_as}@) && @\libconcept{scheduler}@ friend bool operator==(const task_scheduler& lhs, const Sch& rhs) noexcept; private: - shared_ptr @\exposidnc{sch_}@; // \expos + // see \ref{exec.parschedrepl.psb} + shared_ptr @\exposidnc{sch_}@; // \expos }; } \end{codeblock} @@ -7041,6 +7479,10 @@ Given an object \tcode{s} of type \tcode{task_scheduler}, let \tcode{\exposid{SCHED}(s)} be the object pointed to by the pointer owned by \tcode{s.\exposid{sch_}}. +The expression \tcode{get_forward_progress_guarantee(s)} is equivalent to +\tcode{get_forward_progress_guarantee(\exposid{SCHED}(s))}. +The expression \tcode{get_completion_domain(s)} is equivalent to +\tcode{task_scheduler::\exposid{ts-domain}()}. \indexlibraryctor{task_scheduler} \begin{itemdecl} @@ -7049,10 +7491,16 @@ explicit task_scheduler(Sch&& sch, Allocator alloc = {}); \end{itemdecl} \begin{itemdescr} +\pnum +\mandates +\tcode{Sch} satisfies \tcode{\exposconcept{infallible-scheduler}>}. + \pnum \effects -Initialize \exposid{sch_} with -\tcode{allocate_shared>(alloc,\brk{} std::forward\brk{}(sch))}. +Initializes \exposid{sch_} with: +\begin{codeblock} +allocate_shared<@\exposid{backend-for}@>>(alloc, std::forward(sch)) +\end{codeblock} \pnum \recommended @@ -7061,22 +7509,10 @@ \pnum \remarks -Any allocations performed by construction of \exposid{ts-sender} or -\exposid{state} objects resulting from calls on \tcode{*this} are +Any allocations performed by calls on \tcode{*this} are performed using a copy of \tcode{alloc}. \end{itemdescr} -\indexlibrarymember{scheduler}{task_scheduler}% -\begin{itemdecl} -@\exposid{ts-sender}@ schedule(); -\end{itemdecl} -\begin{itemdescr} -\pnum -\effects -Returns an object of type \exposid{ts-sender} containing a sender -initialized with \tcode{sched\-ule(\brk{}\exposid{SCHED}\brk{}(*this))}. -\end{itemdescr} - \indexlibrarymember{operator==}{task_scheduler}% \begin{itemdecl} bool operator==(const task_scheduler& lhs, const task_scheduler& rhs) noexcept; @@ -7102,77 +7538,204 @@ \end{itemdescr} \pnum +For an lvalue \tcode{r} of a type derived from \tcode{receiver_proxy}, +let \tcode{\exposid{WRAP-RCVR}(r)} be an object of a type +that models \libconcept{receiver} and +whose completion handlers result in +invoking the corresponding completion handlers of \tcode{r}. \begin{codeblock} namespace std::execution { - class task_scheduler::@\exposidnc{ts-sender}@ { // \expos + template<@\libconcept{scheduler}@ Sch> + class task_scheduler::@\exposid{backend-for}@ + : public parallel_scheduler_replacement::parallel_scheduler_backend { // \expos public: - using sender_concept = sender_t; + explicit @\exposid{backend-for}@(Sch sch) : @\exposid{sched_}@(std::move(sch)) {} - template<@\libconcept{receiver}@ Rcvr> - @\exposid{state}@ connect(Rcvr&& rcvr) &&; + void schedule(receiver_proxy& r, span s) noexcept override; + void schedule_bulk_chunked(size_t shape, bulk_item_receiver_proxy& r, + span s) noexcept override; + void schedule_bulk_unchunked(size_t shape, bulk_item_receiver_proxy& r, + span s) noexcept override; + + private: + Sch @\exposid{sched_}@; }; } \end{codeblock} -\exposid{ts-sender} is an exposition-only class that models -\libconcept{sender}\iref{exec.snd} and for which -\tcode{completion_signatures_of_t<\exposid{ts-sender}>} denotes: -\begin{codeblock} -completion_signatures< - set_value_t(), - set_error_t(error_code), - set_error_t(exception_ptr), - set_stopped_t()> -\end{codeblock} \pnum -Let \tcode{\placeholder{sch}} be an object of type \tcode{task_scheduler} -and let \tcode{sndr} be an object of type \exposid{ts-sender} obtained -from \tcode{schedule(\placeholder{sch})}. -Then \tcode{get_completion_scheduler(get_env(sndr)) == \placeholder{sch}} -is \tcode{true}. -The object \tcode{\exposid{SENDER}(sndr)} is the sender object contained by -\tcode{sndr} or an object move constructed from it. +Let \tcode{env} be a pack of subexpressions, and +let \exposid{just-sndr-like} be a sender +whose only value completion signature is \tcode{set_value_t()} and +for which the expression +\tcode{get_completion_scheduler(get_env(\exposid{just-sndr-like)}, env...)} +is expression-equivalent to +\tcode{get_completion_scheduler(\exposid{sched_}, env...)}. -\indexlibrarymember{connect}{task_scheduler::\exposid{ts-sender}}% \begin{itemdecl} -template<@\libconcept{receiver}@ Rcvr> - @\exposid{state}@ connect(Rcvr&& rcvr) &&; +void schedule(receiver_proxy& r, span s) noexcept override; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Constructs an operation state \tcode{os} +with \tcode{connect(schedule(\exposid{sched_}), \exposid{WRAP-RCVR}(r))} and +calls \tcode{start(os)}. +\end{itemdescr} + +\begin{itemdecl} +void schedule_bulk_chunked(size_t shape, bulk_item_receiver_proxy& r, + span s) noexcept override; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Let \tcode{chunk_size} be an integer less than or equal to \tcode{shape}, +let \tcode{num_chunks} be \tcode{(shape + chunk_size - 1) / chunk_size}, and +let \tcode{fn} be a function object such that +for an integer \tcode{i}, +\tcode{fn(i)} calls \tcode{r.execute(i * chunk_size, m)}, +where \tcode{m} is the lesser of \tcode{(i + 1) * chunk_size} and \tcode{shape}. +Constructs an operation state \tcode{os} as if with +\begin{codeblock} +connect(bulk(@\exposid{just-sndr-like}@, par, num_chunks, fn), @\exposid{WRAP-RCVR}@(r)) +\end{codeblock} +and calls \tcode{start(os)}. +\end{itemdescr} + +\begin{itemdecl} +void schedule_bulk_unchunked(size_t shape, bulk_item_receiver_proxy& r, + span s) noexcept override; \end{itemdecl} + \begin{itemdescr} \pnum \effects -Let \tcode{\placeholder{r}} be an object of a type that models \libconcept{receiver} -and whose completion handlers result in invoking the corresponding -completion handlers of \tcode{rcvr} or copy thereof. -Returns an object of type \tcode{\exposid{state}} containing -an operation state object initialized with \tcode{connect(\exposid{SENDER}(*this), -std::move(\placeholder{r}))}. +Let \tcode{fn} be a function object such that +for an integer \tcode{i}, +\tcode{fn(i)} is equivalent to \tcode{r.execute(i, i + 1)}. +Constructs an operation state \tcode{os} as if with +\begin{codeblock} +connect(bulk(@\exposid{just-sndr-like}@, par, shape, fn), @\exposid{WRAP-RCVR}@(r)) +\end{codeblock} +and calls \tcode{start(os)}. \end{itemdescr} +\begin{itemdecl} +@\seebelow@ schedule(); +\end{itemdecl} + +\begin{itemdescr} \pnum +\returns +A prvalue \exposid{ts-sndr} whose type models \libconcept{sender} such that: +\begin{itemize} +\item +\tcode{get_completion_scheduler(get_env(\exposid{ts-sndr}))} +is equal to \tcode{*this}. +\item +\tcode{get_completion_domain(get_env(\exposid{ts-sndr}))} +is expression-equivalent to \tcode{\exposid{ts-do\-main}()}. +\item +If a receiver \tcode{rcvr} is connected to \exposid{ts-sndr} and +the resulting operation state is started, +calls \tcode{\exposid{sch_}->schedule(r, s)}, where +\begin{itemize} +\item +\tcode{r} is a proxy for \tcode{rcvr} with base +\tcode{parallel_scheduler_replacement::receiver_proxy}\iref{exec.par.scheduler} +and +\item +\tcode{s} is a preallocated backend storage for \tcode{r}. +\end{itemize} +\item +For any type \tcode{E}, +\tcode{completion_signatures_of_t} denotes +\tcode{completion_signatures} if +\tcode{\libconcept{unstoppable_token}>} is \tcode{true}, and +otherwise \tcode{completion_signatures}. +\end{itemize} +\end{itemdescr} + \begin{codeblock} namespace std::execution { - template<@\libconcept{receiver}@ R> - class task_scheduler::@\exposidnc{state}@ { // \expos + class task_scheduler::@\exposid{ts-domain}@ : public default_domain { // \expos public: - using operation_state_concept = operation_state_t; - - void start() & noexcept; + template + static constexpr auto transform_sender(set_value_t, BulkSndr&& bulk_sndr, const Env& env) + noexcept(@\seebelow@); }; } \end{codeblock} -\exposid{state} is an exposition-only class template whose -specializations model \libconcept{operation_state}\iref{exec.opstate}. -\indexlibrarymember{start}{task_scheduler::\exposid{state}}% \begin{itemdecl} -void start() & noexcept; +template + static constexpr auto transform_sender(BulkSndr&& bulk_sndr, const Env& env) + noexcept(is_nothrow_constructible_v, BulkSndr>); \end{itemdecl} + \begin{itemdescr} +\pnum +\constraints +\begin{itemize} +\item +\tcode{\libconcept{sender_in}} is \tcode{true}, +\item +\tcode{auto(std::forward(bulk_sndr))} is well-formed, and +\item +either +\begin{itemize} +\item +\tcode{\exposconcept{sender-for}} or +\item +\tcode{\exposconcept{sender-for}} +\end{itemize} +is \tcode{true}. +\end{itemize} + \pnum \effects -Equivalent to \tcode{start(st)} where \tcode{st} is the operation -state object contained by \tcode{*this}. +Equivalent to: +\begin{codeblock} +auto& [_, data, child] = bulk_sndr; +auto& [_, shape, fn] = data; +auto sch = @\exposidnc{call-with-default}@(get_completion_scheduler, + @\exposidnc{not-a-scheduler}@(), get_env(child), @\exposidnc{FWD-ENV}@(env)); +return @$e$@; +\end{codeblock} +where $e$ is \tcode{\exposid{not-a-sender}()} +if the type of \tcode{sch} is not \tcode{task_scheduler}; +otherwise, it is a prvalue whose type models \libconcept{sender} such that, +if it is connected to a receiver \tcode{rcvr} and +the resulting operation state is started, +\tcode{child} is connected to an unspecified receiver \tcode{R} and started. +The expression \tcode{get_env(R)} +is expression-equivalent to \tcode{\exposid{FWD-ENV}(get_env(\exposid{rcvr-copy}))}, +where \exposid{rcvr-copy} is an lvalue subexpression +designating an object decay-copied from \tcode{rcvr}. + +If \tcode{child} completes with an error or a stopped completion, +the completion operation is forwarded unchanged to \tcode{rcvr}. +Otherwise, let \tcode{args} be a pack of lvalue subexpressions +designating objects decay-copied from the value result datums. +Then: +\begin{itemize} +\item +If \tcode{bulk_sndr} was the result of the evaluation of +an expression equivalent to \tcode{bulk_chunked(child, policy, shape, fn)} or +a copy of such, +then \tcode{\exposid{sch_}->schedule_bulk_chunked(shape, r, s)} is called +where \tcode{r} is a bulk chunked proxy\iref{exec.par.scheduler} +for \tcode{rcvr} with callable \tcode{fn} and arguments \tcode{args}, and +\tcode{s} is a preallocated backend storage for \tcode{r}. +\item +Otherwise, calls \tcode{\exposid{sch_}->schedule_bulk_unchunked(shape, r, s)} +where \tcode{r} is a bulk unchunked proxy for \tcode{rcvr} +with callable \tcode{fn} and arguments \tcode{args}, and +\tcode{s} is a preallocated backend storage for \tcode{r}. +\end{itemize} \end{itemdescr} \rSec2[exec.task]{\tcode{execution::task}} @@ -7201,10 +7764,9 @@ class @\exposidnc{state}@; // \expos public: - using sender_concept = sender_t; - using completion_signatures = @\seebelow@; + using sender_concept = sender_tag; using allocator_type = @\seebelow@; - using scheduler_type = @\seebelow@; + using start_scheduler_type = @\seebelow@; using stop_source_type = @\seebelow@; using stop_token_type = decltype(declval().get_token()); using error_types = @\seebelow@; @@ -7215,6 +7777,9 @@ task(task&&) noexcept; ~task(); + template + static consteval auto get_completion_signatures(); + template<@\libconcept{receiver}@ Rcvr> @\exposid{state}@ connect(Rcvr&& rcvr) &&; @@ -7238,7 +7803,7 @@ \item \tcode{allocator_type} is \tcode{Environment::allocator_type} if that \grammarterm{qualified-id} is valid and denotes a type, \tcode{allocator} otherwise. -\item \tcode{scheduler_type} is \tcode{Environment::scheduler_type} +\item \tcode{start_scheduler_type} is \tcode{Environment::start_scheduler_type} if that \grammarterm{qualified-id} is valid and denotes a type, \tcode{task_scheduler} otherwise. \item \tcode{stop_source_type} is \tcode{Environment::stop_source_type} @@ -7257,21 +7822,9 @@ \tcode{set_error_t(E)} for some type \tcode{E}. \pnum -The type alias \tcode{completion_signatures} is a specialization -of \tcode{execution::completion_signatures} with the template -arguments (in unspecified order): -\begin{itemize} -\item \tcode{set_value_t()} if \tcode{T} is \tcode{void}, -and \tcode{set_value_t(T)} otherwise; -\item template arguments of the specialization of -\tcode{execution::completion_signatures} denoted by \tcode{error_types}; -and -\item \tcode{set_stopped_t()}. -\end{itemize} - -\pnum -\tcode{allocator_type} shall meet the \oldconcept{Allocator} -requirements. +\tcode{allocator_type} shall meet the \oldconcept{Allocator} requirements, +\tcode{scheduler_type} shall model \libconcept{scheduler}, and +\tcode{stop_source_type} shall model \exposconcept{stoppable-source}. \rSec3[task.members]{\tcode{task} members} @@ -7300,12 +7853,45 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{get_completion_signatures}{task}% +\begin{itemdecl} +template + static consteval auto get_completion_signatures(); +\end{itemdecl} +\begin{itemdescr} +\pnum +Let the type \tcode{C} be a specialization +of \tcode{execution::completion_signatures} +with the template arguments (in unspecified order): +\begin{itemize} +\item +\tcode{set_value_t()} if \tcode{T} is \tcode{void}, +and \tcode{set_value_t(T)} otherwise; +\item +template arguments of the specialization of +\tcode{execution::completion_signatures} denoted by \tcode{error_types}; +and +\item \tcode{set_stopped_t()}. +\end{itemize} + +\pnum +\returns +\tcode{C()}. +\end{itemdescr} + \indexlibrarymember{connect}{task}% \begin{itemdecl} template<@\libconcept{receiver}@ Rcvr> @\exposid{state}@ connect(Rcvr&& recv) &&; \end{itemdecl} \begin{itemdescr} +\pnum +\mandates +At least one of the expressions +\tcode{allocator_type(get_allocator(get_env(rcvr)))} and +\tcode{allocator_type()} +is well-formed. + \pnum \expects \tcode{bool(\exposid{handle})} is \tcode{true}. @@ -7326,7 +7912,7 @@ template<@\libconcept{receiver}@ Rcvr> class task::@\exposidnc{state}@ { // \expos public: - using operation_state_concept = operation_state_t; + using operation_state_concept = operation_state_tag; template @\exposid{state}@(coroutine_handle h, R&& rr); @@ -7335,12 +7921,17 @@ void start() & noexcept; + stop_token_type @\exposidnc{get-stop-token}@(); // \expos + private: using @\exposidnc{own-env-t}@ = @\seebelownc@; // \expos coroutine_handle @\exposidnc{handle}@; // \expos remove_cvref_t @\exposidnc{rcvr}@; // \expos + optional @\exposidnc{source}@; // \expos @\exposidnc{own-env-t}@ @\exposidnc{own-env}@; // \expos Environment @\exposidnc{environment}@; // \expos + optional @\exposidnc{result}@; // \expos; present only if \tcode{is_void_v} is \tcode{false} + exception_ptr @\exposidnc{error}@; // \expos }; } \end{codeblock} @@ -7402,28 +7993,36 @@ \item \tcode{\exposid{STATE}(\placeholder{prom})} is \tcode{*this}. \item \tcode{\exposid{RCVR}(\placeholder{prom})} is \exposid{rcvr}. \item \tcode{\exposid{SCHED}(\placeholder{prom})} is the object initialized -with \tcode{scheduler_type(get_scheduler(get_env(\exposid{rcvr})))} -if that expression is valid and \tcode{scheduler_type()} otherwise. +with \tcode{start_scheduler_type(get_start_scheduler(get_env(\exposid{rcvr})))} +if that expression is valid and \tcode{start_scheduler_type()} otherwise. If neither of these expressions is valid, the program is ill-formed. \end{itemize} -Let \tcode{\placeholder{st}} be \tcode{get_stop_token(get_env(\exposid{rcvr}))}. -Initializes \tcode{\placeholder{prom}.\exposid{token}} and -\tcode{\placeholder{prom}.\exposid{source}} such that +Finally, invokes \tcode{\exposid{handle}.resume()}. +\end{itemdescr} + +\indexlibrarymember{\exposid{get-stop-token}}{task::\exposid{state}}% +\begin{itemdecl} +stop_token_type @\exposidnc{get-stop-token}@(); // \expos +\end{itemdecl} +\begin{itemdescr} +\pnum +\effects +If +\tcode{\libconcept{same_as}().get_token()), decltype(get_\linebreak{}stop_token(get_env(\exposid{rcvr})))>} +is \tcode{true}, +returns \tcode{get_stop_token(get_env(\exposid{rcvr}))}. +Otherwise, if \tcode{\exposid{source}.has_value()} is \tcode{false}, +initializes the contained value of \exposid{source} such that \begin{itemize} \item -\tcode{\placeholder{prom}.\exposid{token}.stop_requested()} returns -\tcode{\placeholder{st}.stop_requested()}; -\item -\tcode{\placeholder{prom}.\exposid{token}.stop_possible()} returns -\tcode{\placeholder{st}.stop_possible()}; and +\tcode{\exposid{source}->stop_requested()} returns +\tcode{get_stop_token(get_env(\exposid{rcvr}))->stop_requested()};\linebreak +and \item -for types \tcode{Fn} and \tcode{Init} such that both -\tcode{\libconcept{invocable}} and -\tcode{\libconcept{constructible_from}} are modeled, -\tcode{stop_token_type::callback_type} models -\tcode{\exposconcept{stoppable-callback-for}}. +\tcode{\exposid{source}->stop_possible()} returns +\tcode{get_stop_token(get_env(\exposid{rcvr}))->stop_possible()}. \end{itemize} -After that invokes \tcode{\exposid{handle}.resume()}. +Finally, returns \tcode{\exposid{source}->get_token()}. \end{itemdescr} \rSec3[task.promise]{Class \tcode{task::promise_type}} @@ -7433,9 +8032,6 @@ template class task::promise_type { public: - template - promise_type(const Args&... args); - task get_return_object() noexcept; static constexpr suspend_always @\libmember{initial_suspend}{task::promise_type}@() noexcept { return {}; } @@ -7451,26 +8047,18 @@ template @\unspec@ yield_value(with_error error); - template - auto await_transform(A&& a); - template - auto await_transform(change_coroutine_scheduler sch); + template<@\libconcept{sender}@ Sender> + auto await_transform(Sender&& sndr); @\unspec@ get_env() const noexcept; - template - void* operator new(size_t size, Args&&... args); + void* operator new(size_t size); + template + void* operator new(size_t size, allocator_arg_t, Alloc alloc, Args&&...); + template + void* operator new(size_t size, const This&, allocator_arg_t, Alloc alloc, Args&&...); void operator delete(void* pointer, size_t size) noexcept; - - private: - using @\exposidnc{error-variant}@ = @\seebelownc@; // \expos - - allocator_type @\exposidnc{alloc}@; // \expos - stop_source_type @\exposidnc{source}@; // \expos - stop_token_type @\exposidnc{token}@; // \expos - optional @\exposidnc{result}@; // \expos; present only if \tcode{is_void_v} is \tcode{false} - @\exposidnc{error-variant}@ @\exposidnc{errors}@; // \expos }; } \end{codeblock} @@ -7487,32 +8075,6 @@ during evaluation of \tcode{task::\exposid{state}::start} for some receiver \tcode{Rcvr}. -\pnum -\exposid{error-variant} is a \tcode{variant...>}, with duplicate types removed, where \tcode{E...} -are the parameter types of the template arguments of the specialization of -\tcode{execution::completion_signatures} denoted by -\tcode{error_types}. - -\indexlibraryctor{task::promise_type}% -\begin{itemdecl} -template - promise_type(const Args&... args); -\end{itemdecl} -\begin{itemdescr} -\pnum -\mandates -The first parameter of type \tcode{allocator_arg_t} (if any) is not -the last parameter. - -\pnum -\effects -If \tcode{Args} contains an element of type \tcode{allocator_arg_t} -then \exposid{alloc} is initialized with the corresponding next -element of \tcode{args}. -Otherwise, \exposid{alloc} is initialized with \tcode{allocator_type()}. -\end{itemdescr} - \indexlibrarymember{get_return_object}{task::promise_type}% \begin{itemdecl} task get_return_object() noexcept; @@ -7533,17 +8095,19 @@ \returns An awaitable object of unspecified type\iref{expr.await} whose member functions arrange for the completion of the asynchronous -operation associated with \tcode{\exposid{STATE}(*this)} by invoking: +operation associated with \tcode{\exposid{STATE}(*this)}. +Let \tcode{st} be a reference to \tcode{\exposid{STATE}(*this)}. +The asynchronous completion first destroys the coroutine frame +using \tcode{st.\exposid{handle}.destroy()} and then invokes: \begin{itemize} \item -\tcode{set_error(std::move(\exposid{RCVR}(*this)), std::move(e))} -if \tcode{\exposid{errors}.index()} is greater than zero and -\tcode{e} is the value held by \exposid{errors}, otherwise +\tcode{set_error(std::move(st.\exposid{rcvr}), std::move(st.\exposid{error}))} +if \tcode{bool(st.\exposid{error})} is \tcode{true}, otherwise \item -\tcode{set_value(std::move(\exposid{RCVR}(*this)))} if \tcode{is_void} is \tcode{true}, +\tcode{set_value(std::move(st.\exposid{rcvr}))} if \tcode{is_void_v} is \tcode{true}, and otherwise \item - \tcode{set_value(std::move(\exposid{RCVR}(*this)), *\exposid{result})}. + \tcode{set_value(std::move(st.\exposid{rcvr}), *std::move(st.\exposid{result}))}. \end{itemize} \end{itemdescr} @@ -7564,36 +8128,27 @@ An awaitable object of unspecified type\iref{expr.await} whose member functions arrange for the calling coroutine to be suspended and then completes the asynchronous operation associated with -\tcode{\exposid{STATE}(*this)} by invoking \tcode{set_error(std::move(\exposid{RCVR}(*this)), +\tcode{\exposid{STATE}(*this)}. +Let \tcode{st} be a reference to \tcode{\exposid{STATE}(*this)}. +Then the asynchronous operation completes by first +destroying the coroutine frame using \tcode{st.\exposid{handle}.destroy()} +and then invoking +\tcode{set_error(std::move(st.\exposid{rcvr}), \placeholder{Cerr}(std::move(err.error)))}. \end{itemdescr} \indexlibrarymember{await_transform}{task::promise_type}% \begin{itemdecl} template<@\libconcept{sender}@ Sender> - auto await_transform(Sender&& sndr) noexcept; + auto await_transform(Sender&& sndr); \end{itemdecl} \begin{itemdescr} \pnum \returns -If \tcode{\libconcept{same_as}} is \tcode{true} -returns \tcode{as_awaitable(\brk{}std::\brk{}for\-ward(sndr), *this)}; -otherwise returns -\tcode{as_awaitable(affine_on(\brk{}std::\brk{}for\-ward(sndr), \exposid{SCHED}(*this)), *this)}. -\end{itemdescr} - -\indexlibrarymember{await_transform}{task::promise_type}% -\begin{itemdecl} -template - auto await_transform(change_coroutine_scheduler sch) noexcept; -\end{itemdecl} -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -return await_transform(just(exchange(@\exposid{SCHED}@(*this), scheduler_type(sch.scheduler))), *this); -\end{codeblock} +If \tcode{\libconcept{same_as}} +is \tcode{true}, +returns \tcode{as_awaitable(\brk{}std::forward(sndr), *this)}; +otherwise returns \tcode{as_awaitable(affine(std::forward<\brk{}Sender>(sndr)), *this)}. \end{itemdescr} \indexlibrarymember{unhandled_exception}{task::promise_type}% @@ -7605,7 +8160,8 @@ \effects If the signature \tcode{set_error_t(exception_ptr)} is not an element of \tcode{error_types}, calls \tcode{terminate()}\iref{except.terminate}. -Otherwise, stores \tcode{current_exception()} into \exposid{errors}. +Otherwise, stores \tcode{current_exception()} into +\tcode{\exposid{STATE}(*this).\exposid{error}}. \end{itemdescr} \indexlibrarymember{unhandled_stopped}{task::promise_type}% @@ -7615,8 +8171,12 @@ \begin{itemdescr} \pnum \effects -Completes the asynchronous operation associated with \tcode{\exposid{STATE}(*this)} -by invoking \tcode{set_stopped(std::move(\exposid{RCVR}(*this)))}. +Completes the asynchronous operation associated with \tcode{\exposid{STATE}(*this)}. +Let \tcode{st} be a reference to \tcode{\exposid{STATE}(*this)}. +The asynchronous operation is completed by first +destroying the coroutine frame +using \tcode{st.\exposid{handle}.destroy()} and then +invoking \tcode{set_stopped(std::move(st.\exposid{rcvr}))}. \end{itemdescr} \begin{itemdescr} \pnum @@ -7654,12 +8214,17 @@ \returns An object \tcode{env} such that queries are forwarded as follows: \begin{itemize} -\item \tcode{env.query(get_scheduler)} returns \tcode{scheduler_type(\exposid{SCHED}(*this))}. -\item \tcode{env.query(get_allocator)} returns \exposid{alloc}. -\item \tcode{env.query(get_stop_token)} returns \exposid{token}. +\item \tcode{env.query(get_start_scheduler)} returns +\tcode{start_scheduler_type(\exposid{SCHED}(*this))}. +\item \tcode{env.query(get_allocator)} returns +\tcode{allocator_type(get_allocator(get_env(\exposid{RCVR}(*this))\brk{}))} +if this expression is well-formed and +\tcode{allocator_type()} otherwise. +\item \tcode{env.query(get_stop_token)} returns +\tcode{\exposid{STATE}(*this).\exposid{get-stop-token}()}. \item For any other query \tcode{q} and arguments \tcode{a...} a call to \tcode{env.query(q, a...)} returns -\tcode{\exposid{STATE}(*this)}. \tcode{environment.query(q, a...)} if this expression +\tcode{\exposid{STATE}(*this)}. \tcode{\exposid{environment}.query(q, a...)} if this expression is well-formed and \tcode{forwarding_query(q)} is well-formed and is \tcode{true}. Otherwise \tcode{env.query(q, a...)} is ill-formed. \end{itemize} @@ -7667,28 +8232,33 @@ \indexlibrarymember{operator new}{task::promise_type}% \begin{itemdecl} -template - void* operator new(size_t size, const Args&... args); +void* operator new(size_t size); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return operator new(size, allocator_arg, allocator_type());} +\end{itemdescr} + +\indexlibrarymember{operator new}{task::promise_type}% +\begin{itemdecl} +template + void* operator new(size_t size, allocator_arg_t, Alloc alloc, Args&&...); +template + void* operator new(size_t size, const This&, allocator_arg_t, Alloc alloc, Args&&...); \end{itemdecl} \begin{itemdescr} \pnum -If there is no parameter with type \tcode{allocator_arg_t} then let -\tcode{alloc} be \tcode{allocator_type()}. -Otherwise, let \tcode{arg_next} be the parameter -following the first \tcode{allocator_arg_t} parameter, -and let \tcode{alloc} be \tcode{allocator_type(arg_next)}. -Let \tcode{PAlloc} be \tcode{allocator_traits::template -rebind_alloc}, where \tcode{U} is an unspecified type +Let \tcode{PAlloc} be +\tcode{allocator_traits::template rebind_alloc}, +where \tcode{U} is an unspecified type whose size and alignment are both \mname{STDCPP_DEFAULT_NEW_ALIGNMENT}. \pnum \mandates -\begin{itemize} -\item The first parameter of type \tcode{allocator_arg_t} (if any) is not the last parameter. -\item \tcode{allocator_type(arg_next)} is a valid expression if there is a parameter -of type \tcode{allocator_arg_t}. -\item \tcode{allocator_traits::pointer} is a pointer type. -\end{itemize} +\tcode{allocator_traits::pointer} is a pointer type. \pnum \effects @@ -7954,7 +8524,7 @@ template struct @\exposid{state}@ { // \expos struct @\exposid{rcvr-t}@ { // \expos - using receiver_concept = receiver_t; + using receiver_concept = receiver_tag; Rcvr& @\exposid{rcvr}@; // \expos @@ -7977,7 +8547,7 @@ }; using @\exposid{sched-sender}@ = // \expos - decltype(schedule(get_scheduler(get_env(declval())))); + decltype(schedule(get_start_scheduler(get_env(declval())))); using @\exposid{op-t}@ = // \expos connect_result_t<@\exposid{sched-sender}@, @\exposid{rcvr-t}@>; @@ -7989,7 +8559,7 @@ noexcept(@\exposconcept{nothrow-callable}@) : @\exposid{scope}@(scope), @\exposid{receiver}@(rcvr), - @\exposid{op}@(connect(schedule(get_scheduler(get_env(rcvr))), @\exposid{rcvr-t}@(rcvr))) {} + @\exposid{op}@(connect(schedule(get_start_scheduler(get_env(rcvr))), @\exposid{rcvr-t}@(rcvr))) {} void @\exposid{complete}@() noexcept { // \expos start(@\exposid{op}@); @@ -8066,7 +8636,7 @@ size_t @\exposid{count}@; // \expos @\exposid{scope-state-type}@ @\exposid{state}@; // \expos - @\exposid{assoc-t}@ @\exposid{try-associate}@() noexcept; // \expos + @\exposid{assoc-t}@ @\exposid{try-associate}@() noexcept; // \expos void @\exposid{disassociate}@() noexcept; // \expos template bool @\exposid{start-join-sender}@(State& state) noexcept; // \expos @@ -8226,12 +8796,11 @@ \begin{itemdescr} \pnum \effects -If \exposid{state} is +If \tcode{count} is zero, then +changes \exposid{state} to \exposid{joined} and returns \tcode{true}. +Otherwise, if \exposid{state} is \begin{itemize} \item -\exposid{unused}, \exposid{unused-and-closed}, or \exposid{joined}, then -changes \exposid{state} to \exposid{joined} and returns \tcode{true}; -\item \exposid{open} or \exposid{open-and-joining}, then changes \exposid{state} to \exposid{open-and-joining}, registers \tcode{st} with \tcode{*this} and returns \tcode{false}; @@ -8469,24 +9038,6 @@ for operations launched via calls to \tcode{parallel_scheduler_backend}. \end{note} -\pnum -A \defnx{bulk chunked proxy for \tcode{rcvr} -with callable \tcode{f} and arguments \tcode{args}}{proxy!bulk chunked} -is a proxy \tcode{r} for \tcode{rcvr} -with base \tcode{system_context_replaceability::bulk_item_receiver_proxy} -such that -\tcode{r.execute(i, j)} for indices \tcode{i} and \tcode{j} -has effects equivalent to \tcode{f(i, j, args...)}. - -\pnum -A \defnx{bulk unchunked proxy for \tcode{rcvr} -with callable \tcode{f} and arguments \tcode{args}}{proxy!bulk unchunked} -is a proxy \tcode{r} for \tcode{rcvr} -with base \tcode{system_context_replaceability::bulk_item_receiver_proxy} -such that -\tcode{r.execute(i, i + 1)} for index \tcode{i} -has effects equivalent to \tcode{f(i, args...)}. - \pnum Let \tcode{b} be \tcode{\exposid{BACKEND-OF}(sch)}, let \tcode{sndr} be the object returned by \tcode{schedule(sch)}, and @@ -8500,7 +9051,7 @@ \begin{itemize} \item \tcode{r} is a proxy for \tcode{rcvr} -with base \tcode{system_context_replaceability::receiver_proxy} and +with base \tcode{parallel_scheduler_replacement::receiver_proxy} and \item \tcode{s} is a preallocated backend storage for \tcode{r}. \end{itemize} @@ -8509,46 +9060,93 @@ \end{itemize} \pnum -\tcode{parallel_scheduler} provides a customized implementation of -the \tcode{bulk_chunked} algorithm\iref{exec.bulk}. -If a receiver \tcode{rcvr} is connected to the sender -returned by \tcode{bulk_chunked(sndr, pol, shape, f)} and +The expression \tcode{get_domain(sch)} +returns an expression of exposition-only type +\exposid{parallel-scheduler-do\-main}, that is equivalent with: + +\begin{codeblock} +struct @\exposid{parallel-scheduler-domain}@ { + template<@\exposconcept{sender-for}@ Sndr, @\exposconcept{queryable}@ Env> + static constexpr decltype(auto) + transform_sender(set_value_t, Sndr&& sndr, const Env& env) const noexcept { + return @\seebelow@; + } + template<@\exposconcept{sender-for}@ Sndr, @\exposconcept{queryable}@ Env> + static constexpr decltype(auto) + transform_sender(set_value_t, Sndr&& sndr, const Env& env) const noexcept { + return @\seebelow@; + } +}; +\end{codeblock} + +\pnum +For argument \tcode{sndr} of the above \tcode{transform_sender}, +let \tcode{child}, \tcode{pol}, \tcode{shape} and \tcode{f} +be defined by the following declarations: +\begin{codeblock} +auto& [_, data, child] = sndr; +auto& [pol, shape, f] = data; +\end{codeblock} + +\pnum +Let \tcode{p} be +\begin{itemize} +\item +\tcode{true}, if the type of the expression \tcode{pol} is +\cv{}~\tcode{parallel_policy} or \cv{}~\tcode{parallel_unsequenced_policy}; +\item +\impldef{parallelism flag for an implementation-defined execution policy}, +if \tcode{pol} is an implementation-defined execution policy; +\item +\tcode{false}, otherwise. +\end{itemize} + +\pnum +The \tcode{transform_sender} overload +that accepts senders with tag \tcode{bulk_chunked_t} +returns a sender such that if it is connected to a receiver \tcode{rcvr} and the resulting operation state is started, then: \begin{itemize} \item -If \tcode{sndr} completes with values \tcode{vals}, +If \tcode{child} completes with values \tcode{vals}, let \tcode{args} be a pack of lvalue subexpressions designating \tcode{vals}, -then \tcode{b.schedule_bulk_chunked(shape, r, s)} is called, where +then \tcode{b.schedule_bulk_chunked(p ? shape : 1, r, s)} is called, where \begin{itemize} \item -\tcode{r} is a bulk chunked proxy for \tcode{rcvr} -with callable \tcode{f} and arguments \tcode{args} and +\tcode{r} is a proxy for \tcode{rcvr} +with base \tcode{parallel_scheduler_replacement::bulk_item_receiver_proxy} +such that \tcode{r.execute(i, j)} for indices \tcode{i} and \tcode{j} +has effects equivalent to +\tcode{f(i, j, args...)} if \tcode{p} is true and +\tcode{f(0, shape, args...)} otherwise; and \item \tcode{s} is a preallocated backend storage for \tcode{r}. \end{itemize} \item All other completion operations are forwarded unchanged. \end{itemize} -\begin{note} -Customizing the behavior of \tcode{bulk_chunked} -affects the default implementation of \tcode{bulk}. -\end{note} \pnum -\tcode{parallel_scheduler} provides a customized implementation of -the \tcode{bulk_unchunked} algorithm\iref{exec.bulk}. -If a receiver \tcode{rcvr} is connected to the sender -returned by \tcode{bulk_unchunked(sndr, pol, shape, f)} and +The \tcode{transform_sender} overload +that accepts senders with tag \tcode{bulk_unchunked_t} +returns a sender such that if it is connected to a receiver \tcode{rcvr} and the resulting operation state is started, then: \begin{itemize} \item -If \tcode{sndr} completes with values \tcode{vals}, +If \tcode{child} completes with values \tcode{vals}, let \tcode{args} be a pack of lvalue subexpressions designating \tcode{vals}, -then \tcode{b.schedule_bulk_unchunked(shape, r, s)} is called, where +then \tcode{b.schedule_bulk_unchunked(p ? shape : 1, r, s)} is called, where \begin{itemize} \item -\tcode{r} is a bulk unchunked proxy for \tcode{rcvr} -with callable \tcode{f} and arguments \tcode{args} and +\tcode{r} is a proxy for \tcode{rcvr} +with base \tcode{parallel_scheduler_replacement::bulk_item_receiver_proxy} +such that \tcode{r.execute(i, i + 1)} for index \tcode{i} +has effects equivalent to +\tcode{f(i, args...)} if \tcode{p} is true and +\begin{codeblock} +for (decltype(shape) i = 0; i < shape; i++) { f(i, args...); } +\end{codeblock} +otherwise; and \item \tcode{s} is a preallocated backend storage for \tcode{r}. \end{itemize} @@ -8564,28 +9162,26 @@ \begin{itemdescr} \pnum \effects -Let \tcode{eb} be the result of \tcode{system_context_replaceability::query_parallel_scheduler_backend()}. +Let \tcode{eb} be the result of \tcode{parallel_scheduler_replacement::query_parallel_scheduler_backend()}. If \tcode{eb == nullptr} is \tcode{true}, calls \tcode{terminate}\iref{except.terminate}. Otherwise, returns a \tcode{parallel_scheduler} object associated with \tcode{eb}. \end{itemdescr} -\rSec1[exec.sysctxrepl]{Namespace \tcode{system_context_replaceability}} +\rSec1[exec.parschedrepl]{Namespace \tcode{parallel_scheduler_replacement}} -\rSec2[exec.sysctxrepl.general]{General} +\rSec2[exec.parschedrepl.general]{General} \pnum -Facilities in the \tcode{system_context_replaceability} namespace +Facilities in the \tcode{parallel_scheduler_replacement} namespace allow users to replace the default implementation of \tcode{parallel_scheduler}. -\rSec2[exec.sysctxrepl.recvproxy]{Receiver proxies} +\rSec2[exec.parschedrepl.recvproxy]{Receiver proxies} \begin{codeblock} -namespace std::execution::system_context_replaceability { +namespace std::execution::parallel_scheduler_replacement { struct @\libglobal{receiver_proxy}@ { - virtual ~receiver_proxy() = default; - protected: virtual bool @\exposidnc{query-env}@(@\unspecnc@) noexcept = 0; // \expos @@ -8595,7 +9191,7 @@ virtual void set_stopped() noexcept = 0; template - optional

try_query(Query q) noexcept; + optional

try_query(Query q) const noexcept; }; struct @\libglobal{bulk_item_receiver_proxy}@ : receiver_proxy { @@ -8617,7 +9213,7 @@ \begin{itemdecl} template - optional

@\libglobal{try_query}@(Query q) noexcept; + optional

@\libglobal{try_query}@(Query q) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -8637,11 +9233,14 @@ \tcode{P} is not a member of an implementation-defined set of supported result types for \tcode{Query}; or \item -the expression \tcode{q(env)} is not well-formed or -does not have type \cv{} \tcode{P}, +the expression \tcode{q(env)} is not well-formed, \end{itemize} then returns \tcode{nullopt}. -Otherwise, returns \tcode{q(env)}. +Otherwise, if \tcode{q(env)} has type \cv{}~\tcode{P}, +then returns \tcode{q(env)}. +Otherwise, returns an +\impldef{return value of \tcode{receiver_proxy::try_query}} value +of type \tcode{optional

}. \pnum \remarks @@ -8650,9 +9249,22 @@ \tcode{inplace_stop_token} is a member of the implementation-defined set of supported result types for \tcode{get_stop_token_t}. + +\pnum +\recommended +If \tcode{P} is \tcode{inplace_stop_token} and +\tcode{T} is a type other than \tcode{inplace_stop_token} +that models \libconcept{stoppable_token}, +\tcode{try_query} should return an object of type \tcode{inplace_stop_token} +such that until one of +\tcode{set_value}, +\tcode{set_error} or +\tcode{set_stopped} +is called on \tcode{*this}, +all calls to \tcode{try_query} return equivalent \tcode{inplace_stop_token} objects. \end{itemdescr} -\rSec2[exec.sysctxrepl.query]{\tcode{query_parallel_scheduler_backend}} +\rSec2[exec.parschedrepl.query]{\tcode{query_parallel_scheduler_backend}} \indexlibraryglobal{query_parallel_scheduler_backend}% \begin{itemdecl} @@ -8679,10 +9291,10 @@ This function is replaceable\iref{term.replaceable.function}. \end{itemdescr} -\rSec2[exec.sysctxrepl.psb]{Class \tcode{parallel_scheduler_backend}} +\rSec2[exec.parschedrepl.psb]{Class \tcode{parallel_scheduler_backend}} \begin{codeblock} -namespace std::execution::system_context_replaceability { +namespace std::execution::parallel_scheduler_replacement { struct @\libglobal{parallel_scheduler_backend}@ { virtual ~parallel_scheduler_backend() = default; diff --git a/source/expressions.tex b/source/expressions.tex index 869c3de36a..42cfd25cea 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -64,7 +64,7 @@ \indextext{zero!remainder undefined}% If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for -its type, the behavior is undefined. +its type, the behavior is undefined\ubdef{expr.expr.eval}. \begin{note} \indextext{overflow}% Treatment of division by zero, forming a remainder using a zero divisor, @@ -95,7 +95,7 @@ \end{codeblock} due to the associativity and precedence of these operators. Thus, the result of the sum \tcode{(a + 32760)} is next added to \tcode{b}, and -that result is then added to 5 which results in the value assigned to +that result is then added to \tcode{5} which results in the value assigned to \tcode{a}. On a machine in which overflows produce an exception and in which the range of values representable by an \tcode{int} is \crange{-32768}{+32767}, the implementation cannot rewrite this @@ -317,7 +317,7 @@ If a program attempts to access\iref{defns.access} the stored value of an object through a glvalue through which it is not type-accessible, -the behavior is undefined. +the behavior is undefined\ubdef{expr.basic.lvalue.strict.aliasing.violation}. \begin{footnote} The intent of this list is to specify those circumstances in which an object can or cannot be aliased. @@ -326,7 +326,7 @@ a defaulted copy/move constructor or copy/move assignment operator for a union of type \tcode{U} with a glvalue argument that does not denote an object of type \cv{}~\tcode{U} within its lifetime, -the behavior is undefined. +the behavior is undefined\ubdef{expr.basic.lvalue.union.initialization}. \begin{note} In C, an entire object of structure type can be accessed, e.g., using assignment. By contrast, \Cpp{} has no notion of accessing an object of class type @@ -345,7 +345,7 @@ If a pointer to $X$ would be valid in the context of the evaluation of the expression\iref{basic.fundamental}, the result designates $X$; -otherwise, the behavior is undefined. +otherwise, the behavior is undefined\ubdef{expr.type.reference.lifetime}. \begin{note} Before the lifetime of the reference has started or after it has ended, the behavior is undefined (see~\ref{basic.life}). @@ -686,7 +686,7 @@ \item Otherwise, if the bits in the value representation of the object to which the glvalue refers -are not valid for the object's type, the behavior is undefined. +are not valid for the object's type, the behavior is undefined\ubdef{conv.lval.valid.representation}. \begin{example} \begin{codeblock} bool f() { @@ -989,7 +989,7 @@ that exact representation. If the source value is between two adjacent destination values, the result of the conversion is an \impldef{result of inexact floating-point conversion} choice of either of those values. -Otherwise, the behavior is undefined. +Otherwise, the behavior is undefined\ubdef{conv.double.out.of.range}. \pnum The conversions allowed as floating-point promotions are excluded from @@ -1003,7 +1003,7 @@ integer type. The conversion truncates; that is, the fractional part is discarded. \indextext{value!undefined unrepresentable integral}% -The behavior is undefined if the truncated value cannot be represented +The behavior is undefined\ubdef{conv.fpint.float.not.represented} if the truncated value cannot be represented in the destination type. \begin{note} If the destination type is \keyword{bool}, see~\ref{conv.bool}. @@ -1024,7 +1024,9 @@ exactly as a value of the floating-point type. \end{note} If the value being converted is -outside the range of values that can be represented, the behavior is undefined. If the +outside the range of values that can be represented, +the behavior is undefined\ubdef{conv.fpint.int.not.represented}. +If the source type is \keyword{bool}, the value \keyword{false} is converted to zero and the value \keyword{true} is converted to one. @@ -1077,7 +1079,7 @@ that is within its lifetime or within its period of construction or destruction\iref{class.cdtor}, -the behavior is undefined. +the behavior is undefined\ubdef{conv.ptr.virtual.base}. Otherwise, the result is a pointer to the base class subobject of the derived class object. @@ -1111,7 +1113,8 @@ \tcode{D}, a program that necessitates this conversion is ill-formed. If class \tcode{D} does not contain the original member and is not a base class of the class containing the original member, -the behavior is undefined. Otherwise, +the behavior is undefined\ubdef{conv.member.missing.member}. +Otherwise, the result of the conversion refers to the same member as the pointer to member before the conversion took place, but it refers to the base class member as if it were a member of the derived class. The result refers to @@ -1436,7 +1439,7 @@ \pnum If an \grammarterm{id-expression} $E$ denotes -a member $M$ of an anonymous union\iref{class.union.anon} $U$: +a variant member $M$ of an anonymous union\iref{class.union.anon} $U$: \begin{itemize} \item If $U$ is a non-static data member, @@ -2034,7 +2037,7 @@ \pnum The \grammarterm{constant-expression} shall be -a converted constant expression\iref{expr.const} of type \tcode{std::size_t} +a converted constant expression\iref{expr.const.const} of type \tcode{std::size_t} whose value $V$, termed the index, is such that $0 \le V < \tcode{sizeof...($P$)}$. @@ -2238,7 +2241,8 @@ \end{note} \pnum -The closure type is not an aggregate type\iref{dcl.init.aggr}; +The closure type is not an aggregate type\iref{dcl.init.aggr} +and is not \tcode{final}\iref{class.pre}; it is a structural type\iref{term.structural.type} if and only if the lambda has no \grammarterm{lambda-capture}. An implementation may define the closure type differently from what @@ -2800,7 +2804,8 @@ return x+2; }(); // Updates \tcode{::x} to 6, and initializes \tcode{y} to 7. -auto z = [a = 42](int a) { return 1; }; // error: parameter and conceptual local variable have the same name +auto z = [a = 42](int a) { return 1; }; // error: parameter and conceptual local variable + // have the same name auto counter = [i=0]() mutable -> decltype(i) { // OK, returns \tcode{int} return i++; }; @@ -3091,12 +3096,13 @@ \end{example} \pnum -When the \grammarterm{lambda-expression} is evaluated, the entities that are +The entities that are captured by copy are used to direct-initialize each corresponding non-static data member of the resulting closure object, and the non-static data members corresponding to the \grammarterm{init-capture}{s} are initialized as indicated by the corresponding \grammarterm{initializer} (which may be copy- or direct-initialization). (For array members, the array elements are direct-initialized in increasing subscript order.) These initializations are performed +when the \grammarterm{lambda-expression} is evaluated and in the (unspecified) order in which the non-static data members are declared. \begin{note} This ensures that the destructions will occur in the reverse order of the constructions. @@ -3318,7 +3324,7 @@ \end{note} If the substitution of template arguments into a \grammarterm{requirement} would always result in a substitution failure, the program is ill-formed; -no diagnostic required. +no diagnostic required\ifndrdef{expr.prim.req.always.sub.fail}. \begin{example} \begin{codeblock} template concept C = @@ -3389,7 +3395,7 @@ typename T::inner; // required nested member name typename S; // required valid\iref{temp.names} \grammarterm{template-id}; fails if \tcode{T::type} does not exist as a type // to which \tcode{0} can be implicitly converted - typename Ref; // required alias template substitution, fails if \tcode{T} is void + typename Ref; // required alias template substitution, fails if \tcode{T} is \tcode{void} typename [:T::r1:]; // fails if \tcode{T::r1} is not a reflection of a type typename [:T::r2:]; // fails if \tcode{T::r2} is not a reflection of a template \tcode{Z} for which \tcode{Z} is a type }; @@ -3559,7 +3565,7 @@ \end{example} \pnum -For a \grammarterm{splice-expression} of the form \grammarterm{splice-specifier}, +For a \grammarterm{splice-expression} $E$ of the form \grammarterm{splice-specifier}, let $S$ be the construct designated by \grammarterm{splice-specifier}. \begin{itemize} \item @@ -3609,10 +3615,24 @@ Otherwise, if $S$ is a variable or a structured binding, $S$ shall either have static or thread storage duration or shall inhabit a scope enclosing the expression. -The expression is an lvalue referring to the object or function $X$ -associated with or referenced by $S$, -has the same type as that of $S$, and +The expression $E$ is an lvalue referring to the object or function $X$ +associated with or referenced by $S$, and is a bit-field if and only if $X$ is a bit-field. +If $E$ appears in the predicate of a contract assertion $C$\iref{basic.contract} +and $S$ is +\begin{itemize} +\item +a variable declared outside of $C$ +of object type \tcode{T}, +\item +a variable declared outside of $C$ +of type ``reference to \tcode{T}'', or +\item +a structured binding of type \tcode{T} +whose corresponding variable is declared outside of $C$, +\end{itemize} +then the type of $E$ is \tcode{const T}, +otherwise $E$ has the same type as that of $S$. \begin{note} The type of a \grammarterm{splice-expression} designating a variable or structured binding of reference type @@ -3843,7 +3863,7 @@ expression whose function type is not call-compatible with the type of the called function's -definition results in undefined behavior. +definition results in undefined behavior\ubdef{expr.call.different.type}. \begin{note} This requirement allows the case when the expression has the type of a @@ -4044,7 +4064,7 @@ After these conversions, if the argument does not have arithmetic, enumeration, pointer, pointer-to-member, or class type, the program is ill-formed. -Passing a potentially-evaluated argument +Passing a potentially evaluated argument of a scoped enumeration type\iref{dcl.enum} or of a class type\iref{class} having an eligible non-trivial copy constructor\iref{special,class.copy.ctor}, @@ -4375,7 +4395,7 @@ or direct base class relationship and the result of \tcode{E1} is an object whose type is not similar\iref{conv.qual} to the type of \tcode{E1}, -the behavior is undefined. +the behavior is undefined\ubdef{expr.ref.member.not.similar}. \begin{example} \begin{codeblock} struct A { int i; }; @@ -4504,14 +4524,14 @@ that is within its lifetime or within its period of construction or destruction\iref{class.cdtor}, -the behavior is undefined. +the behavior is undefined\ubdef{expr.dynamic.cast.pointer.lifetime}. If \tcode{v} is a glvalue of type \tcode{U} and \tcode{v} does not refer to an object whose type is similar to \tcode{U} and that is within its lifetime or within its period of construction or destruction, -the behavior is undefined. +the behavior is undefined\ubdef{expr.dynamic.cast.glvalue.lifetime}. \pnum If \tcode{T} is ``pointer to \cv{} \keyword{void}'', then the result @@ -4716,7 +4736,7 @@ type ``\cvqual{cv1} \tcode{B}''. If the object of type ``\cvqual{cv1} \tcode{B}'' is actually a base class subobject of an object of type \tcode{D}, the result refers to the enclosing object of type -\tcode{D}. Otherwise, the behavior is undefined. +\tcode{D}. Otherwise, the behavior is undefined\ubdef{expr.static.cast.base.class}. \begin{example} \begin{codeblock} struct B { }; @@ -4816,7 +4836,7 @@ the value is unchanged if the original value is within the range of the enumeration values\iref{dcl.enum}, and -otherwise, the behavior is undefined. +otherwise, the behavior is undefined\ubdef{expr.static.cast.enum.outside.range}. A value of floating-point type can also be explicitly converted to an enumeration type. The resulting value is the same as converting the original value to the underlying type of the enumeration\iref{conv.fpint}, and subsequently to @@ -4831,7 +4851,7 @@ the result of the conversion is an \impldef{result of inexact floating-point conversion} choice of either of those values. -Otherwise, the behavior is undefined. +Otherwise, the behavior is undefined\ubdef{expr.static.cast.fp.outside.range}. \pnum \indextext{cast!base class}% @@ -4852,7 +4872,7 @@ ``pointer to \cvqual{cv1} \tcode{B}'' points to a \tcode{B} that is actually a base class subobject of an object of type \tcode{D}, the resulting pointer points to the enclosing object of type \tcode{D}. Otherwise, the -behavior is undefined. +behavior is undefined\ubdef{expr.static.cast.downcast.wrong.derived.type}. \pnum \indextext{cast!pointer-to-member}% @@ -4875,7 +4895,7 @@ member pointer value of the destination type. If class \tcode{B} contains the original member, or is a base class of the class containing the original member, the resulting pointer to member points -to the original member. Otherwise, the behavior is undefined. +to the original member. Otherwise, the behavior is undefined\ubdef{expr.static.cast.does.not.contain.orignal.member}. \begin{note} Although class \tcode{B} need not contain the original member, the dynamic type of the object with which indirection through the pointer @@ -5253,7 +5273,8 @@ The operator yields an lvalue of type \tcode{T}. If the operand points to an object or function, the result denotes that object or function; -otherwise, the behavior is undefined except as specified in \ref{expr.typeid}. +otherwise, the behavior is undefined except as specified in \ref{expr.typeid} +\ubdef{expr.unary.dereference}. \begin{note} Indirection through a pointer to an out-of-lifetime object is valid\iref{basic.life}. \end{note} @@ -5448,7 +5469,7 @@ \end{bnf} \pnum -An \grammarterm{await-expression} shall appear only as a potentially-evaluated +An \grammarterm{await-expression} shall appear only as a potentially evaluated expression within the \grammarterm{compound-statement} of a \grammarterm{function-body} or \grammarterm{lambda-expression}, in either case @@ -5674,6 +5695,8 @@ When applied to a class, the result is the number of bytes in an object of that class including any padding required for placing objects of that type in an array. +The amount and placement of padding in a class type +is a property of the implementation. The result of applying \keyword{sizeof} to a potentially-overlapping subobject is the size of the type, not the size of the subobject. @@ -5718,7 +5741,7 @@ \tcode{std::size_t}. \begin{note} A \keyword{sizeof} expression -is an integral constant expression\iref{expr.const}. +is an integral constant expression\iref{expr.const.const}. The \grammarterm{typedef-name} \tcode{std::size_t} is declared in the standard header \libheader{cstddef}\iref{cstddef.syn,support.types.layout}. \end{note} @@ -5737,7 +5760,7 @@ The result is a prvalue of type \tcode{std::size_t}. \begin{note} An \keyword{alignof} expression -is an integral constant expression\iref{expr.const}. +is an integral constant expression\iref{expr.const.const}. The \grammarterm{typedef-name} \tcode{std::size_t} is declared in the standard header \libheader{cstddef}\iref{cstddef.syn,support.types.layout}. \end{note} @@ -5771,7 +5794,7 @@ \tcode{true} otherwise. \begin{note} A \grammarterm{noexcept-expression} -is an integral constant expression\iref{expr.const}. +is an integral constant expression\iref{expr.const.const}. \end{note} \indextext{expression!unary|)} @@ -5915,7 +5938,7 @@ \pnum Every \grammarterm{constant-expression} in a \grammarterm{noptr-new-declarator} shall be a converted constant -expression\iref{expr.const} of type \tcode{std::size_t} and +expression\iref{expr.const.const} of type \tcode{std::size_t} and its value shall be greater than zero. \begin{example} Given the definition \tcode{int n = 42}, @@ -5980,7 +6003,7 @@ If the value of the \grammarterm{expression} is invalid after converting to \tcode{std::size_t}: \begin{itemize} \item -if the \grammarterm{expression} is a potentially-evaluated core constant expression, +if the \grammarterm{expression} is a potentially evaluated core constant expression, the program is ill-formed; \item otherwise, an allocation function is not called; instead @@ -6004,7 +6027,7 @@ the \grammarterm{new-initializer} is a \grammarterm{braced-init-list} or a parenthesized \grammarterm{expression-list}, and the \grammarterm{expression} -is potentially-evaluated and not a core constant expression, +is potentially evaluated and not a core constant expression, the semantic constraints of initializing a hypothetical element of the array are checked as follows: \begin{itemize} @@ -6096,7 +6119,7 @@ \pnum During an evaluation of a constant expression, -a call to a replaceable allocation function is always omitted\iref{expr.const}. +a call to a replaceable allocation function is always omitted\iref{expr.const.core}. \pnum The implementation may @@ -6267,7 +6290,7 @@ \end{note} If the allocation function is a non-allocating form\iref{new.delete.placement} that returns null, -the behavior is undefined. +the behavior is undefined\ubdef{expr.new.non.allocating.null}. Otherwise, if the allocation function returns null, initialization shall not be done, the deallocation function shall not be called, and the value of @@ -6349,23 +6372,45 @@ searching for it in the global scope. \pnum -A declaration of a placement deallocation function matches the -declaration of a placement allocation function if it has the same number -of parameters and, after parameter transformations\iref{dcl.fct}, all -parameter types except the first are identical. If -the lookup finds a single matching deallocation function, that function -will be called; otherwise, no deallocation function will be called. If -the lookup finds a usual deallocation -function -and that function, -considered as a placement deallocation function, would have been -selected as a match for the allocation function, the program is -ill-formed. For a non-placement allocation function, the normal deallocation +For a non-placement allocation function, the normal deallocation function lookup is used to find the matching deallocation function\iref{expr.delete}. +For a placement allocation function, the selection process is described below. In any case, the matching deallocation function (if any) shall be non-deleted and accessible from the point where the \grammarterm{new-expression} appears. + +\pnum +For a placement allocation function, +the matching deallocation function is selected as follows: +\begin{itemize} +\item +Each candidate that is a function template is replaced by +the function template specializations (if any) +generated using template argument deduction\iref{temp.over,temp.deduct.call} +with arguments as specified below. +\item +Each candidate whose parameter-type-list is not identical to +that of the allocation function, +ignoring their respective first parameters, +is removed from the set of candidates. +\item +Each candidate whose associated constraints (if any) +are not satisfied\iref{temp.constr.constr} +is removed from the set of candidates. +\item +If exactly one function remains, that function is selected. +\item +Otherwise, no deallocation function is selected. +\end{itemize} +If a usual deallocation function is selected, the program is ill-formed. +\begin{note} +A deallocation function with an additional trailing parameter +compared to the allocation function is never matched, +even if a default argument is provided. +\end{note} + +\pnum \begin{example} \begin{codeblock} struct S { @@ -6379,7 +6424,55 @@ S* p = new (0) S; // error: non-placement deallocation function matches // placement allocation function \end{codeblock} +\end{example} + +\begin{example} +\begin{codeblock} +struct A {}; +struct T { T(); }; + +void* operator new(std::size_t s, A& al); // \#1 + +template +void operator delete(void* p, A& al); // \#2 + +A al; +T* p = new (al) T; // OK, uses \#1 and \#2. +\end{codeblock} +\end{example} + +\begin{example} +\begin{codeblock} +template +struct A {}; +struct T { T(); }; + +void* operator new(std::size_t s, A<0>& al); // \#1 + +template +void operator delete(void* p, A& al); +void operator delete(void* p, A<0>& al); + +A<0> al; +T* p = new (al) T; // OK, uses \#1. No deallocation function is selected (two candidates remain). +\end{codeblock} +\end{example} + +\begin{example} +\begin{codeblock} +template +struct A {}; +struct T { T(); }; + +void* operator new(std::size_t s, A<0>& al); // \#1 +template requires (I > 0) +void operator delete(void* p, A& al); +void operator delete(void* p, A<0>& al); // \#2 + +A<0> al; +T* p = new (al) T; // OK, uses \#1 and \#2. +\end{codeblock} \end{example} \pnum @@ -6439,7 +6532,7 @@ that resulted from a previous non-array \grammarterm{new-expression}, or a pointer to a base class subobject of an object created by such a \grammarterm{new-expression}. -If not, the behavior is undefined. +If not, the behavior is undefined\ubdef{expr.delete.mismatch}. \indextext{array!\idxcode{delete}}% In an array delete expression, the value of the operand of \keyword{delete} may be a null pointer value or a pointer value that resulted from @@ -6451,7 +6544,7 @@ element of the array created by that \grammarterm{new-expression}. Zero-length arrays do not have a first element. \end{footnote} -If not, the behavior is undefined. +If not, the behavior is undefined\ubdef{expr.delete.array.mismatch}. \begin{note} This means that the syntax of the \grammarterm{delete-expression} must match the type of the object allocated by \keyword{new}, not the syntax of the @@ -6472,9 +6565,9 @@ is not a destroying operator delete, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall -have a virtual destructor or the behavior is undefined. In an array delete +have a virtual destructor or the behavior is undefined\ubdef{expr.delete.dynamic.type.differ}. In an array delete expression, if the dynamic type of the object to be deleted is not similar to -its static type, the behavior is undefined. +its static type, the behavior is undefined\ubdef{expr.delete.dynamic.array.dynamic.type.differ}. \pnum \indextext{type!incomplete}% @@ -6702,13 +6795,13 @@ that represents a template shall not be followed by \tcode{<}. \begin{example} \begin{codeblock} -static_assert(std::meta::is_type(^^int())); // \tcode{\caret\caret} applies to the type-id \tcode{int()} +static_assert(std::meta::is_type(^^int())); // \tcode{\caret\caret} applies to the \grammarterm{type-id} \tcode{int()} template struct X {}; consteval bool operator<(std::meta::info, X) { return false; } consteval void g(std::meta::info r, X xv) { r == ^^int && true; // error: \tcode{\caret\caret} applies to the \grammarterm{type-id} \tcode{int\&\&} - r == ^^int & true; // error: \tcode{\caret\caret} applies to the type-id \tcode{int\&} + r == ^^int & true; // error: \tcode{\caret\caret} applies to the \grammarterm{type-id} \tcode{int\&} r == (^^int) && true; // OK r == ^^int &&&& true; // error: \tcode{int \&\&\&\&} is not a valid \grammarterm{type-id} ^^X < xv; // error: \grammarterm{reflect-expression} that represents a template is followed by \tcode{<} @@ -7039,7 +7132,7 @@ whose type is not similar to the type of \tcode{E1}, or whose most derived object does not contain the member to which -\tcode{E2} refers, the behavior is undefined. +\tcode{E2} refers, the behavior is undefined\ubdef{expr.mptr.oper.not.contain.member}. The expression \tcode{E1} is sequenced before the expression \tcode{E2}. \pnum @@ -7091,7 +7184,7 @@ operand is an lvalue and an xvalue otherwise. The result of a \tcode{.*} expression whose second operand is a pointer to a member function is a prvalue. If the second operand is the null -member pointer value\iref{conv.mem}, the behavior is undefined. +member pointer value\iref{conv.mem}, the behavior is undefined\ubdef{expr.mptr.oper.member.func.null}. \rSec2[expr.mul]{Multiplicative operators}% \indextext{expression!multiplicative operators}% @@ -7132,7 +7225,7 @@ expression by the second. \indextext{zero!undefined division by}% If the second operand of \tcode{/} or \tcode{\%} is zero, the behavior is -undefined. +undefined\ubdef{expr.mul.div.by.zero}. For integral operands, the \tcode{/} operator yields the algebraic quotient with any fractional part discarded; \begin{footnote} @@ -7140,7 +7233,7 @@ \end{footnote} if the quotient \tcode{a/b} is representable in the type of the result, \tcode{(a/b)*b + a\%b} is equal to \tcode{a}; otherwise, the behavior -of both \tcode{a/b} and \tcode{a\%b} is undefined. +of both \tcode{a/b} and \tcode{a\%b} is undefined\ubdef{expr.mul.representable.type.result}. \rSec2[expr.add]{Additive operators}% \indextext{expression!additive operators}% @@ -7219,7 +7312,7 @@ and the expression \tcode{P - J} points to the (possibly-hypothetical) array element $i - j$ of \tcode{x} if $0 \le i - j \le n$. -\item Otherwise, the behavior is undefined. +\item Otherwise, the behavior is undefined\ubdef{expr.add.out.of.bounds}. \end{itemize} \begin{note} Adding a value other than $0$ or $1$ @@ -7245,13 +7338,13 @@ of type \tcode{std::ptrdiff_t}, the behavior is undefined\iref{expr.pre}. \end{note} -\item Otherwise, the behavior is undefined. +\item Otherwise, the behavior is undefined\ubdef{expr.add.sub.diff.pointers}. \end{itemize} \pnum For addition or subtraction, if the expressions \tcode{P} or \tcode{Q} have type ``pointer to \cv{}~\tcode{T}'', where \tcode{T} and the array element type -are not similar\iref{conv.qual}, the behavior is undefined. +are not similar\iref{conv.qual}, the behavior is undefined\ubdef{expr.add.not.similar}. \begin{example} \begin{codeblock} int arr[5] = {1, 2, 3, 4, 5}; @@ -7288,7 +7381,7 @@ promotions are performed. The type of the result is that of the promoted left operand. \indextext{left shift!undefined}% -The behavior is undefined if the right operand is negative, or greater +The behavior is undefined\ubdef{expr.shift.neg.and.width} if the right operand is negative, or greater than or equal to the width of the promoted left operand. \pnum @@ -8199,7 +8292,7 @@ If the value being stored in an object is read via another object that overlaps in any way the storage of the first object, then the overlap shall be exact and the two objects shall have the same type, otherwise the behavior is -undefined. +undefined\ubdef{expr.assign.overlap}. \begin{note} This restriction applies to the relationship between the left and right sides of the assignment operation; it is not a @@ -8279,20 +8372,10 @@ \end{example} \end{note} -\rSec1[expr.const]{Constant expressions}% +\rSec1[expr.const]{Constant evaluation}% \indextext{expression!constant} -\pnum -Certain contexts require expressions that satisfy additional -requirements as detailed in this subclause; other contexts have different -semantics depending on whether or not an expression satisfies these requirements. -Expressions that satisfy these requirements, -assuming that copy elision\iref{class.copy.elision} is not performed, -are called constant expressions. -\begin{note} -Constant expressions can be evaluated -during translation. -\end{note} +\rSec2[expr.const.general]{General} \begin{bnf} \nontermdef{constant-expression}\br @@ -8300,182 +8383,53 @@ \end{bnf} \pnum -The constituent values and constituent references of -a variable \tcode{x} are defined as follows: -\begin{itemize} -\item -If \tcode{x} declares an object, -the constituent values and references of that object\iref{intro.object} are -constituent values and references of \tcode{x}. -\item -If \tcode{x} declares a reference, -that reference is a constituent reference of \tcode{x}. -\end{itemize} -For any constituent reference \tcode{r} of a variable \tcode{x}, -if \tcode{r} is bound to a temporary object or subobject thereof -whose lifetime is extended to that of \tcode{r}, -the constituent values and references of that temporary object -are also constituent values and references of \tcode{x}, recursively. - -\pnum -An object $o$ is \defn{constexpr-referenceable} from a point $P$ if -\begin{itemize} -\item -$o$ has static storage duration, or -\item -$o$ has automatic storage duration, and, letting \tcode{v} denote -\begin{itemize} -\item -the variable corresponding to $o$'s complete object or -\item -the variable to whose lifetime that of $o$ is extended, -\end{itemize} -the smallest scope enclosing \tcode{v} and the smallest scope enclosing $P$ -that are neither -\begin{itemize} -\item -block scopes nor -\item -function parameter scopes associated with -a \grammarterm{requirement-parameter-list} -\end{itemize} -are the same function parameter scope. -\end{itemize} -\begin{example} -\begin{codeblock} -struct A { - int m; - const int& r; -}; -void f() { - static int sx; - thread_local int tx; // \tcode{tx} is never constexpr-referenceable - int ax; - A aa = {1, 2}; - static A sa = {3, 4}; - // The objects \tcode{sx}, \tcode{ax}, and \tcode{aa.m}, \tcode{sa.m}, and the temporaries to which \tcode{aa.r} and \tcode{sa.r} are bound, are constexpr-referenceable. - auto lambda = [] { - int ay; - // The objects \tcode{sx}, \tcode{sa.m}, and \tcode{ay} (but not \tcode{ax} or \tcode{aa}), and the - // temporary to which \tcode{sa.r} is bound, are constexpr-referenceable. - }; -} -\end{codeblock} -\end{example} - -\pnum -An object or reference \tcode{x} is -\defn{constexpr-representable} at a point $P$ if, -for each constituent value of \tcode{x} that points to or past an object $o$, -and for each constituent reference of \tcode{x} that refers to an object $o$, -$o$ is constexpr-referenceable from $P$. - -\pnum -\indextext{contract evaluation semantics!ignore} -A variable \tcode{v} is \defn{constant-initializable} if -\begin{itemize} -\item -the full-expression of its initialization is a constant expression -when interpreted as a \grammarterm{constant-expression} -with all contract assertions -using the ignore evaluation semantic\iref{basic.contract.eval}, -\begin{note} -Within this evaluation, -\tcode{std::is_constant_evaluated()}\iref{meta.const.eval} -returns \keyword{true}. -\end{note} +Certain contexts require expressions that satisfy additional +requirements as detailed in \ref{expr.const}; other contexts have different +semantics depending on whether or not an expression satisfies these requirements. +Expressions that satisfy these requirements, +assuming that copy elision\iref{class.copy.elision} is not performed, +are called constant expressions. \begin{note} -The initialization, when evaluated, -can still evaluate contract assertions -with other evaluation semantics, -resulting in a diagnostic or ill-formed program -if a contract violation occurs. +Certain constant expressions are evaluated during translation\iref{lex.phases}. \end{note} -\item -immediately after the initializing declaration of \tcode{v}, -the object or reference \tcode{x} declared by \tcode{v} -is constexpr-representable, and -\item -if \tcode{x} has static or thread storage duration, -\tcode{x} is constexpr-representable at the nearest point -whose immediate scope is a namespace scope -that follows the initializing declaration of \tcode{v}. -\end{itemize} \pnum -A constant-initializable variable is \defn{constant-initialized} -if either it has an initializer or -its type is const-default-constructible\iref{dcl.init.general}. +\recommended +Implementations should provide consistent results of floating-point evaluations, +irrespective of whether the evaluation is performed +during translation or during program execution. +\begin{note} +Since this document +imposes no restrictions on the accuracy of floating-point operations, it is unspecified whether the +evaluation of a floating-point expression during translation yields the same result as the +evaluation of the same expression (or the same operations on the same values) during program +execution. \begin{example} \begin{codeblock} -void f() { - int ax = 0; // \tcode{ax} is constant-initialized - thread_local int tx = 0; // \tcode{tx} is constant-initialized - static int sx; // \tcode{sx} is not constant-initialized - static int& rss = sx; // \tcode{rss} is constant-initialized - static int& rst = tx; // \tcode{rst} is not constant-initialized - static int& rsa = ax; // \tcode{rsa} is not constant-initialized - thread_local int& rts = sx; // \tcode{rts} is constant-initialized - thread_local int& rtt = tx; // \tcode{rtt} is not constant-initialized - thread_local int& rta = ax; // \tcode{rta} is not constant-initialized - int& ras = sx; // \tcode{ras} is constant-initialized - int& rat = tx; // \tcode{rat} is not constant-initialized - int& raa = ax; // \tcode{raa} is constant-initialized +bool f() { + char array[1 + int(1 + 0.2 - 0.1 - 0.1)]; // Must be evaluated during translation + int size = 1 + int(1 + 0.2 - 0.1 - 0.1); // May be evaluated at runtime + return sizeof(array) == size; } \end{codeblock} +It is unspecified whether the value of \tcode{f()} will be \tcode{true} or \tcode{false}. \end{example} +\end{note} -\pnum -A variable is \defn{potentially-constant} if -it is constexpr or -it has reference or non-volatile const-qualified integral or enumeration type. +\rSec2[expr.const.core]{Core constant expressions} \pnum -A constant-initialized potentially-constant variable $V$ is -\defn{usable in constant expressions} at a point $P$ if -$V$'s initializing declaration $D$ is reachable from $P$ and -\begin{itemize} -\item $V$ is constexpr, -\item $V$ is not initialized to a TU-local value, or -\item $P$ is in the same translation unit as $D$. -\end{itemize} -An object or reference is -\defn{potentially usable in constant expressions} at point $P$ if it is +\indextext{type!constexpr-unknown representation}% +A type has \defnadj{constexpr-unknown}{representation} if it \begin{itemize} +\item is a union, +\item is a pointer or pointer-to-member type, +\item is volatile-qualified, +\item is a class type with a non-static data member of reference type, or \item -the object or reference declared by a variable -that is usable in constant expressions at $P$, -\item -a temporary object of non-volatile const-qualified literal type -whose lifetime is extended\iref{class.temporary} -to that of a variable that is usable in constant expressions at $P$, -\item -a template parameter object\iref{temp.param}, -\item -a string literal object\iref{lex.string}, -\item -a non-mutable subobject of any of the above, or -\item -a reference member of any of the above. +has a base class or a non-static member whose +type has constexpr-unknown representation. \end{itemize} -An object or reference is \defn{usable in constant expressions} at point $P$ -if it is an object or reference -that is potentially usable in constant expressions at $P$ and -is constexpr-representable at $P$. -\begin{example} -\begin{codeblock} -struct A { - int* const & r; -}; -void f(int x) { - constexpr A a = {&x}; - static_assert(a.r == &x); // OK - [&] { - static_assert(a.r != nullptr); // error: \tcode{a.r} is not usable in constant expressions at this point - }(); -} -\end{codeblock} -\end{example} \pnum An expression $E$ is a \defnadj{core constant}{expression} @@ -8655,10 +8609,11 @@ with an allocated type \tcode{T}, where \begin{itemize} \item -the placement argument to the \grammarterm{new-expression} points to -an object whose type is similar to \tcode{T}\iref{conv.qual} or, -if \tcode{T} is an array type, -to the first element of an object of a type similar to \tcode{T}, and +the placement argument to the \grammarterm{new-expression} points +to an object that is transparently replaceable\iref{basic.life} by +the object created by the \grammarterm{new-expression} +or, if \tcode{T} is an array type, +to the first element of such an object, and \item the placement argument points to storage whose duration began within the evaluation of $E$; @@ -8704,6 +8659,34 @@ relational\iref{expr.rel}, or equality\iref{expr.eq} operator where the result is unspecified; +\item +an equality operator comparing pointers to potentially non-unique objects, +if the pointer values of the two operands +are associated with different evaluations\iref{basic.compound} and either +they can both point to the same offset within +the same potentially non-unique object or +one of them points to an object whose +type has constexpr-unknown representation; +\begin{example} +\begin{codeblock} +constexpr const char *f() { return "foo"; } + +constexpr bool b1 = +"foo" == "foo"; // error: non-constant +constexpr bool b2 = f() == f(); // error: non-constant +constexpr const char *p = f(); +constexpr bool b3 = p == p; // OK, value of \tcode{b3} is \tcode{true} +constexpr bool b4 = "xfoo" + 1 == "foo\0y"; // error: non-constant; string literal + // object could contain \tcode{"xfoo\textbackslash{}0y"} +constexpr bool b5 = "foo" == "bar" + 0; // OK, value of \tcode{b5} is \tcode{false} +constexpr bool b6 = (const char*)"foo" == "oo"; // OK, value of \tcode{b6} is \tcode{false}; offsets would + // be different in a merged string literal object + +constexpr std::initializer_list il1 = { (int *)nullptr }; +constexpr std::initializer_list il2 = { 0 }; +constexpr bool b7 = il1.begin() == (void *)il2.begin(); // error: non-constant +\end{codeblock} +\end{example} + \item a \keyword{dynamic_cast}\iref{expr.dynamic.cast} or \keyword{typeid}\iref{expr.typeid} expression @@ -8926,20 +8909,85 @@ \end{codeblock} \end{example} +\rSec2[expr.const.const]{Constant expressions} + \pnum -An object \tcode{a} is said to have \defnadj{constant}{destruction} if +A \defnadj{constant}{expression} is either \begin{itemize} \item - it is not of class type nor (possibly multidimensional) array thereof, or +a glvalue core constant expression $E$ for which +\begin{itemize} \item - it is of class type or (possibly multidimensional) array thereof, - that class type has a constexpr destructor\iref{dcl.constexpr}, and - for a hypothetical expression $E$ - whose only effect is to destroy \tcode{a}, - $E$ would be a core constant expression - if the lifetime of \tcode{a} and its non-mutable subobjects - (but not its mutable subobjects) were considered to start within $E$. +$E$ refers to a non-immediate function, +\item +$E$ designates an object \tcode{o}, and +if the complete object of \tcode{o} is of consteval-only type then so is $E$, +\begin{example} +\begin{codeblock} +struct Base { }; +struct Derived : Base { std::meta::info r; }; + +consteval const Base& fn(const Derived& derived) { return derived; } + +constexpr Derived obj{.r=^^::}; // OK +constexpr const Derived& d = obj; // OK +constexpr const Base& b = fn(obj); // error: not a constant expression because \tcode{Derived} + // is a consteval-only type but \tcode{Base} is not. +\end{codeblock} +\end{example} +\end{itemize} +or +\item +a prvalue core constant expression whose result object\iref{basic.lval} (if any) +satisfies the following constraints: +\begin{itemize} +\item +each constituent reference refers to an object or a non-immediate function, +\item +no constituent value of scalar type is an indeterminate or erroneous value\iref{basic.indet}, +\item +no constituent value of pointer type is a pointer to an immediate function or +an invalid pointer value\iref{basic.compound}, +\item +no constituent value of pointer-to-member type designates an immediate function, and +\item +unless the value is of consteval-only type, +\begin{itemize} +\item +no constituent value of pointer-to-member type points to +a direct member of a consteval-only class type, +\item +no constituent value of pointer type points to or past an object +whose complete object is of consteval-only type, and +\item +no constituent reference refers to an object +whose complete object is of consteval-only type. +\end{itemize} +\end{itemize} \end{itemize} +\begin{note} +A glvalue core constant expression +that either refers to or points to an unspecified object +is not a constant expression. +\end{note} +\begin{example} +\begin{codeblock} +consteval int f() { return 42; } +consteval auto g() { return f; } +consteval int h(int (*p)() = g()) { return p(); } +constexpr int r = h(); // OK +constexpr auto e = g(); // error: a pointer to an immediate function is + // not a permitted result of a constant expression + +struct S { + int x; + constexpr S() {} +}; +int i() { + constexpr S s; // error: \tcode{s.x} has erroneous value +} +\end{codeblock} +\end{example} \pnum An \defnadj{integral constant}{expression} @@ -9005,111 +9053,199 @@ \end{note} \indextext{contextually converted constant expression of type \tcode{bool}|see{conversion, contextual}}% \indextext{conversion!contextual to constant expression of type \tcode{bool}}% + +\pnum A \term{contextually converted constant expression of type \tcode{bool}} is an expression, contextually converted to \keyword{bool}\iref{conv}, where the converted expression is a constant expression and the conversion sequence contains only the conversions above. +\rSec2[expr.const.init]{Constant initialization} + \pnum -A \defnadj{constant}{expression} is either -\begin{itemize} -\item -a glvalue core constant expression $E$ for which +The constituent values and constituent references of +a variable \tcode{x} are defined as follows: \begin{itemize} \item -$E$ refers to a non-immediate function, +If \tcode{x} declares an object, +the constituent values and references of that object\iref{intro.object} are +constituent values and references of \tcode{x}. \item -$E$ designates an object \tcode{o}, and -if the complete object of \tcode{o} is of consteval-only type then so is $E$, -\begin{example} -\begin{codeblock} -struct Base { }; -struct Derived : Base { std::meta::info r; }; - -consteval const Base& fn(const Derived& derived) { return derived; } - -constexpr Derived obj{.r=^^::}; // OK -constexpr const Derived& d = obj; // OK -constexpr const Base& b = fn(obj); // error: not a constant expression because \tcode{Derived} - // is a consteval-only type but \tcode{Base} is not. -\end{codeblock} -\end{example} +If \tcode{x} declares a reference, +that reference is a constituent reference of \tcode{x}. \end{itemize} -or -\item -a prvalue core constant expression whose result object\iref{basic.lval} -satisfies the following constraints: +For any constituent reference \tcode{r} of a variable \tcode{x}, +if \tcode{r} is bound to a temporary object or subobject thereof +whose lifetime is extended to that of \tcode{r}, +the constituent values and references of that temporary object +are also constituent values and references of \tcode{x}, recursively. + +\pnum +An object $o$ is \defn{constexpr-referenceable} from a point $P$ if \begin{itemize} \item -each constituent reference refers to an object or a non-immediate function, -\item -no constituent value of scalar type is an indeterminate or erroneous value\iref{basic.indet}, +$o$ has static storage duration, or \item -no constituent value of pointer type is a pointer to an immediate function or -an invalid pointer value\iref{basic.compound}, +$o$ has automatic storage duration, and, letting \tcode{v} denote +\begin{itemize} \item -no constituent value of pointer-to-member type designates an immediate function, and +the variable corresponding to $o$'s complete object or \item -unless the value is of consteval-only type, +the variable to whose lifetime that of $o$ is extended, +\end{itemize} +the smallest scope enclosing \tcode{v} and the smallest scope enclosing $P$ +that are neither \begin{itemize} \item -no constituent value of pointer-to-member type points to -a direct member of a consteval-only class type, -\item -no constituent value of pointer type points to or past an object -whose complete object is of consteval-only type, and +block scopes nor \item -no constituent reference refers to an object -whose complete object is of consteval-only type. -\end{itemize} +function parameter scopes associated with +a \grammarterm{requirement-parameter-list} \end{itemize} +are the same function parameter scope. \end{itemize} -\begin{note} -A glvalue core constant expression -that either refers to or points to an unspecified object -is not a constant expression. -\end{note} \begin{example} \begin{codeblock} -consteval int f() { return 42; } -consteval auto g() { return f; } -consteval int h(int (*p)() = g()) { return p(); } -constexpr int r = h(); // OK -constexpr auto e = g(); // error: a pointer to an immediate function is - // not a permitted result of a constant expression - -struct S { - int x; - constexpr S() {} +struct A { + int m; + const int& r; }; -int i() { - constexpr S s; // error: \tcode{s.x} has erroneous value +void f() { + static int sx; + thread_local int tx; // \tcode{tx} is never constexpr-referenceable + int ax; + A aa = {1, 2}; + static A sa = {3, 4}; + // The objects \tcode{sx}, \tcode{ax}, and \tcode{aa.m}, \tcode{sa.m}, and the temporaries to which \tcode{aa.r} and \tcode{sa.r} are bound, are constexpr-referenceable. + auto lambda = [] { + int ay; + // The objects \tcode{sx}, \tcode{sa.m}, and \tcode{ay} (but not \tcode{ax} or \tcode{aa}), and the + // temporary to which \tcode{sa.r} is bound, are constexpr-referenceable. + }; } \end{codeblock} \end{example} \pnum -\recommended -Implementations should provide consistent results of floating-point evaluations, -irrespective of whether the evaluation is performed -during translation or during program execution. +An object or reference \tcode{x} is +\defn{constexpr-representable} at a point $P$ if, +for each constituent value of \tcode{x} that points to or past an object $o$, +and for each constituent reference of \tcode{x} that refers to an object $o$, +$o$ is constexpr-referenceable from $P$. + +\pnum +\indextext{contract evaluation semantics!ignore} +A variable \tcode{v} is \defn{constant-initializable} if +\begin{itemize} +\item +the full-expression of its initialization is a constant expression +when interpreted as a \grammarterm{constant-expression} +with all contract assertions +using the ignore evaluation semantic\iref{basic.contract.eval}, \begin{note} -Since this document -imposes no restrictions on the accuracy of floating-point operations, it is unspecified whether the -evaluation of a floating-point expression during translation yields the same result as the -evaluation of the same expression (or the same operations on the same values) during program -execution. +In the course of this determination, +\tcode{std::is_constant_evaluated()}\iref{meta.const.eval} +has the value \keyword{true}. +\end{note} +\begin{note} +Furthermore, if the initialization is manifestly constant-evaluated, +its evaluation during translation +can still evaluate contract assertions +with other evaluation semantics, +resulting in a diagnostic or ill-formed program +if a contract violation occurs. +\end{note} +\item +immediately after the initializing declaration of \tcode{v}, +the object or reference \tcode{x} declared by \tcode{v} +is constexpr-representable, and +\item +if \tcode{x} has static or thread storage duration, +\tcode{x} is constexpr-representable at the nearest point +whose immediate scope is a namespace scope +that follows the initializing declaration of \tcode{v}. +\end{itemize} + +\pnum +A constant-initializable variable is \defn{constant-initialized} +if either it has an initializer or +its type is const-default-constructible\iref{dcl.init.general}. \begin{example} \begin{codeblock} -bool f() { - char array[1 + int(1 + 0.2 - 0.1 - 0.1)]; // Must be evaluated during translation - int size = 1 + int(1 + 0.2 - 0.1 - 0.1); // May be evaluated at runtime - return sizeof(array) == size; +void f() { + int ax = 0; // \tcode{ax} is constant-initialized + thread_local int tx = 0; // \tcode{tx} is constant-initialized + static int sx; // \tcode{sx} is not constant-initialized + static int& rss = sx; // \tcode{rss} is constant-initialized + static int& rst = tx; // \tcode{rst} is not constant-initialized + static int& rsa = ax; // \tcode{rsa} is not constant-initialized + thread_local int& rts = sx; // \tcode{rts} is constant-initialized + thread_local int& rtt = tx; // \tcode{rtt} is not constant-initialized + thread_local int& rta = ax; // \tcode{rta} is not constant-initialized + int& ras = sx; // \tcode{ras} is constant-initialized + int& rat = tx; // \tcode{rat} is not constant-initialized + int& raa = ax; // \tcode{raa} is constant-initialized } \end{codeblock} -It is unspecified whether the value of \tcode{f()} will be \tcode{true} or \tcode{false}. \end{example} -\end{note} + +\pnum +A variable is \defn{potentially-constant} if +it is constexpr or +it has reference or non-volatile const-qualified integral or enumeration type. + +\pnum +A constant-initialized potentially-constant variable $V$ is +\defn{usable in constant expressions} at a point $P$ if +$V$'s initializing declaration $D$ is reachable from $P$ and +\begin{itemize} +\item $V$ is constexpr, +\item $V$ is not initialized to a TU-local value, or +\item $P$ is in the same translation unit as $D$. +\end{itemize} + +\pnum +An object or reference is +\defn{potentially usable in constant expressions} at point $P$ if it is +\begin{itemize} +\item +the object or reference declared by a variable +that is usable in constant expressions at $P$, +\item +a temporary object of non-volatile const-qualified literal type +whose lifetime is extended\iref{class.temporary} +to that of a variable that is usable in constant expressions at $P$, +\item +a template parameter object\iref{temp.param}, +\item +a string literal object\iref{lex.string}, +\item +a non-mutable subobject of any of the above, or +\item +a reference member of any of the above. +\end{itemize} + +\pnum +An object or reference is \defn{usable in constant expressions} at point $P$ +if it is an object or reference +that is potentially usable in constant expressions at $P$ and +is constexpr-representable at $P$. +\begin{example} +\begin{codeblock} +struct A { + int* const & r; +}; +void f(int x) { + constexpr A a = {&x}; + static_assert(a.r == &x); // OK + [&] { + static_assert(a.r != nullptr); // error: \tcode{a.r} is not usable in constant expressions at this point + }(); +} +\end{codeblock} +\end{example} + +\rSec2[expr.const.imm]{Immediate functions} \pnum An expression or conversion is in an \defn{immediate function context} @@ -9126,7 +9262,7 @@ the \grammarterm{compound-statement} of a consteval if statement\iref{stmt.if}. \end{itemize} An invocation is an \defn{immediate invocation} -if it is a potentially-evaluated explicit or implicit invocation of +if it is a potentially evaluated explicit or implicit invocation of an immediate function and is not in an immediate function context. An aggregate initialization is an immediate invocation @@ -9138,7 +9274,7 @@ \indexdefn{conversion!immediate-escalating}% \indexdefn{immediate-escalating!expression|see{expression, immediate-escalating}}% \indexdefn{immediate-escalating!conversion|see{conversion, immediate-escalating}}% -A potentially-evaluated expression or conversion is \defn{immediate-escalating} +A potentially evaluated expression or conversion is \defn{immediate-escalating} if it is neither initially in an immediate function context nor a subexpression of an immediate invocation, and \begin{itemize} @@ -9159,7 +9295,7 @@ the call operator of a lambda that is not declared with the \keyword{consteval} specifier, \item -a defaulted special member function +a non-user-provided defaulted function that is not declared with the \keyword{consteval} specifier, or \item a function that is not a prospective destructor and @@ -9192,6 +9328,8 @@ are considered to be part of the function body\iref{dcl.fct.def.general}. \end{tailnote} \end{itemize} + +\pnum \begin{example} \begin{codeblock} consteval int id(int i) { return i; } @@ -9258,52 +9396,7 @@ \end{codeblock} \end{example} -\pnum -An expression or conversion is \defn{manifestly constant-evaluated} -if it is: -\begin{itemize} -\item a \grammarterm{constant-expression}, or -\item the condition of a constexpr if statement\iref{stmt.if}, or -\item an immediate invocation, or -\item the result of substitution into an atomic constraint expression -to determine whether it is satisfied\iref{temp.constr.atomic}, or -\item the initializer of a variable -that is usable in constant expressions or -has constant initialization\iref{basic.start.static}. -\begin{footnote} -Testing this condition -can involve a trial evaluation of its initializer, -with evaluations of contract assertions -using the ignore evaluation semantic\iref{basic.contract.eval}, -as described above. -\end{footnote} -\begin{example} -\begin{codeblock} -template struct X {}; -X x; // type \tcode{X} -int y; -const int a = std::is_constant_evaluated() ? y : 1; // dynamic initialization to 1 -double z[a]; // error: \tcode{a} is not usable - // in constant expressions -const int b = std::is_constant_evaluated() ? 2 : y; // static initialization to 2 -int c = y + (std::is_constant_evaluated() ? 2 : y); // dynamic initialization to \tcode{y+y} - -constexpr int f() { - const int n = std::is_constant_evaluated() ? 13 : 17; // \tcode{n} is 13 - int m = std::is_constant_evaluated() ? 13 : 17; // \tcode{m} can be 13 or 17 (see below) - char arr[n] = {}; // char[13] - return m + sizeof(arr); -} -int p = f(); // \tcode{m} is 13; initialized to 26 -int q = p + f(); // \tcode{m} is 17 for this call; initialized to 56 -\end{codeblock} -\end{example} -\end{itemize} -\begin{note} -Except for a \grammarterm{static_assert-message}, -a manifestly constant-evaluated expression -is evaluated even in an unevaluated operand\iref{term.unevaluated.operand}. -\end{note} +\rSec2[expr.const.reflect]{Reflection} \pnum The evaluation of an expression can introduce @@ -9351,6 +9444,8 @@ there is a function parameter scope or class scope that encloses exactly one of $C$ or $P$. \end{itemize} + +\pnum \begin{example} \begin{codeblock} struct S0 { @@ -9412,39 +9507,144 @@ \end{example} \pnum -The \defn{evaluation context} is a set of program points -that determines the behavior of certain functions -used for reflection\iref{meta.reflection}. -During the evaluation $V$ of an expression $E$ as a core constant expression, -the evaluation context of an evaluation $X$\iref{intro.execution} -consists of the following points: -\begin{itemize} -\item -The program point $\textit{EVAL-PT}(L)$, -where $L$ is the point at which $E$ appears, and -where $\textit{EVAL-PT}(P)$, for a point $P$, -is a point $R$ determined as follows: +During an evaluation $V$\iref{intro.execution} of +an expression, conversion, or initialization $E$ +as a core constant expression, the +\indextext{point of!evaluation}% +\indextext{point!of evaluation}% +\indextext{evaluation!point of evaluation, during}% +\defnx{point of evaluation of $E$ during $V$}{point of evaluation during evaluation} +is the program point $P$ determined as follows: \begin{itemize} \item -If a potentially-evaluated subexpression\iref{intro.execution} of -a default member initializer $I$ appears at $P$, and -a (possibly aggregate) initialization during $V$ is using $I$, -then $R$ is $\textit{EVAL-PT}(Q)$ -where $Q$ is the point at which that initialization appears. +If $E$ is a potentially-evaluated subexpression of +a default member initializer $I$, and +$V$ is the evaluation of $E$ in the evaluation of $I$ +as an immediate subexpression of a (possibly aggregate) initialization, then +$P$ is the point of evaluation of that initialization. +\begin{tailnote} +For example, +$E$ can be an immediate invocation in a default member initializer +used by an aggregate initialization appearing at $P$. +\end{tailnote} + \item -Otherwise, if a potentially-evaluated subexpression of -a default argument\iref{dcl.fct.default} appears at $P$, and -an invocation of a function\iref{expr.call} during $V$ -is using that default argument, -then $R$ is $\textit{EVAL-PT}(Q)$ -where $Q$ is the point at which that invocation appears. +Otherwise, +if $E$ is a potentially-evaluated subexpression of +a default argument $A$\iref{dcl.fct.default}, and +$V$ is the evaluation of $E$ in the evaluation of $A$ as +an immediate subexpression of a function call\iref{expr.call}, then +$P$ is the point of evaluation of that function call. + \item -Otherwise, $R$ is $P$. +Otherwise, +$P$ is the point at which $E$ appears. \end{itemize} +During the evaluation $V$ of an expression $E$ as a core constant expression, +the \defnadj{evaluation}{context} of an evaluation $X$ +during $V$ is the set $C$ of program points determined as follows: +\begin{itemize} +\item +If $X$ occurs during the evaluation $Y$ of +a manifestly constant-evaluated expression, +where $Y$ occurs during $V$, then +$C$ is the evaluation context of $X$ during $Y$. \item -Each synthesized point corresponding to an injected declaration produced by -any evaluation sequenced before $X$\iref{intro.execution}. +Otherwise, $C$ contains + \begin{itemize} + \item + the point of evaluation of $E$ during $V$ and + each synthesized point in the instantiation context thereof and + \item + each synthesized point corresponding to an injected declaration + produced by any evaluation executed during $V$ that + is sequenced before $X$\iref{intro.execution}. + \end{itemize} \end{itemize} +\begin{note} +The evaluation context determines the behavior of certain functions +used for reflection\iref{meta.reflection}. +\end{note} +\begin{example} +\begin{codeblock} +struct S; +consteval std::size_t f(int p) { + constexpr std::size_t r = /* @\tcode{Q}@ */ + std::meta::is_complete_type(^^S) ? 1 : 2; // \#1 + if (!std::meta::is_complete_type(^^S)) { // \#2 + std::meta::define_aggregate(^^S, {}); + } + return (p > 0) ? f(p - 1) : r; +} + +consteval { + if (f(1) != 2) { + throw; // OK, not evaluated + } +} +\end{codeblock} +During each evaluation of +\tcode{std::meta::is_complete_type(\caret\caret{}S)} +at \#1\iref{meta.reflection.queries} that is +executed during the evaluation of \tcode{f(1) != 2}, +the evaluation context contains \tcode{Q}, +but does not contain the synthesized point +associated with the injected declaration of \tcode{S}. +However, the synthesized point is in the evaluation context of +\tcode{std::meta::is_complete_type(\caret\caret{}S)} at \#2 +during the evaluation of \tcode{f(0)}. +\end{example} + +\rSec2[expr.const.defns]{Further definitions} + +\pnum +An expression or conversion is \defn{manifestly constant-evaluated} +if it is +\begin{itemize} +\item a \grammarterm{constant-expression}, or +\item the condition of a constexpr if statement\iref{stmt.if}, or +\item the expression corresponding to +a \grammarterm{consteval-block-declaration}\iref{dcl.pre}, or +\item an immediate invocation, or +\item the result of substitution into an atomic constraint expression +to determine whether it is satisfied\iref{temp.constr.atomic}, or +\item the initializer of a variable +that is usable in constant expressions or +has constant initialization\iref{basic.start.static}. +\begin{footnote} +Testing this condition +can involve a notional evaluation of its initializer, +with evaluations of contract assertions +using the ignore evaluation semantic\iref{basic.contract.eval}, +as described above. +\end{footnote} +\begin{example} +\begin{codeblock} +template struct X {}; +X x; // type \tcode{X} +int y; +const int a = std::is_constant_evaluated() ? y : 1; // dynamic initialization to 1 +double z[a]; // error: \tcode{a} is not usable + // in constant expressions +const int b = std::is_constant_evaluated() ? 2 : y; // static initialization to 2 +int c = y + (std::is_constant_evaluated() ? 2 : y); // dynamic initialization to \tcode{y+y} + +constexpr int f() { + const int n = std::is_constant_evaluated() ? 13 : 17; // \tcode{n} is 13 + int m = std::is_constant_evaluated() ? 13 : 17; // \tcode{m} can be 13 or 17 (see below) + char arr[n] = {}; // \tcode{char[13]} + return m + sizeof(arr); +} +int p = f(); // \tcode{m} is 13; initialized to 26 +int q = p + f(); // \tcode{m} is 17 for this call; initialized to 56 +\end{codeblock} +\end{example} +\end{itemize} +\begin{note} +Except for a \grammarterm{static_assert-message}, +a manifestly constant-evaluated expression +is evaluated even in an unevaluated operand\iref{term.unevaluated.operand}. +\end{note} \pnum \indextext{expression!potentially constant evaluated}% @@ -9455,7 +9655,7 @@ a manifestly constant-evaluated expression, \item -a potentially-evaluated expression\iref{basic.def.odr}, +a potentially evaluated expression\iref{basic.def.odr}, \item an immediate subexpression of a \grammarterm{braced-init-list}, @@ -9489,4 +9689,19 @@ a potentially-constant variable named by a potentially constant evaluated expression. \end{itemize} +\pnum +An object \tcode{a} is said to have \defnadj{constant}{destruction} if +\begin{itemize} +\item + it is not of class type nor (possibly multidimensional) array thereof, or +\item + it is of class type or (possibly multidimensional) array thereof, + that class type has a constexpr destructor\iref{dcl.constexpr}, and + for a hypothetical expression $E$ + whose only effect is to destroy \tcode{a}, + $E$ would be a core constant expression + if the lifetime of \tcode{a} and its non-mutable subobjects + (but not its mutable subobjects) were considered to start within $E$. +\end{itemize} + \indextext{expression|)} diff --git a/source/future.tex b/source/future.tex index 14b1e41efe..72dbeabbc5 100644 --- a/source/future.tex +++ b/source/future.tex @@ -805,7 +805,7 @@ \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return visit(std::forward(vis), arg.value);} +Equivalent to: \tcode{return visit(std::forward(vis), arg.\exposid{value_});} \end{itemdescr} \rSec1[depr.ctime]{Deprecated time formatting} @@ -929,7 +929,7 @@ \begin{itemdescr} \pnum \returns -\tcode{system_encoded_string()}. +\tcode{native_encoded_string()}. \end{itemdescr} \indexlibrarymember{generic_string}{path}% @@ -940,7 +940,7 @@ \begin{itemdescr} \pnum \returns -\tcode{generic_system_encoded_string()}. +\tcode{generic_native_encoded_string()}. \end{itemdescr} \rSec1[depr.atomics]{Deprecated atomic operations} diff --git a/source/ifndr.tex b/source/ifndr.tex new file mode 100644 index 0000000000..651918b3b6 --- /dev/null +++ b/source/ifndr.tex @@ -0,0 +1,974 @@ +%!TEX root = std.tex +\infannex{ifndr}{Enumeration of Ill-formed, No Diagnostic Required} + +\rSec1[ifndr.general]{General} + +This Annex documents ill-formed no diagnostic required behavior called out in the main standard text by +the following phrases: no diagnostic is required, no diagnostic required and no diagnostic shall be issued. +Each entry contains a title, a numeric cross reference to the main standard text, a summary of the issue +and a code example demonstrating the issue. The code examples are there to clarify the ill-formed no +diagnostic required cases and will not exhaustively cover all possible ways of invoking that case. + +\rSec1[ifndr.lex]{\ref{lex}: Lexical conventions} + +\rSec2[ifndr.lex.name]{Identifiers} + +\pnum +\ifndrxref{lex.name.reserved} +Some identifiers are reserved for use by \Cpp{} implementations and shall not be used otherwise; no +diagnostic is required. + +\pnum +\begin{example} +\begin{codeblock} +int _z; // no diagnostic required, \tcode{\_z} is reserved because it starts with \tcode{\_} at global scope + +int main() { + int __x; // no diagnostic required, \tcode{\_\_x} is reserved because it starts with \tcode{\_\_} + int _Y; // no diagnostic required, \tcode{\_Y} is reserved because it starts with \tcode{\_} followed by a capital letter + int x__y; // no diagnostic required, \tcode{x\_\_y} is reserved because it contains \tcode{\_\_} +} +\end{codeblock} +\end{example} + + +\rSec1[ifndr.basic]{\ref{basic}: Basics} + +\rSec2[ifndr.basic.link]{Program and linkage} + +\pnum +\ifndrxref{basic.link.consistent.types} +Multiple declarations of an entity must be consistent, +no diagnostic is required if neither declaration is reachable +from the other. + +\pnum +\begin{example} +\begin{codeblocktu}{Module interface of \tcode{M}} +void g(); // \#1 +void h(); // \#2 +template int j; // \#3 +\end{codeblocktu} +\begin{codeblocktu}{Module interface of \tcode{N}} +int g(); // same entity as \#1, different type +namespace h {} // same entity as \#2, not both namespaces +template int j; // same entity as \#3, non-equivalent template heads +\end{codeblocktu} +\begin{codeblocktu}{Other translation unit} +import M; +import N; + // ill-formed, no diagnostic required due to the mismatched pairs above +\end{codeblocktu} +\end{example} + +\rSec2[ifndr.basic.def.odr]{One-definition rule} + +\pnum +\ifndrxref{basic.def.odr.exact.one.def} +Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in +that program outside of a discarded statement\iref{stmt.if}; no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +auto f() { + struct A {}; + return A{}; +} +decltype(f()) g(); +auto x = g(); // ill-formed, no diagnostic required, function \tcode{g} is used but not defined + // in this translation unit, and cannot be defined in any other translation unit + // because its type does not have linkage +\end{codeblock} +\end{example} + + +\pnum +\ifndrxref{basic.def.odr.unnamed.enum.same.type} +If, at any point in the program, there is more than one reachable unnamed enumeration definition in the same scope that have +the same first enumerator name and do not have typedef names for linkage purposes\iref{dcl.enum}, those unnamed enumeration +types shall be the same; no diagnostic required. + + +\pnum +\begin{example} +\begin{codeblock} +// a.h +enum { a }; + +// b.h +enum { a, b }; + +// main.cpp +import "a.h"; +import "b.h"; +auto n = decltype(a)::b; // ill-formed no diagnostic required, more than one unnammed enum + // definition reachable at this point but their types are not the same +\end{codeblock} +\end{example} + + +\rSec2[ifndr.basic.contract]{Contract assertions} + +\rSec3[ifndr.basic.contract.general]{General} + +\pnum +\ifndrxref{basic.contract.vastart.contract.predicate} +The use of \tcode{va_start}\iref{cstdarg.syn} +within the predicate of a contract assertion +is ill-formed, no diagnostic required; + +\pnum +\begin{example} +\begin{codeblock} +void f(...) +{ + va_list args; + contract_assert((va_start(const_cast(args)), true)) // ill-formed, no diagnostic required +} +\end{codeblock} +\end{example} + +\rSec3[ifndr.basic.contract.handler]{Contract-violation handler} + +\pnum +\ifndrxref{basic.contract.handler.replacing.nonreplaceable} +On platforms where +the contract-violation handler +is not replaceable\iref{term.replaceable.function} +a function definition which could be such a replacement function +is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +#include +void handle_contract_violation(const std::contract_violation& violation) {} + // ill-formed, no diagnostic required if violation-handler is not replaceable +\end{codeblock} +\end{example} + + +\rSec2[ifndr.class.member.lookup]{Member name lookup} + +\pnum +\ifndrxref{class.member.lookup.name.refers.diff.decl} +A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. + +\pnum +\begin{example} +\begin{codeblock} +struct foo {}; + +struct bar { + foo *m_foo; + + foo *foo() { + return m_foo; + } // IFNDR, foo now refers to member function foo() while previously referred to struct foo +}; +\end{codeblock} +\end{example} +\begin{example} +\begin{codeblock} +struct B { + static int f(); +}; + +struct D : public B { + using B::f; + int g(decltype(f()) x) { + return 0; + } // Ill-formed no diagnostic required, + // decltype(f()) will refer to B::f() here but if + // moved to the end of D would refer to D::f() + static float f(); +}; + +int main() { + D d; + + return d.g(0); +} +\end{codeblock} +\end{example} + + +\rSec1[ifndr.expr]{\ref{expr}: Expressions} + +\rSec2[ifndr.expr.prim.req]{Requires expressions} + +\pnum +\ifndrxref{expr.prim.req.always.sub.fail} +If the substitution of template arguments into a \grammarterm{requirement} +would always result in a substitution failure, the program is ill-formed; no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +template concept C = requires { + new int[-(int)sizeof(T)]; // ill-formed, no diagnostic required, the size of the allocation is + // required to be greater than zero but can never be +}; +\end{codeblock} +\end{example} + + +\rSec1[ifndr.stmt.stmt]{\ref{stmt}: Statements} + +\rSec2[ifndr.stmt.ambig]{Ambiguity resolution} + +\pnum +\ifndrxref{stmt.ambig.bound.diff.parse} +If, during +parsing, a name in a template parameter is bound differently than it would be bound during a trial parse, +the program is ill-formed. No diagnostic is required. + +\pnum +\begin{example} +\begin{codeblock} +template struct A { const static int a = 20; }; + +template <> struct A<100> { using a = char; }; + +const int x = 10; + +int main() { + using T = const int; + T(x) + (100), (y)(A::a); // ill-formed no diagnostic required, during trial parse the template + // parameter \tcode{x} is bound to the global \tcode{x} later during parsing the template + // parameter \tcode{x} is bound to the local \tcode{x} declared on the same line +} +\end{codeblock} +\end{example} + + +\rSec1[ifndr.dcl.dcl]{\ref{dcl}: Declarations} + +\rSec2[ifndr.dcl.spec]{Specifiers} + +\rSec3[ifndr.dcl.constinit]{The \keyword{constinit} specifier} + +\pnum +\ifndrxref{dcl.constinit.specifier.not.reachable} +If the initializing declaration +of a variable that has the \tcode{constinit} specifier +applied to declarations not reachable from +that initializing declaration +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +int x = 5; // initializing declaration of \tcode{z} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +extern constinit int x; // IFNDR, not reachable from initializing declaration of \tcode{x} +\end{codeblocktu} +\end{example} + +\rSec3[ifndr.dcl.inline]{The \keyword{inline} specifier} + +\pnum +\ifndrxref{dcl.inline.missing.on.definition} +If a function or variable +with external or module linkage +is declared inline +but there is no inline declaration +reachable from the end of some definition domain +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +inline int f(); +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +int f() { return 17; } + // IFNDR, end of definition domain but no inline declaration of \tcode{f} is reachable. +\end{codeblocktu} +\end{example} + +\rSec2[ifndr.dcl.fct]{Functions} + +\rSec3[ifndr.dcl.fct.default]{Default arguments} + +\pnum +\ifndrxref{dcl.fct.default.inline.same.defaults} +If the accumulated set of default arguments +for a given inline function +with definitions in multiple translation units +is different at the end +of different translation units, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +inline int f(int x, int y = 2); +inline int f(int x = 1, int y); + // IFNDR, default arguments of \tcode{f} are \tcode{1} and \tcode{2} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +inline int f(int x = 3, int y = 4); + // IFNDR, default arguments of \tcode{f} are \tcode{3} and \tcode{4} +\end{codeblocktu} +\end{example} + +\rSec2[ifndr.dcl.contract]{Function contract specifiers} + +\rSec3[ifndr.dcl.contract.func]{General} + +\pnum +\ifndrxref{dcl.contract.func.mismatched.contract.specifiers} +If two different first declarations of a function +(which must therefore not be reachable from one another) +do not have equivalent function contract specifiers +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +int f(int x) pre(x >= 0); // IFNDR, different function contract specifiers from the other first declaration of \tcode{f} +int g(int x) pre(x == 0); // IFNDR, different function contract specifiers from the other first declaration of \tcode{g} +int h(int x) pre(x <= 0); // OK, equivalent function contract specifiers to the other first declaration of \tcode{h} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +int f(int x); // IFNDR, different function contract specifiers from the other first declaration of \tcode{f} +int g(int x) pre(x != 0); // IFNDR, different function contract specifiers from the other first declaration of \tcode{g} +int h(int y) pre(y <= 0); // OK, equivalent function contract specifiers to the other first declaration of \tcode{h} +\end{codeblocktu} +\end{example} + +\rSec2[ifndr.dcl.fct.def]{Function definitions} + +\rSec3[ifndr.dcl.fct.def.replace]{Replaceable function definitions} + +\pnum +\ifndrxref{dcl.fct.def.replace.bad.replacement} +A declaration of a replaceable function +that is inline, +not attached to the global module, +does not have \Cpp{} language linkage, +does not have the required return type, +or is not a valid redeclaration of the +corresponding declaration in a standard library header (if there is one) +then the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +extern "C" // IFNDR, wrong language linkage +inline // IFNDR, inline +int // IFNDR, wrong return type +handle_contract_violation(const std::contract::contract_violation&) {} + +void* operator new(decltype(sizeof(0)) noexcept; // IFNDR, mismatched exception specification to declaration + // in \tcode{} +\end{codeblock} +\end{example} + +\rSec2[ifndr.dcl.link]{Linkage specifications} + +\pnum +\ifndrxref{dcl.link.mismatched.language.linkage} +If two declarations of an entity +do not have the same language linkage +and neither is reachable from the other +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +\end{codeblock} +\end{example} + +\rSec2[ifndr.dcl.attr]{Attributes} + +\rSec3[ifndr.dcl.align]{Alignment specifier} + +\pnum +\ifndrxref{dcl.align.diff.translation.units} +No diagnostic is required if declarations of an entity have different \grammarterm{alignment-specifier}s in different +translation units. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +struct S { int x; } s, *p = &s; +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +struct alignas(16) S; // ill-formed, no diagnostic required, definition of \tcode{S} lacks alignment +extern S* p; +\end{codeblocktu} +\end{example} + +\rSec3[ifndr.dcl.attr.indet]{Indeterminate storage} + +\pnum +\ifndrxref{dcl.attr.indet.mismatched.declarations} +If two first declarations of a function +declare a function parameter with +mismatched uses of the \tcode{indeterminate} attribute, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +int h(int x [[indeterminate]]; // IFNDR, mismatched \tcode{[[indeterminate]]} to other first declaration of \tcode{h} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +int h(int x); // IFNDR, mismatched \tcode{[[indeterminate]]} to other first declaration of \tcode{h} +\end{codeblocktu} +\end{example} + +\rSec3[ifndr.dcl.attr.noreturn]{Noreturn attribute} + +\pnum +\ifndrxref{dcl.attr.noreturn.trans.unit.mismatch} +No diagnostic is requried if a function is declared +in one translation unit with the \tcode{noreturn} attribute +but has declarations in other translation units +without the attribute. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +[[noreturn]] void f() {} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +void f(int i); // ill-formed no diagnostic required, declared without \tcode{noreturn} +\end{codeblocktu} +\end{example} + +\rSec1[ifndr.module]{\ref{module}: Modules} + +\rSec2[ifndr.module.unit]{Module units and purviews} + +\pnum +\ifndrxref{module.unit.reserved.identifiers} +All \grammarterm{module-name}s either beginning with an identifier consisting of +std followed by zero or more digits or containing a reserved identifier\iref{lex.token} are reserved and shall not be +specified in a \grammarterm{module-declaration}; no diagnostic is required. + +\pnum +\begin{example} +\begin{codeblock} +module std; // ill-formed no diagnostic required, \tcode{std} is not allowed at the beginning +module module; // ill-formed no diagnostic required, \tcode{module} is a reserved identifier +module std0; // ill-formed no diagnostic required, \tcode{std} followed by digits is not allowed at the beginning +export module _Test; // ill-formed no diagnostic required, \tcode{_Test} is a reserved identifier +export module te__st; // ill-formed no diagnostic required, \tcode{te__st} is a reserved identifier +\end{codeblock} +\end{example} + + +\pnum +\ifndrxref{module.unit.named.module.no.partition} +A named module shall contain exactly one module interface +unit with no module-partition, known as the primary module interface unit of the module; no diagnostic is +required. + +\pnum +\begin{example} +\begin{codeblock} +module A; +export import :Internals; // ill-formed no diagnostic required, module partition not allowed +\end{codeblock} +\end{example} + +\pnum +\ifndrxref{module.unit.unexported.module.partition} +If a module partition of a module +that is a module interface unit +but is not directly or indirectly exported +by the primary module interface unit\iref{module.import}, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +export module M; // primary module interface unit +export import :A; +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +export module M:A; // OK, directly exported by \tcode{M} +export import :B; +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#3} +export module M:B; // OK, indirectly exported by \tcode{M} +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#4} +export module M:C; // IFNDR, not directl or indirectly exported by \tcode{M} +\end{codeblocktu} +\end{example} + +\rSec2[ifndr.module.private.frag]{Private module fragment} + +\pnum +\ifndrxref{module.private.frag.other.module.units} +If a module has a private module fragment +and there is another module unit of that module, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblocktu}{Translation unit \#1} +export module M; +module :private; // private module fragment +\end{codeblocktu} +\begin{codeblocktu}{Translation unit \#2} +module M:A; // IFNDR, partition of \tcode{M} with private module fragment +\end{codeblocktu} +\end{example} + + +\rSec1[ifndr.class]{\ref{class}: Classes} + +\rSec2[ifndr.class.base.init]{Initializing bases and members} + +\pnum +\ifndrxref{class.base.init.delegate.itself} +If a constructor delegates to itself directly or indirectly, +the program is ill-formed, no diagnostic required + +\pnum +\begin{example} +\begin{codeblock} +struct C { + C( int ) { } // \#1: non-delegating constructor + C(): C(42) { } // \#2: delegates to \#1 + C( char c ) : C(42.0) { } // \#3: ill-formed no diagnostic required due to recursion with \#4 + C( double d ) : C('a') { } // \#4: ill-formed no diagnostic required due to recursion with \#3 +}; +\end{codeblock} +\end{example} + + +\rSec2[ifndr.class.virtual]{Virtual functions} + +\pnum +\ifndrxref{class.virtual.pure.or.defined} +A virtual function must be declared pure or defined, no diagnostic required. A virtual function declared pure can be defined +out of line + +\pnum +\begin{example} +\begin{codeblock} +class A { + virtual void f(); +}; + +int main() { + A a; // ill-formed no diagnostic required, virtual function that is not pure but has not definition +} +\end{codeblock} +\end{example} + + +\rSec1[ifndr.over]{\ref{over}: Overloading} + +\rSec2[ifndr.over.literal]{User-defined literals} + +\pnum +\ifndrxref{over.literal.reserved} +Some literal suffix identifiers are +reserved for future standardization. A declaration whose literal-operator-id uses such a literal +suffix identifier is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +float operator ""E(const char*); // ill-formed, no diagnostic required, reserved literal suffix +double operator"" _Bq(long double); // ill-formed, no diagnostic required, // uses the reserved identifier \tcode{_Bq} +\end{codeblock} +\end{example} + +\rSec1[ifndr.temp]{\ref{temp}: Templates} + +\rSec2[ifndr.temp.pre]{Preamble} + +\pnum +\ifndrxref{temp.pre.reach.def} +A definition of a function template, member function of a class template, variable template, or static data +member of a class template shall be reachable from the end of every definition domain\iref{basic.def.odr} in which it is +implicitly instantiated\iref{temp.inst} unless the corresponding specialization is explicitly instantiated\iref{temp.explicit} in +some translation unit; no diagnostic is required. + +\pnum +\begin{example} +\begin{codeblock} +// a.h +template +void f(); + +// a.cpp +#include "a.h" +int main() { + f(); // ill-formed no diagnostic required, function template implicity + // instantiated but not reachable definition +} +\end{codeblock} +\end{example} + + +\rSec2[ifndr.temp.arg.template]{Template template arguments} + +\pnum +\ifndrxref{temp.arg.template.sat.constraints} +Any partial specializations\iref{temp.spec.partial} associated with the primary template are considered when a specialization +based on the template template-parameter is instantiated. If a specialization is not reachable from the point of +instantiation, and it would have been selected had it been reachable, the program is ill-formed, no diagnostic +required. + +\pnum +\begin{example} +\begin{codeblock} +template struct A { + int x; +}; + +template class V> struct C { + V y; + V z; +}; + +C c; + +// Ill-formed no diagnostic required, specialization is not reachable from point +// of instantiation above and it would have been selected if it had +template struct A { + long x; +}; +\end{codeblock} +\end{example} + + +\rSec2[ifndr.constr.atomic]{Atomic constraints} + +\pnum +\ifndrxref{temp.constr.atomic.equiv.but.not.equiv} +If the validity or meaning of the program depends on whether two atomic +constraints are equivalent, +and they are functionally equivalent but not equivalent, the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +template void f2() +requires Add1<2 * N>; +template int f2() +requires Add1 && true; +void h2() { +f2<0>(); // ill-formed, no diagnostic required, + // requires determination of subsumption between atomic constraints that are + // functionally equivalent but not equivalent +\end{codeblock} +\end{example} + +\pnum +\ifndrxref{temp.constr.atomic.sat.result.diff} +If, at different points in the program, the satisfaction result is different for identical atomic constraints and template arguments, the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +template +concept Complete = sizeof(T) == sizeof(T); + +struct A; +static_assert(!Complete); // \#1 +struct A {}; +static_assert(Complete); // ill-formed no diagnostic required, satisfaction + // result differs from point \#1 +\end{codeblock} +\end{example} + + +\rSec2[ifndr.temp.constr.normal]{Constraint normalization} + +\pnum +\ifndrxref{temp.constr.normal.invalid} +If during constraint normalization any such substitution results in an invalid type or expression, +the program is ill-formed; no diagnostic is required + +\pnum +\begin{example} +\begin{codeblock} +template concept A = T::value || true; +template concept B = A; +template concept C = B; // Ill-formed no diagnostic required, it + // would form the invalid type V\&* in the parameter mapping +\end{codeblock} +\end{example} + + +%TODO: There are two earlier "no diagnostic requireds" in this section, i am +% not sure if they a really are worth calling distinct cases of ifndr. + +\rSec2[ifndr.temp.spec.partial]{Partial specialization} + +\pnum +\ifndrxref{temp.spec.partial.general.partial.reachable} +A partial specialization shall be reachable from any use of a template specialization that would make use of the +partial specialization as the result of an implicit or explicit instantiation; no diagnostic is required. + +\pnum +\begin{example} +\begin{codeblock} +template class X{ +public: + void foo(){}; +}; + +template class X; // ill-formed no diagnostic required, explicit instantiation + // and partial specialization is not reachable + +template class X{ +public: + void baz(); +}; +\end{codeblock} +\end{example} + + +\rSec2[ifndr.temp.names]{Names of template specializations} + + +\rSec2[ifndr.temp.fct]{Function templates} + +\rSec3[ifndr.temp.over.link]{Function template overloading} + +\pnum +\ifndrxref{temp.over.link.equiv.not.equiv} +If the validity or meaning of the program depends on whether two constructs are equivalent, and they are +functionally equivalent but not equivalent, the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +template +struct A{}; + +// ill-formed, no diagnostic required, the following declarations are functionally equivalent but not equivalent +template void f(A, A); +template void f(A, A); +\end{codeblock} +\end{example} + +\rSec2[ifndr.temp.res]{Name resolution} + +\rSec3[ifndr.temp.res.general]{General} + +\pnum +\ifndrxref{temp.res.general.default.but.not.found} +If the validity or meaning of the program would be changed by considering a default argument or default +template argument introduced in a declaration that is reachable from the point of instantiation of a +specialization\iref{temp.point} but is not found by lookup for the specialization, the program is ill-formed, no +diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +\end{codeblock} +\end{example} + +%TODO: SY, JMB: We need to produce an example for this case. + +\rSec3[ifndr.temp.dep.res]{Dependent name resolution} + +\rSec4[ifndr.temp.point]{Point of instantiation} + +\pnum +\ifndrxref{temp.point.diff.pt.diff.meaning} +A specialization for a class template has at most one point of instantiation within a translation unit. A +specialization for any template may have points of instantiation in multiple translation units. If two different +points of instantiation give a template specialization different meanings according to the one-definition +rule (6.3), the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +// a.h +#include + +template +struct is_complete : std::false_type {}; + +template +struct is_complete> : std::true_type {}; + +// a.cpp +#include "a.h" +struct X; +static_assert(!is_complete::value); + +// b.cpp +#include "a.h" +struct X { }; +static_assert(is_complete::value); +\end{codeblock} +\end{example} + +\rSec4[ifndr.temp.dep.candidate]{Candidate functions} + +\pnum +\ifndrxref{temp.dep.candidate.different.lookup.different} +If considering all function declarations +with external linkage +in the associated namespaces in all translations +would make a dependent call\iref{temp.dep} ill-formed +or find a better match, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +\end{codeblock} +\end{example} + +%TODO: JMB: produce an example + + +\rSec3[ifndr.temp.explicit]{Explicit instantiation} + +\pnum +\ifndrxref{temp.explicit.decl.implicit.inst} +An entity that is the subject of +an explicit instantiation declaration and that is also used in a way that would otherwise cause an implicit +instantiation\iref{temp.inst} in the translation unit shall be the subject of an explicit instantiation definition +somewhere in the program; otherwise the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +// Explicit instantiation declaration +extern template class std::vector; + +int main() { + std::cout << std::vector().size(); // ill-formed no diagnostic required, implicit instantiation + // but no explicit instantiation definition +} +\end{codeblock} +\end{example} + +\rSec3[ifndr.temp.expl.spec]{Explicit specialization} + +\pnum +\ifndrxref{temp.expl.spec.unreachable.declaration} +If an implicit instantiation of a template would occur +and there is an unreachable explicit specialization +that would have matched, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +\end{codeblock} +\end{example} + +%TODO: JMB: produce an example + +\pnum +\ifndrxref{temp.expl.spec.missing.definition} +If an explicit specialization of a template is +declared but there is no definition provided +for that specialization, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +\end{codeblock} +\end{example} + +%TODO: JMB: produce an example + + +\rSec2[ifndr.temp.deduct]{Template argument deduction} + +\rSec3[ifndr.temp.deduct.general]{General} + +\pnum +\ifndrxref{temp.deduct.general.diff.order} +If substitution +into different declarations +of the same function template +would cause template instantiations to occur +in a different order or not at all, +the program is ill-formed; no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +template struct A { using X = typename T::X; }; +template typename T::X h(typename A::X); // \#1 +template auto h(typename A::X) -> typename T::X; // redeclaration \#2 +template void h(...) { } + +void x() { + h(0); // ill-formed, no diagnostic required + // \#1 fails to find \tcode{T::X} and instantiates nothing + // \#2 instantiates \tcode{A} +} +\end{codeblock} +\end{example} + +%TODO: JMB: Someone should confirm that the comments correctly describe why +%this example is ill-formed. + + +\rSec1[ifndr.cpp]{\ref{cpp}: Preprocessing directives} + +\rSec2[ifndr.cpp.cond]{Conditional inclusion} + +\pnum +\ifndrxref{cpp.cond.defined.after.macro} +If the expansion of a macro produces the preprocessing token \tcode{defined} +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +#define A defined +#if A // Ill-formed no diagnostic required, \tcode{defined} is generated by macro replacement + // in controlling expression +#endif +\end{codeblock} +\end{example} + +\pnum +\ifndrxref{cpp.cond.defined.malformed} +If the \tcode{defined} unary operator is used when it +does not match +one of the specified grammatical forms, +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +#define A +#define B A) +#if defined ( B // Ill-formed no diagnostic required, unary operator \tcode{defined} did not match + // valid form before replacement +#endif +\end{codeblock} +\end{example} + +\rSec2[ifndr.cpp.include]{Source file inclusion} + +\pnum +\ifndrxref{cpp.include.malformed.headername} +If the \grammarterm{header-name-tokens} after +an \tcode{include} directive +cannot be formed into a \grammarterm{header-name} +(with implementation-defined treatment of whitespace), +the program is ill-formed, no diagnostic required. + +\pnum +\begin{example} +\begin{codeblock} +#include `` // Ill-formed no diagnoatic required, does not match one of the two allowable forms +\end{codeblock} +\end{example} diff --git a/source/intro.tex b/source/intro.tex index 5cb98d2101..3e24d06dce 100644 --- a/source/intro.tex +++ b/source/intro.tex @@ -213,7 +213,7 @@ \definition{constant evaluation}{defns.const.eval} \indexdefn{constant evaluation}% evaluation that is performed as part of evaluating an expression -as a core constant expression\iref{expr.const} +as a core constant expression\iref{expr.const.core} \definition{constant subexpression}{defns.const.subexpr} \indexdefn{constant subexpression}% @@ -265,7 +265,7 @@ Erroneous behavior is always the consequence of incorrect program code. Implementations are allowed, but not required, to diagnose it\iref{intro.compliance.general}. -Evaluation of a constant expression\iref{expr.const} +Evaluation of a constant expression\iref{expr.const.core} never exhibits behavior specified as erroneous in \ref{intro} through \ref{\lastcorechapter}. \end{defnote} @@ -462,6 +462,11 @@ \end{codeblock} \end{example} +\indexdefn{property!of the implementation}% +\definition{property of the implementation}{defns.impl.prop} +behavior, for a well-formed program\iref{defns.well.formed} +construct and correct data, that depends on the implementation + \definition{referenceable type}{defns.referenceable} \indexdefn{type!referenceable}% type that is either an @@ -525,7 +530,7 @@ it is \impldef{whether runtime-undefined behavior results in the expression being deemed non-constant} whether runtime-undefined behavior results in the expression being deemed non-constant -(as specified in~\ref{expr.const}) and +(as specified in~\ref{expr.const.core}) and \item runtime-undefined behavior has no other effect. \end{itemize} @@ -670,7 +675,7 @@ \termref{defns.diagnostic}{diagnostic message}{}), to terminating a translation or execution (with the issuance of a diagnostic message). Many incorrect program constructs do not engender undefined behavior; they are required to be diagnosed. -Evaluation of a constant expression\iref{expr.const} never exhibits behavior explicitly +Evaluation of a constant expression\iref{expr.const.core} never exhibits behavior explicitly specified as undefined in \ref{intro} through \ref{\lastcorechapter}. \end{defnote} @@ -782,7 +787,7 @@ \item a contract assertion\iref{basic.contract.eval} evaluated with a checking semantic -in a manifestly constant-evaluated context\iref{expr.const} +in a manifestly constant-evaluated context\iref{expr.const.defns} resulting in a contract violation, \end{itemize} a conforming implementation @@ -805,7 +810,7 @@ a \grammarterm{static_assert-declaration} that fails\iref{dcl.pre}, or \item a contract assertion evaluated with a terminating semantic\iref{basic.contract.eval} -in a manifestly constant-evaluated context\iref{expr.const} +in a manifestly constant-evaluated context\iref{expr.const.defns} resulting in a contract violation. \end{itemize} @@ -860,6 +865,7 @@ results in a contract violation\iref{structure.specifications}. \pnum +\recommended An implementation is encouraged to document its limitations in the size or complexity of the programs it can successfully process, if possible and where known. @@ -919,10 +925,14 @@ \pnum \indextext{behavior!implementation-defined}% -Certain aspects and operations of the abstract machine are described in this +Certain aspects and operations of the abstract machine +constitute the parameters of the abstract machine and +are described in this document as implementation-defined behavior (for example, -\tcode{sizeof(int)}). These constitute the parameters of the abstract machine. -Each implementation shall include documentation describing its characteristics +\tcode{sizeof(int)}) +or as properties of the implementation (for example, padding in class types). +For implementation-defined behavior, +each implementation shall include documentation describing its characteristics and behavior in these respects. \begin{footnote} This documentation also includes diff --git a/source/iostreams.tex b/source/iostreams.tex index d5d867ad11..3320a770af 100644 --- a/source/iostreams.tex +++ b/source/iostreams.tex @@ -363,17 +363,19 @@ serves as a base class for class templates \tcode{basic_stringbuf}, \tcode{basic_filebuf}, +\tcode{basic_syncbuf}, and -\tcode{basic_syncbuf}. +\tcode{basic_spanbuf}. \pnum The class template specialization \tcode{basic_istream} serves as a base class for class templates -\tcode{basic_istringstream} +\tcode{basic_istringstream}, +\tcode{basic_ifstream}, and -\tcode{basic_ifstream}. +\tcode{basic_ispanstream}. \pnum The @@ -382,17 +384,19 @@ serves as a base class for class templates \tcode{basic_ostringstream}, \tcode{basic_ofstream}, +\tcode{basic_osyncstream}, and -\tcode{basic_osyncstream}. +\tcode{basic_ospanstream}. \pnum The class template specialization \tcode{basic_iostream} serves as a base class for class templates -\tcode{basic_stringstream} +\tcode{basic_stringstream}, +\tcode{basic_fstream}, and -\tcode{basic_fstream}. +\tcode{basic_spanstream}. \pnum \begin{note} @@ -404,9 +408,8 @@ \end{note} \pnum -Other \grammarterm{typedef-name}{s} define instances of -class templates -specialized for +Other \grammarterm{typedef-name}{s} designate +class template specializations for \tcode{char} or \keyword{wchar_t} @@ -5651,7 +5654,7 @@ calls \tcode{setstate(badbit)} (which may throw -\tcode{ios_base::failure}\iref{iostate.flags}, +\tcode{ios_base::failure}\iref{iostate.flags}), and returns \tcode{-1}. Otherwise, returns zero. @@ -7798,7 +7801,7 @@ \effects Equivalent to: \begin{codeblock} -print(stream, runtime_format(string(fmt.get()) + '\n'), std::forward(args)...); +print(stream, dynamic_format(string(fmt.get()) + '\n'), std::forward(args)...); \end{codeblock} \end{itemdescr} @@ -7924,7 +7927,7 @@ Equivalent to: \begin{codeblock} string out = vformat(fmt, args); -vprint_nonunicode("{}", make_format_args(out)); +vprint_nonunicode(stream, "{}", make_format_args(out)); \end{codeblock} \end{itemdescr} @@ -9328,7 +9331,7 @@ template void str(const T& t); - private: + private: basic_stringbuf @\exposid{sb}@; // \expos }; } @@ -13714,7 +13717,7 @@ basic_string string(const Allocator& a = Allocator()) const; std::string display_string() const; - std::string system_encoded_string() const; + std::string native_encoded_string() const; std::wstring wstring() const; std::u8string u8string() const; std::u16string u16string() const; @@ -13726,7 +13729,7 @@ basic_string generic_string(const Allocator& a = Allocator()) const; std::string generic_display_string() const; - std::string generic_system_encoded_string() const; + std::string generic_native_encoded_string() const; std::wstring generic_wstring() const; std::u8string generic_u8string() const; std::u16string generic_u16string() const; @@ -13786,7 +13789,7 @@ \indexlibrarymember{value_type}{path}% \pnum -\tcode{value_type} is a \keyword{typedef} for the +\tcode{value_type} is a \grammarterm{typedef-name} for the operating system dependent encoded character type used to represent pathnames. \indexlibrarymember{preferred_separator}{path}% @@ -14048,7 +14051,8 @@ so no conversion from \tcode{char} value type arguments or to \tcode{char} value type return values is performed. For Windows-based operating systems, the -native ordinary encoding is determined by calling a Windows API function. +native ordinary encoding is determined by +the current locale encoding and the Windows \tcode{AreFileApisANSI} function. \end{note} \begin{note} This results in behavior identical to other C and \Cpp{} @@ -14701,7 +14705,7 @@ \indexlibrarymember{u16string}{path}% \indexlibrarymember{u32string}{path}% \begin{itemdecl} -std::string system_encoded_string() const; +std::string native_encoded_string() const; std::wstring wstring() const; std::u8string u8string() const; std::u16string u16string() const; @@ -14776,7 +14780,7 @@ \indexlibrarymember{generic_u16string}{path}% \indexlibrarymember{generic_u32string}{path}% \begin{itemdecl} -std::string generic_system_encoded_string() const; +std::string generic_native_encoded_string() const; std::wstring generic_wstring() const; std::u8string generic_u8string() const; std::u16string generic_u16string() const; @@ -17685,7 +17689,7 @@ \begin{itemdecl} void filesystem::create_hard_link(const path& to, const path& new_hard_link); void filesystem::create_hard_link(const path& to, const path& new_hard_link, - error_code& ec) noexcept; + error_code& ec) noexcept; \end{itemdecl} \begin{itemdescr} @@ -17720,7 +17724,7 @@ \begin{itemdecl} void filesystem::create_symlink(const path& to, const path& new_symlink); void filesystem::create_symlink(const path& to, const path& new_symlink, - error_code& ec) noexcept; + error_code& ec) noexcept; \end{itemdecl} \begin{itemdescr} @@ -18276,7 +18280,7 @@ \begin{itemdecl} void filesystem::last_write_time(const path& p, file_time_type new_time); void filesystem::last_write_time(const path& p, file_time_type new_time, - error_code& ec) noexcept; + error_code& ec) noexcept; \end{itemdecl} \begin{itemdescr} diff --git a/source/iterators.tex b/source/iterators.tex index 7a8c8b6ff7..ed599d9725 100644 --- a/source/iterators.tex +++ b/source/iterators.tex @@ -1675,6 +1675,7 @@ template concept @\deflibconcept{sentinel_for}@ = @\libconcept{semiregular}@ && + !@\exposid{is-integer-like}@ && @\libconcept{input_or_output_iterator}@ && @\exposconcept{weakly-equality-comparable-with}@; // see \ref{concept.equalitycomparable} \end{itemdecl} @@ -1691,6 +1692,9 @@ \range{++i}{s} denotes a range. \item \tcode{\libconcept{assignable_from}} is either modeled or not satisfied. + +\item If \tcode{I} and \tcode{S} are the same type, then + \tcode{i == i} is \tcode{true}. \end{itemize} \end{itemdescr} @@ -1752,7 +1756,7 @@ for cv-unqualified non-array object types \tcode{S} and \tcode{I} if \tcode{S} and/or \tcode{I} is a program-defined type. Such specializations shall -be usable in constant expressions\iref{expr.const} and +be usable in constant expressions\iref{expr.const.init} and have type \tcode{const bool}. \pnum @@ -6591,7 +6595,7 @@ \pnum \remarks If the initializer \tcode{T()} in the declaration \tcode{auto x = T();} -is a constant initializer\iref{expr.const}, +is a constant initializer\iref{expr.const.init}, then these constructors are \keyword{constexpr} constructors. \end{itemdescr} diff --git a/source/lex.tex b/source/lex.tex index 80f2e8c1e6..399c5df5b9 100644 --- a/source/lex.tex +++ b/source/lex.tex @@ -42,6 +42,13 @@ Translation units can be separately translated and then later linked to produce an executable program\iref{basic.link}. \end{note} +\begin{note} +Source files, translation units, and translated translation units +need not necessarily be stored as files, nor need there be any one-to-one +correspondence between these entities and any external representation. +The description is conceptual only, +and does not specify any particular implementation. +\end{note} \indextext{compilation!separate|)} \rSec1[lex.phases]{Phases of translation}% @@ -192,13 +199,6 @@ dependency\iref{module.unit,module.import} are required to be available. \begin{note} -Source files, translation -units and translated translation units need not necessarily be stored as -files, nor need there be any one-to-one correspondence between these -entities and any external representation. The description is conceptual -only, and does not specify any particular implementation. -\end{note} -\begin{note} Previously translated translation units can be preserved individually or in libraries. The separate translation units of a program communicate\iref{basic.link} by (for example) calls to functions whose names have external or module linkage, @@ -227,11 +227,14 @@ that it be instantiated at an earlier point\iref{temp.inst}. \end{note} -Each instantiation results in new program constructs. The program is ill-formed if any instantiation fails. During the analysis and translation of tokens, -certain expressions are evaluated\iref{expr.const}. +each manifestly constant-evaluated expression is evaluated\iref{expr.const.defns}. +The values of these expressions affect +the types named and reflection values used in the program and +thus the syntactic analysis. +Their evaluation also can produce side effects that affect that analysis. Constructs appearing at a program point $P$ are analyzed in a context where each side effect of evaluating an expression $E$ as a full-expression is complete if and only if @@ -261,19 +264,19 @@ void fn() { /* @$p_1$@ */ Incomplete i; // OK } - }; /* @$p_2$@ */ + } /* @$p_2$@ */ ; consteval { define_aggregate(^^Incomplete, {}); } -}; /* @$p_3$@ */ +} /* @$p_3$@ */ ; \end{codeblock} Constructs at $p_1$ are analyzed in a context -where the side effect of the call to \tcode{define_aggregate} is evaluated +where the side effect of the call to \tcode{define_aggregate} is complete because \begin{itemize} \item -$E$ is the expression corresponding to a consteval block, and +the call appears in a consteval block, and \item $p_1$ is in a complete-class context of \tcode{S} and the consteval block is reachable from $p_3$. @@ -585,6 +588,7 @@ \pnum Each preprocessing token that is converted to a token\iref{lex.token} shall have the lexical form of a keyword, an identifier, a literal, +a header name, or an operator or punctuator. \pnum @@ -872,12 +876,14 @@ identifier\br keyword\br literal\br + header-name\br operator-or-punctuator \end{bnf} \pnum \indextext{\idxgram{token}}% -There are five kinds of tokens: identifiers, keywords, literals, +There are six kinds of tokens: identifiers, keywords, literals, +header names, operators, and other separators. \indextext{token|)} @@ -979,6 +985,12 @@ \keyword{pre} \\ \end{multicolfloattable} +\pnum +\begin{note} +Identifiers with special meaning +cannot be used as macro names\iref{cpp.replace.general}. +\end{note} + \pnum \indextext{\idxcode{_}|see{character, underscore}}% \indextext{character!underscore!in identifier}% @@ -987,7 +999,7 @@ appearing as a \grammarterm{token} or \grammarterm{preprocessing-token} are reserved for use by \Cpp{} implementations and shall -not be used otherwise; no diagnostic is required. +not be used otherwise; no diagnostic is required \ifndrdef{lex.name.reserved}. \begin{itemize} \item Each identifier that contains a double underscore @@ -1021,7 +1033,7 @@ \indextext{keyword|(}% The identifiers shown in \tref{lex.key} are reserved for use as keywords (that is, they are unconditionally treated as keywords in -phase 7) except in an \grammarterm{attribute-token}\iref{dcl.attr.grammar}. +phases 6 and 7) except in an \grammarterm{attribute-token}\iref{dcl.attr.grammar}. \begin{note} The \keyword{register} keyword is unused but is reserved for future use. @@ -1117,6 +1129,11 @@ \keyword{while} \\ \end{multicolfloattable} +\pnum +\begin{note} +Keywords cannot be used as macro names\iref{cpp.replace.general}. +\end{note} + \pnum Furthermore, the alternative representations shown in \tref{lex.key.digraph} for certain operators and @@ -1781,6 +1798,15 @@ else the larger or smaller representable value nearest the scaled value, chosen in an \impldef{choice of larger or smaller value of \grammarterm{floating-point-literal}} manner. +\begin{example} +The following example assumes that +\tcode{std::float32_t} is supported\iref{basic.extended.fp}. +\begin{codeblock} +std::float32_t x = 0.0f32; // value \tcode{0} is exactly representable +std::float32_t y = 0.1f32; // rounded to one of two values nearest to \tcode{0.1} +std::float32_t z = 1e1000000000f32; // either greatest finite value or positive infinity +\end{codeblock} +\end{example} \rSec2[lex.string]{String literals} diff --git a/source/lib-intro.tex b/source/lib-intro.tex index c0b53ee3ad..24029adb67 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -541,11 +541,11 @@ namespace std { template requires @\libconcept{convertible_to}@> - constexpr decay_t @\exposidnc{decay-copy}@(T&& v) // \expos + constexpr decay_t @\exposidnc{decay-copy}@(T&& v) // \expos noexcept(is_nothrow_convertible_v>) { return std::forward(v); } - constexpr auto @\exposidnc{synth-three-way}@ = // \expos + constexpr auto @\exposidnc{synth-three-way}@ = // \expos [](const T& t, const U& u) requires requires { { t < u } -> @\exposconcept{boolean-testable}@; @@ -562,8 +562,15 @@ }; template - using @\exposidnc{synth-three-way-result}@ = // \expos + using @\exposidnc{synth-three-way-result}@ = // \expos decltype(@\exposidnc{synth-three-way}@(declval(), declval())); + + template + concept @\defexposconceptnc{constexpr-wrapper-like}@ = // \expos + @\libconcept{convertible_to}@ && + @\libconcept{equality_comparable_with}@ && + bool_constant::value && + bool_constant(T()) == T::value>::value; } \end{codeblock} @@ -1817,12 +1824,6 @@ rvalue of type \tcode{const T}. \end{itemize} -\pnum -In general, a default constructor is not required. Certain container class -member function signatures specify \tcode{T()} as a default argument. -\tcode{T()} shall be a well-defined expression\iref{dcl.init} if one of those -signatures is called using the default argument\iref{dcl.fct.default}. - \begin{oldconcepttable}{EqualityComparable}{}{cpp17.equalitycomparable} {x{1in}x{1in}p{3in}} \topline @@ -1850,7 +1851,6 @@ \tcode{<} is a strict weak ordering relation\iref{alg.sorting} \\ \end{oldconcepttable} -\enlargethispage{-3\baselineskip} \begin{oldconcepttable}{DefaultConstructible}{}{cpp17.defaultconstructible} {x{2.15in}p{3in}} \topline @@ -2347,12 +2347,12 @@ \pnum \remarks -If \tcode{Allocator} is a class template instantiation of the form +If \tcode{Allocator} is a class template specialization of the form \tcode{SomeAllocator}, where \tcode{Args} is zero or more type arguments, and \tcode{Allocator} does not supply a \tcode{rebind} member template, the standard \tcode{allocator_traits} template uses \tcode{SomeAllocator} in place of \tcode{Allocator::re\-bind::other} -by default. For allocator types that are not template instantiations of the +by default. For allocator types that are not template specializations of the above form, no default is provided. \pnum @@ -3074,7 +3074,7 @@ Let \tcode{\placeholder{F}} denote a standard library function\iref{global.functions}, a standard library static member function, -or an instantiation +or a specialization of a standard library function template. Unless \tcode{\placeholder{F}} is designated an \defnadj{addressable}{function}, @@ -3096,7 +3096,7 @@ or if it attempts to form a pointer-to-member designating either a standard library non-static member function\iref{member.functions} -or an instantiation of a standard library member function template. +or a specialization of a standard library member function template. \pnum Let \tcode{\placeholder{F}} denote @@ -3104,6 +3104,14 @@ Unless \tcode{\placeholder{F}} is designated an addressable function, it is unspecified if or how a reflection value designating the associated entity can be formed. +For any value \tcode{\placeholder{p}} of type \tcode{meta::info} that +represents a reflection of a parameter of \tcode{\placeholder{F}}, +it is unspecified if \tcode{has_identifier(\placeholder{p})} +returns \tcode{true} or \tcode{false}, and +if \tcode{meta::has_identifier(\placeholder{p})} is \tcode{true}, then +the \ntmbs{} produced by +\tcode{meta::identifier_of(\placeholder{p})} and +\tcode{meta::u8identifier_of(\placeholder{p})} is unspecified. %FIXME: Why is this not an example, but a note that begins with "For example"? \begin{note} For example, it is possible that \tcode{std::meta::members_of} @@ -3788,6 +3796,16 @@ the \Cpp{} standard library may be recursively reentered} which functions in the \Cpp{} standard library may be recursively reentered. +\pnum +During the execution of +a standard library non-static member function $F$ on an object, +if that object is accessed through a glvalue that is not obtained, +directly or indirectly, +from the object parameter of $F$, +in a manner that can conflict\iref{intro.races} +with any access that $F$ is permitted to perform\iref{res.on.data.races}, +the behavior is undefined unless otherwise specified. + \rSec3[res.on.data.races]{Data race avoidance} \pnum @@ -3977,7 +3995,7 @@ \rSec3[value.error.codes]{Value of error codes} \pnum -Certain functions in the \Cpp{} standard library report errors via a +Certain functions in the \Cpp{} standard library report errors via an \tcode{error_code}\iref{syserr.errcode.overview} object. That object's \tcode{category()} member shall return \tcode{system_category()} for errors originating from the operating system, or a reference to an diff --git a/source/limits.tex b/source/limits.tex index bdc1f3deb6..e0596a320a 100644 --- a/source/limits.tex +++ b/source/limits.tex @@ -111,7 +111,7 @@ \item% Recursive constexpr function invocations\iref{dcl.constexpr} [512]. \item% -Full-expressions evaluated within a core constant expression\iref{expr.const} [1\,048\,576]. +Full-expressions evaluated within a core constant expression\iref{expr.const.core} [1\,048\,576]. \item% Template parameters in a template declaration\iref{temp.param} [1\,024]. \item% diff --git a/source/macros.tex b/source/macros.tex index ae5591106e..dad5db884e 100644 --- a/source/macros.tex +++ b/source/macros.tex @@ -386,6 +386,17 @@ \newcommand{\ctype}{\Fundesc{Type}} \newcommand{\templalias}{\Fundesc{Alias template}} +%% Undefined behavior and ill-formed, no diagnostic required +% Use in main body of text to mark undefined behavior +\newcommand{\ubdef}[1]{\nolinebreak[3] (\label{ub:#1}\ref{ubx:#1})} +% Use in Annex to cross-reference marked undefined behavior +\newcommand{\ubxref}[1]{\label{ubx:#1}\textbf{Specified in:}\space\ref{ub:#1}\newline} + +% Use in main body of text to mark IFNDR +\newcommand{\ifndrdef}[1]{\nolinebreak[3] (\label{ifndr:#1}\ref{ifndrx:#1})} +% Use in Annex to cross-reference marked IFNDR +\newcommand{\ifndrxref}[1]{\label{ifndrx:#1}\textbf{Specified in:}\space\ref{ifndr:#1}} + %% Cross-reference \newcommand{\xref}[1]{\textsc{See also:}\space #1} \newcommand{\xrefc}[1]{\xref{\IsoC{}, #1}} @@ -406,8 +417,10 @@ \ExplSyntaxOff %% Inline non-parenthesized table reference (override memoir's \tref) +\providecommand{\tref}{} \renewcommand{\tref}[1]{\hyperref[tab:#1]{\tablerefname \nolinebreak[3] \ref*{tab:#1}}} %% Inline non-parenthesized figure reference (override memoir's \fref) +\providecommand{\fref}{} \renewcommand{\fref}[1]{\hyperref[fig:#1]{\figurerefname \nolinebreak[3] \ref*{fig:#1}}} %% NTBS, etc. @@ -609,7 +622,7 @@ #1:}}\CodeBlockSetup}{} % An environment for command / program output that is not C++ code. -\lstnewenvironment{outputblock}{\lstset{language=}}{} +\lstnewenvironment{outputblock}{\lstset{escapechar=@, language=}}{} % A code block in which single-quotes are digit separators % rather than character literals. diff --git a/source/memory.tex b/source/memory.tex index efbf7fee28..be9812fa2d 100644 --- a/source/memory.tex +++ b/source/memory.tex @@ -88,6 +88,8 @@ bool is_sufficiently_aligned(T* ptr); // freestanding // \ref{obj.lifetime}, explicit lifetime management + template + constexpr void start_lifetime(T& r) noexcept; // freestanding template T* start_lifetime_as(void* p) noexcept; // freestanding template @@ -413,47 +415,52 @@ O ofirst, S olast); // see \ref{algorithms.parallel.overloads} } - template + template::value_type> constexpr void uninitialized_fill(NoThrowForwardIterator first, // freestanding NoThrowForwardIterator last, const T& x); - template + template::value_type> void uninitialized_fill(ExecutionPolicy&& exec, // freestanding-deleted, NoThrowForwardIterator first, // see \ref{algorithms.parallel.overloads} NoThrowForwardIterator last, const T& x); - template + template::value_type> constexpr NoThrowForwardIterator uninitialized_fill_n(NoThrowForwardIterator first, Size n, const T& x); // freestanding - template + template::value_type> NoThrowForwardIterator uninitialized_fill_n(ExecutionPolicy&& exec, // freestanding-deleted, NoThrowForwardIterator first, // see \ref{algorithms.parallel.overloads} Size n, const T& x); namespace ranges { - template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S, class T> + template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S, class T = iter_value_t> requires @\libconcept{constructible_from}@, const T&> constexpr I uninitialized_fill(I first, S last, const T& x); // freestanding - template<@\exposconcept{nothrow-forward-range}@ R, class T> + template<@\exposconcept{nothrow-forward-range}@ R, class T = range_value_t> requires @\libconcept{constructible_from}@, const T&> constexpr borrowed_iterator_t uninitialized_fill(R&& r, const T& x); // freestanding - template<@\exposconcept{nothrow-forward-iterator}@ I, class T> + template<@\exposconcept{nothrow-forward-iterator}@ I, class T = iter_value_t> requires @\libconcept{constructible_from}@, const T&> constexpr I uninitialized_fill_n(I first, // freestanding iter_difference_t n, const T& x); template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{nothrow-random-access-iterator}@ I, - @\exposconcept{nothrow-sized-sentinel-for}@ S, class T> + @\exposconcept{nothrow-sized-sentinel-for}@ S, class T = iter_value_t> requires @\libconcept{constructible_from}@, const T&> I uninitialized_fill(Ep&& exec, I first, S last, const T& x); // freestanding-deleted, // see \ref{algorithms.parallel.overloads} - template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{nothrow-sized-random-access-range}@ R, class T> + template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{nothrow-sized-random-access-range}@ R, + class T = range_value_t> requires @\libconcept{constructible_from}@, const T&> borrowed_iterator_t uninitialized_fill(Ep&& exec, R&& r, // freestanding-deleted, const T& x); // see \ref{algorithms.parallel.overloads} - template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{nothrow-random-access-iterator}@ I, class T> + template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{nothrow-random-access-iterator}@ I, class T = iter_value_t> requires @\libconcept{constructible_from}@, const T&> I uninitialized_fill_n(Ep&& exec, I first, // freestanding-deleted, iter_difference_t n, const T& x); // see \ref{algorithms.parallel.overloads} @@ -837,7 +844,7 @@ 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}, +\tcode{Ptr} is a class template specialization 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} @@ -1019,6 +1026,10 @@ \end{itemdecl} \begin{itemdescr} +\pnum +\mandates +\tcode{Alignment} is a power of two. + \pnum \expects \tcode{p} points to @@ -1036,6 +1047,31 @@ \rSec2[obj.lifetime]{Explicit lifetime management} +\indexlibraryglobal{start_lifetime}% +\begin{itemdecl} +template + constexpr void start_lifetime(T& r) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{T} is a complete type and +an implicit-lifetime\iref{basic.types} aggregate\iref{dcl.init.aggr}. + +\pnum +\effects +If the object referenced by \tcode{r} +is already within its lifetime\iref{basic.life}, +no effects. +Otherwise, begins the lifetime of the object referenced by \tcode{r}. +\begin{note} +No initialization is performed and no subobject has its lifetime started. +If \tcode{r} denotes a member of a union $U$, +it becomes the active member of $U$\iref{class.union}. +\end{note} +\end{itemdescr} + \indexlibraryglobal{start_lifetime_as}% \begin{itemdecl} template @@ -1710,7 +1746,7 @@ \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 +\tcode{Alloc} if \tcode{Alloc} is a class template specialization 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} @@ -2637,6 +2673,10 @@ \end{itemdecl} \begin{itemdescr} +\pnum +\constraints +\tcode{*declval()} is a well-formed expression. + \pnum \mandates \tcode{reference_converts_from_temporary_v, decltype(\linebreak{}*declval())>} is \tcode{false}. @@ -3433,9 +3473,9 @@ constexpr long use_count() const noexcept; constexpr explicit operator bool() const noexcept; template - constexpr bool owner_before(const shared_ptr& b) const noexcept; + bool owner_before(const shared_ptr& b) const noexcept; template - constexpr bool owner_before(const weak_ptr& b) const noexcept; + bool owner_before(const weak_ptr& b) const noexcept; size_t owner_hash() const noexcept; template constexpr bool owner_equal(const shared_ptr& b) const noexcept; @@ -4041,8 +4081,8 @@ \indexlibrarymember{owner_before}{shared_ptr}% \begin{itemdecl} -template constexpr bool owner_before(const shared_ptr& b) const noexcept; -template constexpr bool owner_before(const weak_ptr& b) const noexcept; +template bool owner_before(const shared_ptr& b) const noexcept; +template bool owner_before(const weak_ptr& b) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -4401,7 +4441,7 @@ 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\}} + // \tcode{shared_ptr} to a \tcode{double[6][2]}, where each \tcode{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} @@ -4758,9 +4798,9 @@ constexpr bool expired() const noexcept; constexpr shared_ptr lock() const noexcept; template - constexpr bool owner_before(const shared_ptr& b) const noexcept; + bool owner_before(const shared_ptr& b) const noexcept; template - constexpr bool owner_before(const weak_ptr& b) const noexcept; + bool owner_before(const weak_ptr& b) const noexcept; size_t owner_hash() const noexcept; template constexpr bool owner_equal(const shared_ptr& b) const noexcept; @@ -4957,8 +4997,8 @@ \indexlibrarymember{owner_before}{weak_ptr}% \begin{itemdecl} -template constexpr bool owner_before(const shared_ptr& b) const noexcept; -template constexpr bool owner_before(const weak_ptr& b) const noexcept; +template bool owner_before(const shared_ptr& b) const noexcept; +template bool owner_before(const weak_ptr& b) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -5032,26 +5072,26 @@ template struct owner_less; template struct owner_less> { - constexpr bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; - constexpr bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; - constexpr bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; + 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> { - constexpr bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; - constexpr bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; - constexpr bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; + 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 - constexpr bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; + bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; template - constexpr bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; + bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; template - constexpr bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; + bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; template - constexpr bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; + bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; using is_transparent = @\unspec@; }; @@ -6531,7 +6571,7 @@ \begin{itemdecl} template constexpr bool operator==(const indirect& lhs, const indirect& rhs) - noexcept(noexcept(*lhs == *rhs)); + noexcept(noexcept(bool(*lhs == *rhs))); \end{itemdecl} \begin{itemdescr} @@ -6570,7 +6610,8 @@ %FIXME: "friend" included on declaration in synopsis but not here. \begin{itemdecl} template - constexpr bool operator==(const indirect& lhs, const U& rhs) noexcept(noexcept(*lhs == rhs)); + constexpr bool operator==(const indirect& lhs, const U& rhs) + noexcept(noexcept(bool(*lhs == rhs))); \end{itemdecl} \begin{itemdescr} @@ -6796,7 +6837,7 @@ using the allocator \exposid{alloc}. \end{itemdescr} -\indexlibraryctor{indirect}% +\indexlibraryctor{polymorphic}% \begin{itemdecl} constexpr explicit polymorphic(allocator_arg_t, const Allocator& a); \end{itemdecl} @@ -6894,8 +6935,9 @@ considering that owned object as an rvalue. Otherwise, if \tcode{\exposid{alloc} != other.\exposid{alloc}} is \tcode{true}, -constructs an object of type \tcode{polymorphic}, -considering the owned object in \tcode{other} as an rvalue, +constructs an owned object of type \tcode{U}, +where \tcode{U} is the type of the owned object in \tcode{other}, +with the owned object in \tcode{other} as an rvalue, using the allocator \exposid{alloc}. \end{itemdescr} @@ -7092,7 +7134,10 @@ \pnum \effects If \tcode{*this} is not valueless, -destroys the owned object using \tcode{allocator_traits::de\-stroy} and +calls \tcode{allocator_traits::destroy(p)}, +where \tcode{p} is a pointer of type \tcode{U*} to +the owned object and +\tcode{U} is the type of the owned object; then the storage is deallocated. \end{itemdescr} @@ -7124,7 +7169,9 @@ \item If \tcode{other} is not valueless, -a new owned object is constructed in \tcode{*this} using +a new owned object of type \tcode{U}, +where \tcode{U} is the type of the owned object in \tcode{other}, +is constructed in \tcode{*this} using \tcode{allocator_traits::construct} with the owned object from \tcode{other} as the argument, using either the allocator in \tcode{*this} or @@ -7190,7 +7237,9 @@ \item Otherwise, -constructs a new owned object with the owned object of +constructs a new owned object of type \tcode{U}, +where \tcode{U} is the type of the owned object in \tcode{other}, +with the owned object of \tcode{other} as the argument as an rvalue, using the allocator in \tcode{*this}. @@ -8011,11 +8060,11 @@ synchronized_pool_resource(const pool_options& opts, memory_resource* upstream); synchronized_pool_resource() - : synchronized_pool_resource(pool_options(), get_default_resource()) {} + : synchronized_pool_resource(pool_options(), get_default_resource()) {} explicit synchronized_pool_resource(memory_resource* upstream) - : synchronized_pool_resource(pool_options(), 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(opts, get_default_resource()) {} synchronized_pool_resource(const synchronized_pool_resource&) = delete; virtual ~synchronized_pool_resource(); @@ -8038,11 +8087,11 @@ unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream); unsynchronized_pool_resource() - : unsynchronized_pool_resource(pool_options(), get_default_resource()) {} + : unsynchronized_pool_resource(pool_options(), get_default_resource()) {} explicit unsynchronized_pool_resource(memory_resource* upstream) - : unsynchronized_pool_resource(pool_options(), 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(opts, get_default_resource()) {} unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete; virtual ~unsynchronized_pool_resource(); diff --git a/source/meta.tex b/source/meta.tex index 76ba9b3dbd..743d89ace5 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -205,22 +205,6 @@ using @\libglobal{true_type}@ = bool_constant; using @\libglobal{false_type}@ = bool_constant; - // \ref{const.wrap.class}, class template \tcode{constant_wrapper} - template - struct @\exposidnc{cw-fixed-value}@; // \expos - - template<@\exposidnc{cw-fixed-value}@ X, class = typename decltype(X)::@\exposid{type}@> - struct constant_wrapper; - - template - concept @\defexposconceptnc{constexpr-param}@ = // \expos - requires { typename constant_wrapper; }; - - struct @\exposidnc{cw-operators}@; // \expos - - template<@\exposid{cw-fixed-value}@ X> - constexpr auto @\libglobal{cw}@ = constant_wrapper{}; - // \ref{meta.unary.cat}, primary type categories template struct is_void; template struct is_null_pointer; @@ -257,8 +241,8 @@ template struct is_abstract; template struct is_final; template struct is_aggregate; - template struct is_consteval_only; + template struct is_structural; template struct is_signed; template struct is_unsigned; template struct is_bounded_array; @@ -511,7 +495,7 @@ template constexpr bool @\libglobal{is_aggregate_v}@ = is_aggregate::value; template - constexpr bool @\libglobal{is_consteval_only_v}@ = is_consteval_only::value; + constexpr bool @\libglobal{is_structural_v}@ = is_structural::value; template constexpr bool @\libglobal{is_signed_v}@ = is_signed::value; template @@ -647,7 +631,8 @@ // \ref{meta.const.eval}, constant evaluation context constexpr bool is_constant_evaluated() noexcept; - consteval bool is_within_lifetime(const auto*) noexcept; + template + consteval bool is_within_lifetime(const T*) noexcept; } \end{codeblock} @@ -679,253 +664,6 @@ are used as base classes to define the interface for various type traits. -\rSec2[const.wrap.class]{Class template \tcode{constant_wrapper}} - -\begin{codeblock} -namespace std { - template - struct @\exposidnc{cw-fixed-value}@ { // \expos - using @\exposidnc{type}@ = T; // \expos - constexpr @\exposidnc{cw-fixed-value}@(@\exposidnc{type}@ v) noexcept : @\exposidnc{data}@(v) {} - T @\exposidnc{data}@; // \expos - }; - - template - struct @\exposidnc{cw-fixed-value}@ { // \expos - using @\exposidnc{type}@ = T[Extent]; // \expos - constexpr @\exposidnc{cw-fixed-value}@(T (&arr)[Extent]) noexcept; - T @\exposidnc{data}@[Extent]; // \expos - }; - - template - @\exposidnc{cw-fixed-value}@(T (&)[Extent]) -> @\exposidnc{cw-fixed-value}@; // \expos - - struct @\exposidnc{cw-operators}@ { // \expos - // unary operators - template<@\exposconcept{constexpr-param}@ T> - friend constexpr auto operator+(T) noexcept -> constant_wrapper<(+T::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ T> - friend constexpr auto operator-(T) noexcept -> constant_wrapper<(-T::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ T> - friend constexpr auto operator~(T) noexcept -> constant_wrapper<(~T::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ T> - friend constexpr auto operator!(T) noexcept -> constant_wrapper<(!T::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ T> - friend constexpr auto operator&(T) noexcept -> constant_wrapper<(&T::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ T> - friend constexpr auto operator*(T) noexcept -> constant_wrapper<(*T::value)> - { return {}; } - - // binary operators - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator+(L, R) noexcept -> constant_wrapper<(L::value + R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator-(L, R) noexcept -> constant_wrapper<(L::value - R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator*(L, R) noexcept -> constant_wrapper<(L::value * R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator/(L, R) noexcept -> constant_wrapper<(L::value / R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator%(L, R) noexcept -> constant_wrapper<(L::value % R::value)> - { return {}; } - - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator<<(L, R) noexcept -> constant_wrapper<(L::value << R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator>>(L, R) noexcept -> constant_wrapper<(L::value >> R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator&(L, R) noexcept -> constant_wrapper<(L::value & R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator|(L, R) noexcept -> constant_wrapper<(L::value | R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator^(L, R) noexcept -> constant_wrapper<(L::value ^ R::value)> - { return {}; } - - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - requires (!is_constructible_v || - !is_constructible_v) - friend constexpr auto operator&&(L, R) noexcept - -> constant_wrapper<(L::value && R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - requires (!is_constructible_v || - !is_constructible_v) - friend constexpr auto operator||(L, R) noexcept - -> constant_wrapper<(L::value || R::value)> - { return {}; } - - // comparisons - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator<=>(L, R) noexcept - -> constant_wrapper<(L::value <=> R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator<(L, R) noexcept -> constant_wrapper<(L::value < R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator<=(L, R) noexcept -> constant_wrapper<(L::value <= R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator==(L, R) noexcept -> constant_wrapper<(L::value == R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator!=(L, R) noexcept -> constant_wrapper<(L::value != R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator>(L, R) noexcept -> constant_wrapper<(L::value > R::value)> - { return {}; } - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator>=(L, R) noexcept -> constant_wrapper<(L::value >= R::value)> - { return {}; } - - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator,(L, R) noexcept = delete; - template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> - friend constexpr auto operator->*(L, R) noexcept -> constant_wrapper*(R::value)> - { return {}; } - - // call and index - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@... Args> - constexpr auto operator()(this T, Args...) noexcept - requires requires { constant_wrapper(); } - { return constant_wrapper{}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@... Args> - constexpr auto operator[](this T, Args...) noexcept - -> constant_wrapper<(T::value[Args::value...])> - { return {}; } - - // pseudo-mutators - template<@\exposconcept{constexpr-param}@ T> - constexpr auto operator++(this T) noexcept - -> constant_wrapper<++Y> { return {}; } - template<@\exposconcept{constexpr-param}@ T> - constexpr auto operator++(this T, int) noexcept - -> constant_wrapper { return {}; } - template<@\exposconcept{constexpr-param}@ T> - constexpr auto operator--(this T) noexcept - -> constant_wrapper<--Y> { return {}; } - template<@\exposconcept{constexpr-param}@ T> - constexpr auto operator--(this T, int) noexcept - -> constant_wrapper { return {}; } - - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator+=(T, R) noexcept - -> constant_wrapper<(T::value += R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator-=(T, R) noexcept - -> constant_wrapper<(T::value -= R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator*=(T, R) noexcept - -> constant_wrapper<(T::value *= R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator/=(T, R) noexcept - -> constant_wrapper<(T::value /= R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator%=(T, R) noexcept - -> constant_wrapper<(T::value %= R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator&=(T, R) noexcept - -> constant_wrapper<(T::value &= R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator|=(T, R) noexcept - -> constant_wrapper<(T::value |= R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator^=(T, R) noexcept - -> constant_wrapper<(T::value ^= R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator<<=(T, R) noexcept - -> constant_wrapper<(T::value <<= R::value)> { return {}; } - template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> - constexpr auto operator>>=(T, R) noexcept - -> constant_wrapper<(T::value >>= R::value)> { return {}; } - }; - - template<@\exposid{cw-fixed-value}@ X, class> - struct @\libglobal{constant_wrapper}@ : @\exposid{cw-operators}@ { - static constexpr const auto & value = X.@\exposid{data}@; - using type = constant_wrapper; - using value_type = decltype(X)::@\exposid{type}@; - - template<@\exposconcept{constexpr-param}@ R> - constexpr auto operator=(R) const noexcept - -> constant_wrapper { return {}; } - - constexpr operator decltype(auto)() const noexcept { return value; } - }; -} -\end{codeblock} - -\pnum -The class template \tcode{constant_wrapper} aids in metaprogramming by ensuring -that the evaluation of expressions comprised entirely of \tcode{constant_wrapper} -are core constant expressions\iref{expr.const}, -regardless of the context in which they appear. -In particular, this enables use of \tcode{constant_wrapper} values -that are passed as arguments to constexpr functions to be used in constant expressions. - -\pnum -\begin{note} -The unnamed second template parameter to \tcode{constant_wrapper} is present -to aid argument-dependent lookup\iref{basic.lookup.argdep} -in finding overloads for which \tcode{constant_wrapper}'s wrapped value is a suitable argument, -but for which the \tcode{constant_wrapper} itself is not. -\end{note} - -\pnum -\begin{example} -\begin{codeblock} - constexpr auto initial_phase(auto quantity_1, auto quantity_2) { - return quantity_1 + quantity_2; - } - - constexpr auto middle_phase(auto tbd) { - return tbd; - } - - void final_phase(auto gathered, auto available) { - if constexpr (gathered == available) - std::cout << "Profit!\n"; - } - - void impeccable_underground_planning() { - auto gathered_quantity = middle_phase(initial_phase(std::cw<42>, std::cw<13>)); - static_assert(gathered_quantity == 55); - auto all_available = std::cw<55>; - final_phase(gathered_quantity, all_available); - } - - void deeply_flawed_underground_planning() { - constexpr auto gathered_quantity = middle_phase(initial_phase(42, 13)); - constexpr auto all_available = 55; - final_phase(gathered_quantity, all_available); // error: \tcode{gathered == available} - // is not a constant expression - } -\end{codeblock} -\end{example} - -\begin{itemdecl} -constexpr @\exposid{cw-fixed-value}@(T (&arr)[Extent]) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initialize elements of \exposid{data} with corresponding elements of \tcode{arr}. -\end{itemdescr} - \rSec2[meta.unary]{Unary type traits} \rSec3[meta.unary.general]{General} @@ -1197,10 +935,10 @@ \tcode{T} is an aggregate type\iref{dcl.init.aggr} & \tcode{T} shall be an array type, a complete type, or \cv~\keyword{void}. \\ \rowsep -\indexlibraryglobal{is_consteval_only}% +\indexlibraryglobal{is_structural}% \tcode{template}\br - \tcode{struct is_consteval_only;} & - \tcode{T} is consteval-only\iref{basic.types.general} & + \tcode{struct is_structural;} & + \tcode{T} is a structural type\iref{temp.param} & \tcode{remove_all_extents_t} shall be a complete type or \cv~\keyword{void}. \\ \rowsep \indexlibrary{\idxcode{is_signed}!class}% @@ -1548,6 +1286,8 @@ the initialization \tcode{T t(\exposidnc{VAL});} is well-formed and binds \tcode{t} to a temporary object whose lifetime is extended\iref{class.temporary}. + The full-expression of the variable initialization is + treated as an unevaluated operand\iref{expr.context}. Access checking is performed as if in a context unrelated to \tcode{T} and \tcode{U}. Only the validity of the immediate context of @@ -1571,6 +1311,8 @@ the initialization \tcode{T t = \exposidnc{VAL};} is well-formed and binds \tcode{t} to a temporary object whose lifetime is extended\iref{class.temporary}. + The full-expression of the variable initialization is + treated as an unevaluated operand\iref{expr.context}. Access checking is performed as if in a context unrelated to \tcode{T} and \tcode{U}. Only the validity of the immediate context of @@ -1639,6 +1381,8 @@ \begin{note} These tokens are never interpreted as a function declaration. \end{note} +The full-expression of the variable initialization is +treated as an unevaluated operand\iref{expr.context}. 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. @@ -1937,7 +1681,8 @@ \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 +shall be satisfied if and only if +the return statement\iref{stmt.return} in the following code would be well-formed, including any implicit conversions to the return type of the function: \begin{codeblock} @@ -1951,9 +1696,11 @@ 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. +in a context unrelated to \tcode{To} and \tcode{From}. +The operand of the \tcode{return} statement +(including initialization of the returned object or reference, if any) +is treated as an unevaluated operand\iref{expr.context}, and +only the validity of its immediate context is considered. \begin{note} The initialization can result in side effects such as the @@ -2844,14 +2591,21 @@ \indexlibraryglobal{is_within_lifetime}% \begin{itemdecl} -consteval bool is_within_lifetime(const auto* p) noexcept; +template + consteval bool is_within_lifetime(const T* p) noexcept; \end{itemdecl} \begin{itemdescr} +\pnum +\mandates +\tcode{static_cast(p)} is well-formed. + \pnum \returns \tcode{true} if \tcode{p} is a pointer to an object that is -within its lifetime\iref{basic.life}; otherwise, \tcode{false}. +within its lifetime\iref{basic.life} and +\tcode{static_cast(p)} is a constant subexpression; +otherwise, \tcode{false}. \pnum \remarks @@ -2923,7 +2677,7 @@ template consteval const ranges::range_value_t* define_static_string(R&& r); template - consteval span> define_static_array(R&& r); + consteval span, @\seebelow@> define_static_array(R&& r); template consteval const remove_cvref_t* define_static_object(T&& r); } @@ -3021,7 +2775,7 @@ consteval bool is_function_parameter(info r); consteval bool is_explicit_object_parameter(info r); consteval bool has_default_argument(info r); - consteval bool has_ellipsis_parameter(info r); + consteval bool is_vararg_function(info r); consteval bool is_template(info r); consteval bool is_function_template(info r); @@ -3068,6 +2822,11 @@ consteval bool has_inaccessible_bases(info r, access_context ctx); consteval bool has_inaccessible_subobjects(info r, access_context ctx); + // \ref{meta.reflection.scope}, scope identification + consteval info current_function(); + consteval info current_class(); + consteval info current_namespace(); + // \ref{meta.reflection.member.queries}, reflection member queries consteval vector members_of(info r, access_context ctx); consteval vector bases_of(info type, access_context ctx); @@ -3089,7 +2848,7 @@ // \ref{meta.reflection.extract}, value extraction template - consteval T extract(info); + consteval T extract(info r); // \ref{meta.reflection.substitute}, reflection substitution template @@ -3113,7 +2872,7 @@ consteval info data_member_spec(info type, data_member_options options); consteval bool is_data_member_spec(info r); template<@\libconcept{reflection_range}@ R = initializer_list> - consteval info define_aggregate(info type_class, R&&); + consteval info define_aggregate(info type_class, R&& mdescrs); // associated with \ref{meta.unary.cat}, primary type categories consteval bool is_void_type(info type); @@ -3151,7 +2910,7 @@ consteval bool is_abstract_type(info type); consteval bool is_final_type(info type); consteval bool is_aggregate_type(info type); - consteval bool is_consteval_only_type(info type); + consteval bool is_structural_type(info type); consteval bool is_signed_type(info type); consteval bool is_unsigned_type(info type); consteval bool is_bounded_array_type(info type); @@ -3271,6 +3030,9 @@ consteval size_t tuple_size(info type); consteval info tuple_element(size_t index, info type); + consteval bool is_applicable_type(info fn, info tuple); + consteval bool is_nothrow_applicable_type(info fn, info tuple); + consteval info apply_result(info fn, info tuple); consteval size_t variant_size(info type); consteval info variant_alternative(size_t index, info type); @@ -3285,6 +3047,13 @@ specified in this header is a designated addressable function\iref{namespace.std}. +\pnum +When a function or function template specialization $F$ specified in this header +throws a \tcode{meta::exception} $E$, +\tcode{$E$.from()} is a reflection representing $F$ and +\tcode{$E$.where()} is a \tcode{source_location} +representing from where the call to $F$ originated. + \pnum The behavior of any function specified in namespace \tcode{std::meta} is \impldef{behavior of any function in \tcode{std::meta} @@ -3318,8 +3087,15 @@ \pnum Any function in namespace \tcode{std::meta} whose return type is \tcode{string_view} or \tcode{u8string_view} -returns an object \exposid{V} such that -\tcode{\exposid{V}.data()[\exposid{V}.size()]} equals \tcode{'\textbackslash 0'}. +returns an object \tcode{V} such that +\tcode{V.data()[V.size()]} equals \tcode{'\textbackslash 0'}. +Each element of the range +$\tcode{V.data()} + \crange{0}{\tcode{V.size()}}$ +is a potentially non-unique object with static storage duration that +is usable in constant expressions\iref{intro.object, expr.const}; +a pointer to such an element is not suitable for use as +a template argument for a constant template parameter of +pointer type\iref{temp.arg.nontype}. \begin{example} \begin{codeblock} struct C { }; @@ -3352,7 +3128,7 @@ \returns \begin{itemize} \item - If \tcode{p} points to an unspecified object\iref{expr.const}, + If \tcode{p} points to an unspecified object\iref{expr.const.core}, \tcode{false}. \item Otherwise, if \tcode{p} points to a subobject @@ -3416,30 +3192,44 @@ \begin{itemdescr} \pnum -Let \tcode{T} be \tcode{ranges::range_value_t} and -$\tcode{\placeholder{e}}_i$ be \tcode{static_cast(*$\tcode{\placeholder{it}}_i$)}, -where $\tcode{\placeholder{it}}_i$ is an iterator to the $i^\text{th}$ element of \tcode{r}. +Let \tcode{U} be \tcode{ranges::range_value_t} and +\tcode{T} be \tcode{remove_all_extents_t}. \pnum \mandates -\tcode{T} is a structural type\iref{temp.param}, -\tcode{is_constructible_v>} is \tcode{true}, and -\tcode{T} satisfies \libconcept{copy_constructible}. +\begin{itemize} +\item \tcode{T} is a structural type\iref{temp.param}, +\item \tcode{T} satisfies \libconcept{copy_constructible}, and +\item +if \tcode{U} is not an array type, then +\tcode{is_constructible_v>} is \tcode{true}. +\end{itemize} \pnum Let $V$ be the pack of values of type \tcode{info} of the same size as \tcode{r}, where the $i^\text{th}$ element is -\tcode{reflect_constant($\tcode{\placeholder{e}}_i$)}. +\begin{itemize} +\item +\tcode{reflect_constant_array(*$\tcode{\placeholder{it}}_i$)} +if \tcode{U} is an array type, +\item +\tcode{reflect_constant(static_cast(*$\tcode{\placeholder{it}}_i$))} +otherwise, +\end{itemize} +and $\tcode{\placeholder{it}}_i$ is an iterator to +the $i^\text{th}$ element of \tcode{r}. \pnum Let $P$ be \begin{itemize} \item the template parameter object\iref{temp.param} - of type \tcode{const T[sizeof...(\brk{}$V$)]} - initialized with\linebreak - \tcode{\{[:$V$:]...\}} if \tcode{sizeof...($V$) > 0} is \tcode{true}, otherwise + of type \tcode{const T[sizeof...($V$)]}, + such that \tcode{$P$[$I$]} is template-argument-equivalent\iref{temp.type} + to the object represented by \tcode{$V$...[$I$]} + for all $I$ in the range \range{0}{sizeof...($V$)} + if \tcode{sizeof...($V$) > 0} is \tcode{true}, otherwise \item the template parameter object of type \tcode{const array} initialized with \tcode{\{\}}. @@ -3451,14 +3241,25 @@ \pnum \throws -Any exception thrown by the evaluation of any $\tcode{\placeholder{e}}_i$, or +Any of +\begin{itemize} +\item +an exception thrown by any operation +on \tcode{r} or +on iterators and sentinels referring to \tcode{r}, +\item +an exception thrown +by the evaluation of any argument of \tcode{reflect_constant} or +by any evaluation of \tcode{reflect_constant_array}, or +\item \tcode{meta::exception} -if evaluation of any \tcode{reflect_constant($\tcode{\placeholder{e}}_i$)} +if any invocation of \tcode{reflect_constant} would exit via an exception. +\end{itemize} \pnum \begin{note} -$P$ is a potentially non-unique object\iref{intro.object}. +When \tcode{r} is not empty, $P$ is a potentially non-unique object\iref{intro.object}. \end{note} \end{itemdescr} @@ -3480,7 +3281,7 @@ \indexlibraryglobal{define_static_array}% \begin{itemdecl} template - consteval span> define_static_array(R&& r); + consteval span, @\seebelow@> define_static_array(R&& r); \end{itemdecl} \begin{itemdescr} @@ -3491,11 +3292,19 @@ using T = ranges::range_value_t; meta::info array = meta::reflect_constant_array(r); if (meta::is_array_type(meta::type_of(array))) { - return span(meta::extract(array), meta::extent(meta::type_of(array))); + return span(meta::extract(array), + meta::extent(meta::type_of(array))); } else { - return span(); + return span(static_cast(nullptr), 0); } \end{codeblock} + +\pnum +\remarks +If \tcode{ranges::size(r)} is a constant expression, +the second template argument of the returned \tcode{span} type +is \tcode{static_cast(ranges::size(r))}; +otherwise, it is \tcode{dynamic_extent}. \end{itemdescr} \indexlibraryglobal{define_static_object}% @@ -3510,8 +3319,12 @@ Equivalent to: \begin{codeblock} using U = remove_cvref_t; -if constexpr (meta::is_class_type(^^U)) { - return addressof(meta::extract(meta::reflect_constant(std::forward(t)))); +if constexpr (meta::is_class_type(^^U) || meta::is_union_type(^^U)) { + return addressof(meta::extract( + meta::reflect_constant(std::forward(t)))); +} else if constexpr (meta::is_array_type(^^U)) { + return addressof(meta::extract( + meta::reflect_constant_array(std::forward(t)))); } else { return define_static_array(span(addressof(t), 1)).data(); } @@ -3815,7 +3628,7 @@ Otherwise, if \tcode{r} represents the parameter $P$ of a function $F$, then let $S$ be the set of declarations, ignoring any explicit instantiations, - that precede some point in the evaluation context + that are reachable from a point in the evaluation context and that declare either $F$ or a templated function of which $F$ is a specialization; \tcode{true} if @@ -3867,10 +3680,12 @@ Otherwise, if \tcode{r} represents a direct base class relationship, then \tcode{has_identifier(type_of(r))}. \item - Otherwise, \tcode{r} represents a data member description - $(T, N, A, W, \mathit{NUA})$\iref{class.mem.general}; + Otherwise, if \tcode{r} represents a data member description + $(T, N, A, W, \mathit{NUA}, \mathit{ANN})$\iref{class.mem.general}; \tcode{true} if $N$ is not $\bot$. Otherwise, \tcode{false}. +\item + Otherwise, \tcode{false}. \end{itemize} \end{itemdescr} @@ -3901,7 +3716,7 @@ Otherwise, if \tcode{r} represents the parameter $P$ of a function $F$, then let $S$ be the set of declarations, ignoring any explicit instantiations, - that precede some point in the evaluation context + that are reachable from a point in the evaluation context and that declare either $F$ or a templated function of which $F$ is a specialization; the name that was introduced by a declaration in $S$ @@ -3915,7 +3730,7 @@ respectively. \item Otherwise, \tcode{r} represents a data member description - $(T, N, A, W, NUA)$\iref{class.mem.general}; + $(T, N, A, W, \mathit{NUA}, \mathit{ANN})$\iref{class.mem.general}; a \tcode{string_view} or \tcode{u8string_view}, respectively, containing the identifier $N$. \end{itemize} @@ -4030,7 +3845,7 @@ \begin{itemize} \item If $E$ is defined by a declaration $D$ - that precedes a point $P$ in the evaluation context + that is reachable from a point $P$ in the evaluation context and $P$ does not occur within an \grammarterm{enum-specifier} of $D$, then a reflection of $E$. \item @@ -4043,7 +3858,7 @@ a direct base class relationship $(D, B)$, then a reflection of $B$. \item - Otherwise, for a data member description $(T, N, A, W, \mathit{NUA})$\iref{class.mem.general}, + Otherwise, for a data member description $(T, N, A, W, \mathit{NUA}, \mathit{ANN})$\iref{class.mem.general}, a reflection of the type $T$. \end{itemize} @@ -4085,7 +3900,7 @@ and if that variable is a reference $R$, then either \begin{itemize} \item - $R$ is usable in constant expressions\iref{expr.const}, or + $R$ is usable in constant expressions\iref{expr.const.init}, or \item the lifetime of $R$ began within the core constant expression currently under evaluation. @@ -4315,7 +4130,7 @@ \returns \tcode{true} if \tcode{r} represents a bit-field, or if \tcode{r} represents a data member description -$(T, N, A, W, \mathit{NUA})$\iref{class.mem.general} +$(T, N, A, W, \mathit{NUA},\brk{} \mathit{ANN})$\iref{class.mem.general} for which $W$ is not $\bot$. Otherwise, \tcode{false}. \end{itemdescr} @@ -4348,7 +4163,7 @@ \pnum \returns -\tcode{true} if \tcode{T} represents a const or volatile type, respectively, +\tcode{true} if $T$ represents a const or volatile type, respectively, or a const- or volatile-qualified function type, respectively. Otherwise, \tcode{false}. \end{itemdescr} @@ -4662,29 +4477,29 @@ \item If $F$ is a specialization of a templated function $T$, then \tcode{true} if there exists a declaration $D$ of $T$ - that precedes some point in the evaluation context + that is reachable from a point in the evaluation context and $D$ specifies a default argument for the parameter of $T$ corresponding to $P$. Otherwise, \tcode{false}. \item Otherwise, if there exists a declaration $D$ of $F$ - that precedes some point in the evaluation context + that is reachable from a point in the evaluation context and $D$ specifies a default argument for $P$, then \tcode{true}. \end{itemize} Otherwise, \tcode{false}. \end{itemdescr} -\indexlibraryglobal{has_ellipsis_parameter}% +\indexlibraryglobal{is_vararg_function}% \begin{itemdecl} -consteval bool has_ellipsis_parameter(info r); +consteval bool is_vararg_function(info r); \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true} if \tcode{r} represents a function or function type -that has an ellipsis in its parameter-type-list\iref{dcl.fct}. +that is a vararg function\iref{dcl.fct}. Otherwise, \tcode{false}. \end{itemdescr} @@ -5122,60 +4937,16 @@ or \tcode{r} represents a function type. \end{itemdescr} -\rSec2[meta.reflection.access.context]{Access control context} +\rSec2[meta.reflection.scope]{Scope identification} \pnum -The class \tcode{access_context} -represents a namespace, class, or function -from which queries pertaining to access rules may be performed, -as well as the designating class\iref{class.access.base}, if any. +The functions in this subclause retrieve information +about where in the program they are invoked. -\indexlibraryglobal{access_context}% \pnum -An \tcode{access_context} has an associated scope and designating class. - -\indexlibraryglobal{access_context}% -\begin{codeblock} -namespace std::meta { - struct access_context { - access_context() = delete; - - consteval info scope() const; - consteval info designating_class() const; - - static consteval access_context current() noexcept; - static consteval access_context unprivileged() noexcept; - static consteval access_context unchecked() noexcept; - consteval access_context via(info cls) const; - }; -} -\end{codeblock} - -\pnum -The type \tcode{access_context} is a structural, consteval-only, non-aggregate type. -Two values \tcode{ac1} and \tcode{ac2} of type \tcode{access_context} -are template-argument-equivalent\iref{temp.type} -if \tcode{ac1.scope()} and \tcode{ac2.scope()} are template-argument-equivalent -and \tcode{ac1.designating_class()} and \tcode{ac2.designating_class()} -are template-argument-equivalent. - -\begin{itemdecl} -consteval info @\libmember{scope}{access_context}@() const; -consteval info @\libmember{designating_class}{access_context}@() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The \tcode{access_context}'s associated scope -and designating class, respectively. -\end{itemdescr} +None of the functions in this subclause +is an addressable function\iref{namespace.std}. -\begin{itemdecl} -static consteval access_context @\libmember{current}{access_context}@() noexcept; -\end{itemdecl} - -\begin{itemdescr} \pnum Given a program point $P$, let \tcode{\exposid{eval-point}($P$)} be the following program point: @@ -5261,14 +5032,153 @@ where $S'$ is the parent scope of $S$. \end{itemize} +\pnum +Let \tcode{\exposid{CURRENT-SCOPE}($P$)} for a point $P$ be +a reflection representing the function, class, or namespace +whose corresponding +function parameter scope, +class scope, or +namespace scope, respectively, +is \tcode{\exposid{ctx-scope}($S$)}, +where $S$ is the immediate scope of \tcode{\exposid{eval-point}($P$)}. + +\indexlibraryglobal{current_function}% +\begin{itemdecl} +consteval info current_function(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +An invocation of \tcode{current_function} that appears at a program point $P$ +is value-dependent\iref{temp.dep.constexpr} +if \tcode{\exposid{eval-point}($P$)} +is enclosed by a scope corresponding to a templated entity. + +\pnum +Let $S$ be \tcode{\exposid{CURRENT-SCOPE}($P$)}, +where $P$ is the point at which the invocation of +\tcode{current_function} lexically appears. + +\pnum +\returns +$S$. + +\pnum +\throws +\tcode{meta::exception} unless $S$ represents a function. +\end{itemdescr} + +\indexlibraryglobal{current_class}% +\begin{itemdecl} +consteval info current_class(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +An invocation of \tcode{current_class} that appears at a program point $P$ +is value-dependent\iref{temp.dep.constexpr} +if \tcode{\exposid{eval-point}($P$)} +is enclosed by a scope corresponding to a templated entity. + +\pnum +Let $S$ be \tcode{\exposid{CURRENT-SCOPE}($P$)} +where $P$ is the point at which the invocation of +\tcode{current_class} lexically appears. + +\pnum +\returns +$S$ if $S$ represents a class. +Otherwise, \tcode{parent_of($S$)}. + +\pnum +\throws +\tcode{meta::exception} unless $S$ represents +either a class or a member function. +\end{itemdescr} + +\indexlibraryglobal{current_namespace}% +\begin{itemdecl} +consteval info current_namespace(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +An invocation of \tcode{current_namespace} that appears at a program point $P$ +is value-dependent\iref{temp.dep.constexpr} +if \tcode{\exposid{eval-point}($P$)} +is enclosed by a scope corresponding to a templated entity. + +\pnum +Let $S$ be \tcode{\exposid{CURRENT-SCOPE}($P$)} +where $P$ is the point at which the invocation of +\tcode{current_namespace} lexically appears. + +\pnum +\returns +$S$ if $S$ represents a namespace. +Otherwise, a reflection representing the nearest enclosing namespace +of the entity represented by $S$. +\end{itemdescr} + +\rSec2[meta.reflection.access.context]{Access control context} + +\pnum +The class \tcode{access_context} +represents a namespace, class, or function +from which queries pertaining to access rules may be performed, +as well as the designating class\iref{class.access.base}, if any. + +\indexlibraryglobal{access_context}% +\pnum +An \tcode{access_context} has an associated scope and designating class. + +\indexlibraryglobal{access_context}% +\begin{codeblock} +namespace std::meta { + struct access_context { + access_context() = delete; + + consteval info scope() const; + consteval info designating_class() const; + + static consteval access_context current() noexcept; + static consteval access_context unprivileged() noexcept; + static consteval access_context unchecked() noexcept; + consteval access_context via(info cls) const; + }; +} +\end{codeblock} + +\pnum +The type \tcode{access_context} is a structural, consteval-only, non-aggregate type. +Two values \tcode{ac1} and \tcode{ac2} of type \tcode{access_context} +are template-argument-equivalent\iref{temp.type} +if \tcode{ac1.scope()} and \tcode{ac2.scope()} are template-argument-equivalent +and \tcode{ac1.designating_class()} and \tcode{ac2.designating_class()} +are template-argument-equivalent. + +\begin{itemdecl} +consteval info @\libmember{scope}{access_context}@() const; +consteval info @\libmember{designating_class}{access_context}@() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The \tcode{access_context}'s associated scope +and designating class, respectively. +\end{itemdescr} + +\begin{itemdecl} +static consteval access_context @\libmember{current}{access_context}@() noexcept; +\end{itemdecl} + +\begin{itemdescr} \pnum \returns An \tcode{access_context} whose designating class is the null reflection -and whose scope represents the function, class, or namespace -whose corresponding function parameter scope, class scope, or namespace scope, respectively, -is \tcode{\exposid{ctx-scope}($S$)}, -where $S$ is the immediate scope of \tcode{\exposid{eval-point}($P$)} -and $P$ is the point at which the invocation of \tcode{current} lexically appears. +and whose scope is \tcode{\exposid{CURRENT-SCOPE}($P$)}, +where $P$ is the point at which the invocation of \tcode{current} lexically appears. \pnum \remarks @@ -5831,7 +5741,7 @@ If \begin{itemize} \item \tcode{r} represents a non-static data member of type $T$ or -a data member description $(T, N, A, W, \mathit{NUA})$ or +a data member description $(T, N, A, W, \mathit{NUA},\brk{} \mathit{ANN})$ or \item \tcode{dealias(r)} represents a type $T$, \end{itemize} then \tcode{sizeof($T$)} if $T$ is not a reference type @@ -5859,7 +5769,7 @@ variable of non-reference type, non-static data member that is not a bit-field, direct base class relationship, or -data member description $(T, N, A, W, \mathit{NUA})$\iref{class.mem.general} +data member description $(T, N, A, W, \mathit{NUA}, \mathit{ANN})$\iref{class.mem.general} where $W$ is $\bot$. \item If \tcode{dealias(r)} represents a type, @@ -5892,7 +5802,7 @@ corresponding to $M$ of a complete object of type $C$. \item Otherwise, \tcode{r} represents a data member description - $(T, N, A, W, \mathit{NUA})$\iref{class.mem.general}. + $(T, N, A, W, \mathit{NUA}, \mathit{ANN})$\iref{class.mem.general}. If $A$ is not $\bot$, then the value $A$. Otherwise, \tcode{alignment_of(\reflexpr{$T$})}. @@ -5911,7 +5821,7 @@ non-static data member that is not a bit-field, direct base class relationship, or data member description -$(T, N, A, W, \mathit{NUA})$\iref{class.mem.general} +$(T, N, A, W, \mathit{NUA}, \mathit{ANN})$\iref{class.mem.general} where $W$ is $\bot$. \item If \tcode{dealias(r)} represents a type, @@ -5936,7 +5846,7 @@ then $W$. \item Otherwise, if \tcode{r} represents a data member description - $(T, N, A, W, \mathit{NUA})$\iref{class.mem.general} + $(T, N, A, W, \mathit{NUA}, \mathit{ANN})$\iref{class.mem.general} and $W$ is not $\bot$, then $W$. \item @@ -5973,20 +5883,33 @@ \begin{itemdescr} \pnum -Let $E$ be -\begin{itemize} -\item - the corresponding \grammarterm{base-specifier} - if \tcode{item} represents a direct base class relationship, -\item - otherwise, the entity represented by \tcode{item}. -\end{itemize} +For a function $F$, +let $S(F)$ be the set of declarations, +ignoring any explicit instantiations, +that declare either $F$ or +a templated function of which $F$ is a specialization. \pnum \returns A \tcode{vector} containing all of the reflections $R$ -representing each annotation applying to each declaration of $E$ that precedes either -some point in the evaluation context\iref{expr.const} or +representing each annotation applying to: +\begin{itemize} +\item + if \tcode{item} represents a function parameter $P$ of a function $F$, + then the declaration of $P$ in each declaration of $F$ in $S(F)$, +\item + otherwise, if \tcode{item} represents a function $F$, + then each declaration of $F$ in $S(F)$, +\item + otherwise, if \tcode{item} represents + a direct base class relationship $(D, B)$, + then the corresponding \grammarterm{base-specifier} + in the definition of $D$, +\item + otherwise, each declaration of the entity represented by \tcode{item}, +\end{itemize} +such that each specified declaration is reachable from either +some point in the evaluation context\iref{expr.const.reflect} or a point immediately following the \grammarterm{class-specifier} of the outermost class for which such a point is in a complete-class context. For any two reflections $R_1$ and $R_2$ in the returned \tcode{vector}, @@ -6007,6 +5930,7 @@ type alias, variable, function, +function parameter, namespace, enumerator, direct base class relationship, or @@ -6483,6 +6407,7 @@ optional alignment; optional bit_width; bool no_unique_address = false; + vector annotations; }; } \end{codeblock} @@ -6543,7 +6468,7 @@ \pnum \returns A reflection of a data member description -$(T, N, A, W, \mathit{NUA})$\iref{class.mem.general} where +$(T, N, A, W, \mathit{NUA}, \mathit{ANN})$\iref{class.mem.general} where \begin{itemize} \item $T$ is the type represented by \tcode{dealias(type)}, @@ -6555,9 +6480,12 @@ or $\bot$ if \tcode{options.alignment} does not contain a value, \item $W$ is either the value held by \tcode{options.bit_width} - or $\bot$ if \tcode{options.bit_width} does not contain a value, and + or $\bot$ if \tcode{options.bit_width} does not contain a value, +\item + $\mathit{NUA}$ is the value held by \tcode{options.no_unique_address}, and \item - $\mathit{NUA}$ is the value held by \tcode{options.no_unique_address}. + $\mathit{ANN}$ is the sequence of values \tcode{constant_of(r)} + for each \tcode{r} in \tcode{options.annotations}. \end{itemize} \begin{note} The returned reflection value is primarily useful @@ -6596,7 +6524,8 @@ \end{note} \item if \tcode{options.name} does not contain a value, - then \tcode{options.bit_width} contains a value; + then \tcode{options.bit_width} contains a value and + \tcode{options.annotations} is empty; \item if \tcode{options.bit_width} contains a value $V$, then \begin{itemize} @@ -6611,11 +6540,19 @@ \item if $V$ equals \tcode{0}, then \tcode{options.name} does not contain a value; and + \item + if \tcode{options.name} does not contain a value, then + \tcode{is_const(type) || is_volatile(type)} is \tcode{false}; and \end{itemize} \item if \tcode{options.alignment} contains a value, it is an alignment value\iref{basic.align} - not less than \tcode{alignment_of(type)}. + not less than \tcode{alignment_of(type)}; and + \item + for every reflection \tcode{r} in \tcode{options.annotations}, + \tcode{\exposid{has-type}(r)} is \tcode{true}, + \tcode{type_of(r)} represents a non-array object type, and + evaluation of \tcode{constant_of(r)} does not exit via an exception. \end{itemize} \end{itemdescr} @@ -6642,7 +6579,7 @@ Let $C$ be the type represented by \tcode{class_type} and $r_K$ be the $K^\text{th}$ reflection value in \tcode{mdescrs}. For every $r_K$ in \tcode{mdescrs}, -let $(T_K, N_K, A_K, W_K, \mathit{NUA}_K)$ be +let $(T_K, N_K, A_K, W_K, \mathit{NUA}_K, \mathit{ANN}_K)$ be the corresponding data member description represented by $r_K$. \pnum @@ -6679,7 +6616,7 @@ \pnum \effects -Produces an injected declaration $D$\iref{expr.const} +Produces an injected declaration $D$\iref{expr.const.reflect} that defines $C$ and has properties as follows: \begin{itemize} \item @@ -6690,7 +6627,7 @@ follows immediately after the core constant expression currently under evaluation. \item - The characteristic sequence of $D$\iref{expr.const} + The characteristic sequence of $D$\iref{expr.const.reflect} is the sequence of reflection values $r_K$. \item If $C$ is a specialization of a templated class $T$, @@ -6721,6 +6658,10 @@ If $A_K$ is not $\bot$, $M_K$ has the \grammarterm{alignment-specifier} \tcode{alignas($A_K$)}. Otherwise, $M_K$ has no \grammarterm{alignment-specifier}. + \item + For every reflection \tcode{r} in $\mathit{ANN}_K$, + $M_K$ has an annotation + whose underlying constant\iref{dcl.attr.annotation} is \tcode{r}. \end{itemize} \item For every $r_L$ in \tcode{mdescrs} such that $K < L$, @@ -6801,7 +6742,7 @@ consteval bool @\libglobal{is_abstract_type}@(info type); consteval bool @\libglobal{is_final_type}@(info type); consteval bool @\libglobal{is_aggregate_type}@(info type); -consteval bool @\libglobal{is_consteval_only_type}@(info type); +consteval bool @\libglobal{is_structural_type}@(info type); consteval bool @\libglobal{is_signed_type}@(info type); consteval bool @\libglobal{is_unsigned_type}@(info type); consteval bool @\libglobal{is_bounded_array_type}@(info type); diff --git a/source/modules.tex b/source/modules.tex index 551e1ecc62..9ecef29d77 100644 --- a/source/modules.tex +++ b/source/modules.tex @@ -39,7 +39,7 @@ consisting of \tcode{std} followed by zero or more \grammarterm{digit}{s} or containing a reserved identifier\iref{lex.name} are reserved and shall not be specified in a \grammarterm{module-declaration}; -no diagnostic is required. +no diagnostic is required\ifndrdef{module.unit.reserved.identifiers}. If any \grammarterm{identifier} in a reserved \grammarterm{module-name} is a reserved identifier, the module name is reserved for use by \Cpp{} implementations; @@ -54,7 +54,7 @@ A named module shall contain exactly one module interface unit with no \grammarterm{module-partition}, known as the \defn{primary module interface unit} of the module; -no diagnostic is required. +no diagnostic is required\ifndrdef{module.unit.named.module.no.partition}. \pnum A \defn{module partition} is @@ -66,7 +66,8 @@ that are module interface units shall be directly or indirectly exported by the primary module interface unit\iref{module.import}. -No diagnostic is required for a violation of these rules. +No diagnostic is required +for a violation of these rules\ifndrdef{module.unit.unexported.module.partition}. \begin{note} Module partitions can be imported only by other module units in the same module. @@ -254,7 +255,7 @@ namespace { export int a2; // error: export of name with internal linkage } -export static int b; // error: b explicitly declared static +export static int b; // error: \tcode{b} explicitly declared static export int f(); // OK export namespace N { } // OK export using namespace N; // OK @@ -810,7 +811,7 @@ in a primary module interface unit\iref{module.unit}. A module unit with a \grammarterm{private-module-fragment} shall be the only module unit of its module; -no diagnostic is required. +no diagnostic is required\ifndrdef{module.private.frag.other.module.units}. \pnum \begin{note} @@ -921,7 +922,7 @@ that resulted from the evaluation of an expression as a core constant expression, the instantiation context contains -each point in the evaluation context\iref{expr.const}. +each point in the evaluation context\iref{expr.const.reflect}. \begin{note} Implicit instantiations can result from invocations of library functions\iref{meta.reflection}. @@ -1064,7 +1065,7 @@ The value of \tcode{n} is 1. The member \tcode{Incomplete::x} members-of-precedes\iref{meta.reflection.member.queries} -the synthesized point P associated with the injected declaration +the synthesized point $P$ associated with the injected declaration produced by the call to \tcode{define_aggregate}. \end{example} diff --git a/source/numerics.tex b/source/numerics.tex index b2d2e2ca07..36f4bc1b86 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -51,7 +51,7 @@ These include arithmetic types, pointers, the library class \tcode{complex}, -and instantiations of +and specializations of \tcode{valarray} for value types. \end{footnote} @@ -1558,62 +1558,60 @@ \pnum Throughout \ref{rand}, -the effect of instantiating a template: +where the template parameters are not constrained, +the names of template parameters are used to express type requirements +on an instantiated template $T$: \begin{itemize} \item - that has a template type parameter + If \tcode{T} has a template type parameter named + \tcode{Sseq}, \tcode{URBG}, \tcode{Engine}, + \tcode{RealType}, \tcode{IntType}, or \tcode{UIntType}, + the program is ill-formed if the corresponding template argument is cv-qualified. + \item + A template argument corresponding to a template parameter named \tcode{Sseq} - is undefined unless the corresponding template argument - is cv-unqualified and - meets the requirements + shall meet the requirements of seed sequence\iref{rand.req.seedseq}. \item - that has a template type parameter + A template argument corresponding to a template parameter named \tcode{URBG} - is undefined unless the corresponding template argument - is cv-unqualified and - meets the requirements + shall meet the requirements of uniform random bit generator\iref{rand.req.urng}. \item - that has a template type parameter + A template argument corresponding to a template parameter named \tcode{Engine} - is undefined unless the corresponding template argument - is cv-unqualified and - meets the requirements + shall meet the requirements of random number engine\iref{rand.req.eng}. \item - that has a template type parameter + If a template argument corresponding to a template parameter named \tcode{RealType} - is undefined unless the corresponding template argument - is cv-unqualified and - is one of - \tcode{float}, \tcode{double}, or \tcode{long double}. + is neither + a standard floating-point type\iref{basic.fundamental} nor + a member of an + \impldef{subset of extended floating-point types that can be used as \tcode{RealType} + template arguments} subset of extended floating-point types, + the program is ill-formed. \item - that has a template type parameter + If a template argument corresponding to a template parameter named \tcode{IntType} - is undefined unless the corresponding template argument - is cv-unqualified and - is one of - \tcode{short}, - \tcode{int}, - \tcode{long}, - \tcode{long long}, - \tcode{unsigned short}, - \tcode{unsigned int}, - \tcode{unsigned long}, - or - \tcode{unsigned long long}. + is neither + a standard signed nor a standard unsigned integer type\iref{basic.fundamental}, nor + an extended integer type whose width is + greater or equal to that of \tcode{char} and + less than or equal to that of \tcode{long long}, nor + a member of an + \impldef{subset of integer types that can be used as \tcode{IntType} template arguments} + subset of integer types, the program is ill-formed. \item - that has a template type parameter + If a template argument corresponding to a template parameter named \tcode{UIntType} - is undefined unless the corresponding template argument - is cv-unqualified and - is one of - \tcode{unsigned short}, - \tcode{unsigned int}, - \tcode{unsigned long}, - or - \tcode{unsigned long long}. + is neither + a standard or extended unsigned integer type whose width is + greater or equal to that of \tcode{short} and + less than or equal to that of \tcode{long long}, nor + a member of an + \impldef{subset of unsigned integer types that can be used as \tcode{UIntType} template arguments} + subset of unsigned integer types, the program is ill-formed. \end{itemize} \pnum @@ -4452,7 +4450,7 @@ \pnum \begin{note} If the values $g_i$ produced by \tcode{g} are uniformly distributed, -the instantiation's results are distributed as uniformly as possible. +\tcode{generate_canonical}'s results are distributed as uniformly as possible. Obtaining a value in this way can be a useful step in the process of transforming @@ -8508,7 +8506,7 @@ const slice_array& operator=(const slice_array&) const; void operator=(const T&) const; - slice_array() = delete; // as implied by declaring copy constructor above + slice_array() = delete; }; } \end{codeblock} @@ -8790,7 +8788,7 @@ const gslice_array& operator=(const gslice_array&) const; void operator=(const T&) const; - gslice_array() = delete; // as implied by declaring copy constructor above + gslice_array() = delete; }; } \end{codeblock} @@ -8918,7 +8916,7 @@ const mask_array& operator=(const mask_array&) const; void operator=(const T&) const; - mask_array() = delete; // as implied by declaring copy constructor above + mask_array() = delete; }; } \end{codeblock} @@ -9035,7 +9033,7 @@ const indirect_array& operator=(const indirect_array&) const; void operator=(const T&) const; - indirect_array() = delete; // as implied by declaring copy constructor above + indirect_array() = delete; }; } \end{codeblock} @@ -9908,7 +9906,7 @@ \indexlibrary{\idxcode{hypot}!3-argument form}% \begin{itemdecl} -constexpr @\placeholder{floating-point-type}@ hypot(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y, +constexpr @\placeholdernc{floating-point-type}@ hypot(@\placeholder{floating-point-type}@ x, @\placeholder{floating-point-type}@ y, @\placeholder{floating-point-type}@ z); \end{itemdecl} @@ -9922,7 +9920,7 @@ \indexlibraryglobal{lerp}% \begin{itemdecl} -constexpr @\placeholder{floating-point-type}@ lerp(@\placeholder{floating-point-type}@ a, @\placeholder{floating-point-type}@ b, +constexpr @\placeholdernc{floating-point-type}@ lerp(@\placeholder{floating-point-type}@ a, @\placeholder{floating-point-type}@ b, @\placeholder{floating-point-type}@ t) noexcept; \end{itemdecl} \begin{itemdescr} @@ -10964,7 +10962,7 @@ struct explicit_diagonal_t; inline constexpr explicit_diagonal_t explicit_diagonal; - // \ref{linalg.layout.packed}, class template layout_blas_packed + // \ref{linalg.layout.packed}, class template \tcode{layout_blas_packed} template class layout_blas_packed; @@ -12682,10 +12680,11 @@ class @\libglobal{scaled_accessor}@ { public: using @\libmember{element_type}{scaled_accessor}@ = - const decltype(declval() * declval()); + const decltype(declval() * + declval()); using @\libmember{reference}{scaled_accessor}@ = remove_const_t; using @\libmember{data_handle_type}{scaled_accessor}@ = NestedAccessor::data_handle_type; - using @\libmember{offset_policy}{scaled_accessor}@ = scaled_accessor; + using @\libmember{offset_policy}{scaled_accessor}@ = scaled_accessor; constexpr scaled_accessor() = default; template @@ -12771,7 +12770,7 @@ \pnum \returns \begin{codeblock} -scaling_factor() * NestedAccessor::element_type(@\exposid{nested-accessor}@.access(p, i)) +scaling_factor() * typename NestedAccessor::element_type(@\exposid{nested-accessor}@.access(p, i)) \end{codeblock} \end{itemdescr} @@ -12783,7 +12782,7 @@ \begin{itemdescr} \pnum \returns -\tcode{\exposid{nested-accessor}.offset(p, i)} +\tcode{\exposid{nested-accessor}.offset(p, i)}. \end{itemdescr} \rSec3[linalg.scaled.scaled]{Function template \tcode{scaled}} @@ -12854,10 +12853,10 @@ class @\libglobal{conjugated_accessor}@ { public: using @\libmember{element_type}{conjugated_accessor}@ = - const decltype(@\exposid{conj-if-needed}@(declval())); + const decltype(@\exposid{conj-if-needed}@(declval())); using @\libmember{reference}{conjugated_accessor}@ = remove_const_t; using @\libmember{data_handle_type}{conjugated_accessor}@ = NestedAccessor::data_handle_type; - using @\libmember{offset_policy}{conjugated_accessor}@ = conjugated_accessor; + using @\libmember{offset_policy}{conjugated_accessor}@ = conjugated_accessor; constexpr conjugated_accessor() = default; constexpr conjugated_accessor(const NestedAccessor& acc); @@ -12930,7 +12929,9 @@ \begin{itemdescr} \pnum \returns -\tcode{\exposid{conj-if-needed}(NestedAccessor::element_type(\exposid{nested-accessor_}.access(p, i)))} +\begin{codeblock} +@\exposid{conj-if-needed}@(typename NestedAccessor::element_type(@\exposid{nested-accessor_}@.access(p, i))) +\end{codeblock} \end{itemdescr} \indexlibrarymember{conjugated_accessor}{offset}% @@ -12941,7 +12942,7 @@ \begin{itemdescr} \pnum \returns -\tcode{\exposid{nested-accessor_}.offset(p, i)} +\tcode{\exposid{nested-accessor_}.offset(p, i)}. \end{itemdescr} \rSec3[linalg.conj.conjugated]{Function template \tcode{conjugated}} @@ -13052,7 +13053,7 @@ \begin{itemdescr} \pnum \returns -\tcode{extents(in.extent(1), in.extent(0))} +\tcode{extents(in.extent(1), in.extent(0))}. \end{itemdescr} \begin{codeblock} @@ -13173,7 +13174,7 @@ \pnum \returns -\tcode{\exposid{nested-mapping_}.stride(r == 0 ? 1 : 0)} +\tcode{\exposid{nested-mapping_}.stride(r == 0 ? 1 : 0)}. \end{itemdescr} \indexlibrarymember{layout_transpose::mapping}{operator==}% @@ -13834,12 +13835,21 @@ \tcode{InVec::value_type} and \tcode{Scalar} are either a floating-point type, or a specialization of \tcode{complex}. Let \tcode{a} be -\tcode{\exposid{abs-if-needed}(declval())}. -Then, \tcode{decltype(\linebreak init + a * a} is convertible to \tcode{Scalar}. +\tcode{\exposid{abs-if-needed}(declval())} and +let \tcode{init_abs} be \tcode{\exposid{abs-if-needed}(init)}. +Then, \tcode{decltype(init_abs * init_abs + a * a)} +is convertible to \tcode{Scalar}. \pnum \returns -The square root of the sum of the square of \tcode{init} and the squares of the absolute values of the elements of \tcode{v}. +The square root of the sum +whose terms are the following: +\begin{itemize} +\item +the square of the absolute value of \tcode{init}, and +\item +the squares of the absolute values of the elements of \tcode{v}. +\end{itemize} \begin{note} For \tcode{init} equal to zero, this is the Euclidean norm (also called 2-norm) of the vector \tcode{v}. @@ -14032,17 +14042,24 @@ \pnum \mandates -\tcode{InVec::value_type} and \tcode{Scalar} are either a floating-point type, or +\tcode{InMat::value_type} and \tcode{Scalar} are either a floating-point type, or a specialization of \tcode{complex}. Let \tcode{a} be -\tcode{\exposid{abs-if-needed}(declval())}. -Then, \tcode{decltype(\linebreak init + a * a)} +\tcode{\exposid{abs-if-needed}(declval())} and +let \tcode{init_abs} be \tcode{\exposid{abs-if-needed}(init)}. +Then, \tcode{decltype(init_abs * init_abs + a * a)} is convertible to \tcode{Scalar}. \pnum \returns -The square root of the sum of squares -of \tcode{init} and the absolute values of the elements of \tcode{A}. +The square root of the sum +whose terms are the following: +\begin{itemize} +\item +the square of the absolute value of \tcode{init}, and +\item +the squares of the absolute values of the elements of \tcode{A}. +\end{itemize} \begin{note} For \tcode{init} equal to zero, this is the Frobenius norm of the matrix \tcode{A}. @@ -14114,7 +14131,7 @@ \item \tcode{init} if \tcode{A.extent(1)} is zero; \item -otherwise, the sum of \tcode{init} and the one norm of the matrix $A$. +otherwise, the sum of \tcode{init} and the one norm of the matrix \tcode{A}. \end{itemize} \begin{note} The one norm of the matrix \tcode{A} @@ -15163,7 +15180,7 @@ \pnum \begin{note} These functions correspond to the BLAS functions -\tcode{xSYR2},\tcode{xSPR2}, \tcode{xHER2} and \tcode{xHPR2}\supercite{blas2}. +\tcode{xSYR2}, \tcode{xSPR2}, \tcode{xHER2} and \tcode{xHPR2}\supercite{blas2}. \end{note} \pnum @@ -15973,7 +15990,7 @@ \tcode{\exposid{multipliable}(A, transposed(B), C)} is \tcode{true}, \item -\tcode{multipliable(B, transposed(A), C)} +\tcode{\exposid{multipliable}(B, transposed(A), C)} is \tcode{true}, and \begin{note} This and the previous imply that \tcode{C} is square. @@ -16038,6 +16055,8 @@ \end{itemdecl} \begin{itemdescr} +\pnum +\effects Computes $C = E + A B^T + B A^T$. \end{itemdescr} @@ -16532,6 +16551,11 @@ \tcode{T} is \defn{value-preserving} if all possible values of \tcode{U} can be represented with type \tcode{T}. +\pnum +If a program declares an explicit or partial specialization of +any of the templates specified in subclause \ref{simd}, +the program is ill-formed, no diagnostic required. + \rSec2[simd.expos]{Exposition-only types, variables, and concepts} \begin{codeblock} @@ -16540,15 +16564,10 @@ template constexpr @\exposidnc{simd-size-type} \exposidnc{simd-size-v} = \seebelownc@; // \expos +template + constexpr @\exposidnc{simd-size-type} \exposidnc{mask-size-v} = \seebelownc@; // \expos template constexpr size_t @\exposidnc{mask-element-size} = \seebelownc@; // \expos -template - concept @\defexposconceptnc{constexpr-wrapper-like}@ = // \expos - @\libconcept{convertible_to}@ && - @\libconcept{equality_comparable_with}@ && - bool_constant::value && - bool_constant(T()) == T::value>::value; - template concept @\defexposconceptnc{explicitly-convertible-to}@ = // \expos requires { @@ -16557,8 +16576,6 @@ template using @\exposidnc{deduced-vec-t} = \seebelownc@; // \expos -template using @\exposidnc{make-compatible-simd-t} = \seebelownc@; // \expos - template concept @\defexposconceptnc{simd-vec-type}@ = // \expos @\libconcept{same_as}@> && @@ -16584,13 +16601,9 @@ concept @\defexposconceptnc{simd-complex}@ = // \expos @\exposconcept{simd-vec-type}@ && @\libconcept{same_as}@>>; -template +template concept @\defexposconceptnc{math-floating-point}@ = // \expos - (@\exposconceptnc{simd-floating-point}<\exposidnc{deduced-vec-t}@> || ...); - -template - requires @\exposconceptnc{math-floating-point}@ - using @\exposidnc{math-common-simd-t} = \seebelownc@; // \expos + @\exposconceptnc{simd-floating-point}<\exposidnc{deduced-vec-t}@>; template concept @\exposconceptnc{reduction-binary-operation} = \seebelownc@; // \expos @@ -16639,36 +16652,30 @@ \end{itemdescr} \begin{itemdecl} -template constexpr size_t @\exposid{mask-element-size}@ = @\seebelow@; +template + constexpr @\exposid{simd-size-type} \exposid{mask-size-v}@ = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum -\tcode{\exposid{mask-element-size}>} has the value -\tcode{Bytes}. +\tcode{\exposid{mask-size-v}} denotes +the width of \tcode{basic_mask} +if the specialization \tcode{ba\-sic_mask} is enabled, or +\tcode{0} otherwise. \end{itemdescr} \begin{itemdecl} -template using @\exposid{deduced-vec-t}@ = @\seebelow@; +template constexpr size_t @\exposid{mask-element-size}@ = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum -Let \tcode{x} denote an lvalue of type \tcode{const T}. - -\pnum -\tcode{\exposid{deduced-vec-t}} is an alias for -\begin{itemize} - \item - \tcode{decltype(x + x)}, if the type of \tcode{x + x} is an enabled - specialization of \tcode{basic_vec}; otherwise - \item - \tcode{void}. -\end{itemize} +\tcode{\exposid{mask-element-size}>} has the value +\tcode{Bytes}. \end{itemdescr} \begin{itemdecl} -template using @\exposid{make-compatible-simd-t}@ = @\seebelow@; +template using @\exposid{deduced-vec-t}@ = @\seebelow@; \end{itemdecl} \begin{itemdescr} @@ -16676,55 +16683,7 @@ Let \tcode{x} denote an lvalue of type \tcode{const T}. \pnum -\tcode{\exposid{make-compatible-simd-t}} is an alias for -\begin{itemize} - \item - \tcode{\exposid{deduced-vec-t}}, if that type is not \tcode{void}, - otherwise - \item - \tcode{vec}. -\end{itemize} -\end{itemdescr} - -\begin{itemdecl} -template - requires @\exposconcept{math-floating-point}@ - using @\exposid{math-common-simd-t}@ = @\seebelow@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{T0} denote \tcode{Ts...[0]}. -Let \tcode{T1} denote \tcode{Ts...[1]}. -Let \tcode{TRest} denote a pack such that \tcode{T0, T1, TRest...} is equivalent -to \tcode{Ts...}. - -\pnum -Let \tcode{\exposid{math-common-simd-t}} be an alias for -\begin{itemize} - \item - \tcode{\exposid{deduced-vec-t}}, if \tcode{sizeof...(Ts)} equals $1$; - otherwise - \item - \tcode{common_type_t<\exposid{deduced-vec-t}, - \exposid{deduced-vec-t}>}, if \tcode{sizeof...(Ts)} equals $2$ and - \tcode{\exposconcept{math-floating-point} \&\& - \exposconcept{math-floating-point}} is \tcode{true}; otherwise - \item - \tcode{common_type_t<\exposid{deduced-vec-t}, T1>}, if - \tcode{sizeof...(Ts)} equals $2$ and - \tcode{\exposconceptx{math-floating-\brk{}point}{math-floating-point}<\brk{}T0>} - is \tcode{true}; otherwise - \item - \tcode{common_type_t>}, if - \tcode{sizeof...(Ts)} equals $2$; otherwise - \item - \tcode{common_type_t<\exposid{math-common-simd-t}, TRest...>}, if - \tcode{\exposid{math-common-simd-t}} is valid and denotes a type; - otherwise - \item - \tcode{common_type_t<\exposid{math-common-simd-t}, T0, T1>}. -\end{itemize} +\tcode{\exposid{deduced-vec-t}} is an alias for \tcode{decltype(x + x)}. \end{itemdescr} \begin{itemdecl} @@ -16779,26 +16738,26 @@ An implementation defines ABI tag types as necessary for the following aliases. \pnum -\tcode{\exposid{deduce-abi-t}} is defined if +\tcode{\exposid{deduce-abi-t}} names an ABI tag type if and only if \begin{itemize} \item \tcode{T} is a vectorizable type, \item \tcode{N} is greater than zero, and \item \tcode{N} is not larger than an implementation-defined maximum. \end{itemize} +Otherwise, \tcode{\exposid{deduce-abi-t}} names an unspecified type. The \impldef{maximum width for \tcode{vec} and \tcode{mask}} maximum for \tcode{N} is not smaller than 64 and can differ depending on \tcode{T}. \pnum -Where present, \tcode{\exposid{deduce-abi-t}} names an ABI tag type such -that +If \tcode{\exposid{deduce-abi-t}} names an ABI tag type, +the following is \tcode{true}: \begin{itemize} - \item - \tcode{\exposid{simd-size-v}>} equals - \tcode{N}, \item \tcode{basic_vec>} is - enabled\iref{simd.overview}, and - \item - \tcode{basic_mask, N>>} is enabled. +\item + \tcode{\exposid{simd-size-v}>} + equals \tcode{N}, and +\item + \tcode{basic_vec>} + is enabled\iref{simd.overview}. \end{itemize} \pnum @@ -16863,6 +16822,12 @@ const basic_vec& x, const typename basic_vec::mask_type& mask, BinaryOperation binary_op = {}, type_identity_t identity_element = @\seebelow@); + template> + constexpr T reduce(const T&, BinaryOperation = {}); + template> + constexpr T reduce(const T& x, @\libconcept{same_as}@ auto mask, BinaryOperation binary_op = {}, + type_identity_t identity_element = @\seebelow@); + template constexpr T reduce_min(const basic_vec&) noexcept; template @@ -16874,6 +16839,11 @@ constexpr T reduce_max(const basic_vec&, const typename basic_vec::mask_type&) noexcept; + template constexpr T reduce_min(const T&) noexcept; + template constexpr T reduce_min(const T&, @\libconcept{same_as}@ auto) noexcept; + template constexpr T reduce_max(const T&) noexcept; + template constexpr T reduce_max(const T&, @\libconcept{same_as}@ auto) noexcept; + // \ref{simd.loadstore}, load and store functions template requires ranges::@\libconcept{sized_range}@ @@ -16966,33 +16936,33 @@ template<@\exposid{simd-size-type}@ N = @\seebelow@, @\exposconcept{simd-vec-type}@ V, class IdxMap> constexpr resize_t permute(const V& v, IdxMap&& idxmap); - template<@\exposid{simd-size-type}@ N = @\seebelow@, @\exposconcept{simd-mask-type}@ M, class IdxMap> - constexpr resize_t permute(const M& v, IdxMap&& idxmap); + template<@\exposid{simd-size-type}@ N = @\seebelow@, @\exposconcept{simd-mask-type}@ V, class IdxMap> + constexpr resize_t permute(const V& v, IdxMap&& idxmap); // \ref{simd.permute.dynamic}, dynamic permute template<@\exposconcept{simd-vec-type}@ V, @\exposconcept{simd-integral}@ I> constexpr resize_t permute(const V& v, const I& indices); - template<@\exposconcept{simd-mask-type}@ M, @\exposconcept{simd-integral}@ I> - constexpr resize_t permute(const M& v, const I& indices); + template<@\exposconcept{simd-mask-type}@ V, @\exposconcept{simd-integral}@ I> + constexpr resize_t permute(const V& v, const I& indices); // \ref{simd.permute.mask}, mask permute template<@\exposconcept{simd-vec-type}@ V> constexpr V compress(const V& v, const typename V::mask_type& selector); - template<@\exposconcept{simd-mask-type}@ M> - constexpr M compress(const M& v, const type_identity_t& selector); + template<@\exposconcept{simd-mask-type}@ V> + constexpr V compress(const V& v, const type_identity_t& selector); template<@\exposconcept{simd-vec-type}@ V> constexpr V compress(const V& v, const typename V::mask_type& selector, const typename V::value_type& fill_value); - template<@\exposconcept{simd-mask-type}@ M> - constexpr M compress(const M& v, const type_identity_t& selector, - const typename M::value_type& fill_value); + template<@\exposconcept{simd-mask-type}@ V> + constexpr V compress(const V& v, const type_identity_t& selector, + const typename V::value_type& fill_value); template<@\exposconcept{simd-vec-type}@ V> constexpr V expand(const V& v, const typename V::mask_type& selector, const V& original = {}); - template<@\exposconcept{simd-mask-type}@ M> - constexpr M expand(const M& v, const type_identity_t& selector, - const M& original = {}); + template<@\exposconcept{simd-mask-type}@ V> + constexpr V expand(const V& v, const type_identity_t& selector, + const V& original = {}); // \ref{simd.permute.memory}, memory permute template @@ -17041,12 +17011,11 @@ constexpr auto chunk(const basic_mask& x) noexcept; template - constexpr basic_vec::size() + ...)>> - cat(const basic_vec&...) noexcept; + constexpr resize_t<(basic_vec::size() + ...), + basic_vec> cat(const basic_vec&...) noexcept; template - constexpr basic_mask, - (basic_mask::size() + ...)>> - cat(const basic_mask&...) noexcept; + constexpr resize_t<(basic_mask::size() + ...)>, + basic_mask> cat(const basic_mask&...) noexcept; // \ref{simd.alg}, algorithms template @@ -17074,8 +17043,12 @@ template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ acos(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ asin(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ atan(const V& x); - template - constexpr @\exposid{math-common-simd-t}@ atan2(const V0& y, const V1& x); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ atan2(const V& y, const V& x); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ atan2(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ atan2(const V& x, const @\exposid{deduced-vec-t}@& y); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ cos(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ sin(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ tan(const V& x); @@ -17113,12 +17086,35 @@ constexpr basic_vec abs(const basic_vec& j); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ abs(const V& j); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ fabs(const V& x); - template - constexpr @\exposid{math-common-simd-t}@ hypot(const V0& x, const V1& y); - template - constexpr @\exposid{math-common-simd-t}@ hypot(const V0& x, const V1& y, const V2& z); - template - constexpr @\exposid{math-common-simd-t}@ pow(const V0& x, const V1& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ hypot(const V& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ hypot(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ hypot(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ hypot(const V& x, const V& y, const V& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ hypot(const @\exposid{deduced-vec-t}@& x, const V& y, const V& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ hypot(const V& x, const @\exposid{deduced-vec-t}@& y, const V& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ hypot(const V& x, const V& y, const @\exposid{deduced-vec-t}@& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ hypot(const @\exposid{deduced-vec-t}@& x, const @\exposid{deduced-vec-t}@& y + @\itcorr@ const V& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ hypot(const @\exposid{deduced-vec-t}@& x, const V& y + @\itcorr@ const @\exposid{deduced-vec-t}@& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ hypot(const V& x, const @\exposid{deduced-vec-t}@& y + @\itcorr@ const @\exposid{deduced-vec-t}@& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ pow(const V& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ pow(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ pow(const V& x, const @\exposid{deduced-vec-t}@& y); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ sqrt(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ erf(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ erfc(const V& x); @@ -17140,28 +17136,92 @@ constexpr rebind_t> llround(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ trunc(const V& x); - template - constexpr @\exposid{math-common-simd-t}@ fmod(const V0& x, const V1& y); - template - constexpr @\exposid{math-common-simd-t}@ remainder(const V0& x, const V1& y); - template - constexpr @\exposid{math-common-simd-t}@ - remquo(const V0& x, const V1& y, rebind_t>* quo); - template - constexpr @\exposid{math-common-simd-t}@ copysign(const V0& x, const V1& y); - template - constexpr @\exposid{math-common-simd-t}@ nextafter(const V0& x, const V1& y); - template - constexpr @\exposid{math-common-simd-t}@ fdim(const V0& x, const V1& y); - template - constexpr @\exposid{math-common-simd-t}@ fmax(const V0& x, const V1& y); - template - constexpr @\exposid{math-common-simd-t}@ fmin(const V0& x, const V1& y); - template - constexpr @\exposid{math-common-simd-t}@ fma(const V0& x, const V1& y, const V2& z); - template - constexpr @\exposid{math-common-simd-t}@ - lerp(const V0& a, const V1& b, const V2& t) noexcept; + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmod(const V& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmod(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmod(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ remainder(const V& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ remainder(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ remainder(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ + remquo(const V& x, const V& y, rebind_t>* quo); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ + remquo(const @\exposid{deduced-vec-t}@& x, const V& y, rebind_t>* quo); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ + remquo(const V& x, const @\exposid{deduced-vec-t}@& y, rebind_t>* quo); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ copysign(const V& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ copysign(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ copysign(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ nextafter(const V& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ nextafter(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ nextafter(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fdim(const V& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fdim(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fdim(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmax(const V& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmax(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmax(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmin(const V& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmin(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmin(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fma(const V& x, const V& y, const V& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fma(const @\exposid{deduced-vec-t}@& x, const V& y, const V& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fma(const V& x, const @\exposid{deduced-vec-t}@& y, const V& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fma(const V& x, const V& y, const @\exposid{deduced-vec-t}@& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fma(const @\exposid{deduced-vec-t}@& x, const @\exposid{deduced-vec-t}@& y + @\itcorr@ const V& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fma(const @\exposid{deduced-vec-t}@& x, const V& y + @\itcorr@ const @\exposid{deduced-vec-t}@& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fma(const V& x, const @\exposid{deduced-vec-t}@& y + @\itcorr@ const @\exposid{deduced-vec-t}@& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ + lerp(const V& a, const V& b, const V& t) noexcept; + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ lerp(const @\exposid{deduced-vec-t}@& x, const V& y, const V& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ lerp(const V& x, const @\exposid{deduced-vec-t}@& y, const V& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ lerp(const V& x, const V& y, const @\exposid{deduced-vec-t}@& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ lerp(const @\exposid{deduced-vec-t}@& x, const @\exposid{deduced-vec-t}@& y + @\itcorr@ const V& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ lerp(const @\exposid{deduced-vec-t}@& x, const V& y + @\itcorr@ const @\exposid{deduced-vec-t}@& z); + template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ lerp(const V& x, const @\exposid{deduced-vec-t}@& y + @\itcorr@ const @\exposid{deduced-vec-t}@& z); template<@\exposconcept{math-floating-point}@ V> constexpr rebind_t> fpclassify(const V& x); template<@\exposconcept{math-floating-point}@ V> @@ -17174,50 +17234,130 @@ constexpr typename @\exposid{deduced-vec-t}@::mask_type isnormal(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr typename @\exposid{deduced-vec-t}@::mask_type signbit(const V& x); - template - constexpr typename @\exposid{math-common-simd-t}@::mask_type - isgreater(const V0& x, const V1& y); - template - constexpr typename @\exposid{math-common-simd-t}@::mask_type - isgreaterequal(const V0& x, const V1& y); - template - constexpr typename @\exposid{math-common-simd-t}@::mask_type - isless(const V0& x, const V1& y); - template - constexpr typename @\exposid{math-common-simd-t}@::mask_type - islessequal(const V0& x, const V1& y); - template - constexpr typename @\exposid{math-common-simd-t}@::mask_type - islessgreater(const V0& x, const V1& y); - template - constexpr typename @\exposid{math-common-simd-t}@::mask_type - isunordered(const V0& x, const V1& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isgreater(const V& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isgreater(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isgreater(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isgreaterequal(const V& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isgreaterequal(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isgreaterequal(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isless(const V& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isless(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isless(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + islessequal(const V& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + islessequal(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + islessequal(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + islessgreater(const V& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + islessgreater(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + islessgreater(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isunordered(const V& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isunordered(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isunordered(const V& x, const @\exposid{deduced-vec-t}@& y); template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-vec-t}@ assoc_laguerre(const rebind_t>& n, - const rebind_t>& m, const V& x); + @\itcorr@ const rebind_t>& m, const V& x); template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-vec-t}@ assoc_legendre(const rebind_t>& l, - const rebind_t>& m, const V& x); - template - @\exposid{math-common-simd-t}@ beta(const V0& x, const V1& y); + @\itcorr@ const rebind_t>& m, const V& x); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ beta(const V& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ beta(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ beta(const V& x, const @\exposid{deduced-vec-t}@& y); template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-vec-t}@ comp_ellint_1(const V& k); template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-vec-t}@ comp_ellint_2(const V& k); - template - @\exposid{math-common-simd-t}@ comp_ellint_3(const V0& k, const V1& nu); - template - @\exposid{math-common-simd-t}@ cyl_bessel_i(const V0& nu, const V1& x); - template - @\exposid{math-common-simd-t}@ cyl_bessel_j(const V0& nu, const V1& x); - template - @\exposid{math-common-simd-t}@ cyl_bessel_k(const V0& nu, const V1& x); - template - @\exposid{math-common-simd-t}@ cyl_neumann(const V0& nu, const V1& x); - template - @\exposid{math-common-simd-t}@ ellint_1(const V0& k, const V1& phi); - template - @\exposid{math-common-simd-t}@ ellint_2(const V0& k, const V1& phi); - template - @\exposid{math-common-simd-t}@ ellint_3(const V0& k, const V1& nu, const V2& phi); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ comp_ellint_3(const V& k, const V& nu); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ comp_ellint_3(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ comp_ellint_3(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_i(const V& nu, const V& x); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_i(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_i(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_j(const V& nu, const V& x); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_j(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_j(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_k(const V& nu, const V& x); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_k(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_k(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_neumann(const V& nu, const V& x); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_neumann(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_neumann(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_1(const V& k, const V& phi); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_1(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_1(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_2(const V& k, const V& phi); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_2(const @\exposid{deduced-vec-t}@& x, const V& y); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_2(const V& x, const @\exposid{deduced-vec-t}@& y); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_3(const V& k, const V& nu, const V& phi); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_3(const @\exposid{deduced-vec-t}@& x, const V& y, const V& z); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_3(const V& x, const @\exposid{deduced-vec-t}@& y, const V& z); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_3(const V& x, const V& y, const @\exposid{deduced-vec-t}@& z); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_3(const @\exposid{deduced-vec-t}@& x, const @\exposid{deduced-vec-t}@& y, const V& z); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_3(const @\exposid{deduced-vec-t}@& x, const V& y, const @\exposid{deduced-vec-t}@& z); + template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_3(const V& x, const @\exposid{deduced-vec-t}@& y, const @\exposid{deduced-vec-t}@& z); template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-vec-t}@ expint(const V& x); template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-vec-t}@ hermite(const rebind_t>& n, const V& x); @@ -17316,9 +17456,9 @@ template<@\exposconcept{simd-complex}@ V> constexpr V pow(const V& x, const V& y); // \ref{simd.mask.class}, class template \tcode{basic_mask} - template>> class basic_mask; + template class basic_mask; template>> - using @\libmember{mask}{simd}@ = basic_mask>; + using @\libmember{mask}{simd}@ = vec::mask_type; // \ref{simd.mask.reductions}, reductions template @@ -17489,10 +17629,6 @@ (converting) loads and stores for the given type \tcode{T} on arrays of type \tcode{U}. \end{note} - -\pnum -The behavior of a program that adds specializations for \tcode{alignment} -is undefined. \end{itemdescr} \indexlibrarymember{rebind}{simd} @@ -17506,8 +17642,7 @@ \begin{itemize} \item \tcode{V} is a data-parallel type, \item \tcode{T} is a vectorizable type, and -\item \tcode{\exposid{deduce-abi-t}} has a member type - \tcode{type}. +\item \tcode{\exposid{deduce-abi-t}} names an ABI tag type. \end{itemize} \pnum @@ -17532,34 +17667,33 @@ \begin{itemdescr} \pnum -Let \tcode{T} denote +Let \tcode{Abi1} denote an ABI tag \begin{itemize} \item - \tcode{typename V::value_type} if \tcode{V} is a specialization of - \tcode{basic_vec}, + such that \tcode{\exposid{simd-size-v}} + equals \tcode{N} if \tcode{V} is a specialization of \tcode{basic_vec}, \item - otherwise \tcode{\exposid{integer-from}<\exposid{mask-element-size}>} if - \tcode{V} is a specialization of \tcode{basic_mask}. + otherwise such that + \tcode{\exposid{mask-size-v}<\exposid{mask-element-size}, Abi1>} + equals \tcode{N} if \tcode{V} is a specialization of \tcode{basic_mask}. \end{itemize} \pnum The member \tcode{type} is present if and only if \begin{itemize} -\item \tcode{V} is a data-parallel type, and -\item \tcode{\exposid{deduce-abi-t}} has a member type \tcode{type}. +\item + \tcode{V} is a data-parallel type, and +\item + there exists at least one ABI tag + that satisfies the above constraints for \tcode{Abi1}. \end{itemize} \pnum -If \tcode V is a specialization of \tcode{basic_vec}, let \tcode{Abi1} denote an -ABI tag such that \tcode{basic_vec::\brk{}size()} equals \tcode{N}. -If \tcode V is a specialization of \tcode{basic_mask}, let \tcode{Abi1} -denote an ABI tag such that \tcode{basic_mask::size()} equals \tcode{N}. - -\pnum -Where present, the member typedef \tcode{type} names \tcode{basic_vec} -if \tcode V is a specialization of \tcode{basic_vec} or -\tcode{basic_mask} if \tcode V is a specialization of -\tcode{basic_mask}. +Where present, the member typedef \tcode{type} names +\tcode{basic_vec} +if \tcode{V} is a specialization of \tcode{basic_vec}, or +\tcode{basic_mask<\exposid{mask-element-size}, Abi1>} +if \tcode{V} is a specialization of \tcode{basic_mask}. \end{itemdescr} \rSec2[simd.flags]{Load and store flags} @@ -17589,7 +17723,7 @@ \rSec3[simd.flags.oper]{\tcode{flags} operators} -\indexlibrarymember{operator|}{simd::flags} +\indexlibrarymember{operator"|}{simd::flags} \begin{itemdecl} template friend consteval auto operator|(flags a, flags b); @@ -17897,7 +18031,7 @@ // \ref{simd.ctor}, \tcode{basic_vec} constructors template - constexpr explicit(@\seebelow@) basic_vec(U&& value) noexcept; + constexpr basic_vec(U&& value) noexcept; template constexpr explicit(@\seebelow@) basic_vec(const basic_vec&) noexcept; template @@ -17984,7 +18118,8 @@ \begin{itemize} \item enabled, if \tcode{T} is a vectorizable type, and there exists value - \tcode{N} in the range \crange{1}{64}, such that \tcode{Abi} is + \tcode{N} in the range \crange{1}{64}, + such that \tcode{Abi} names the ABI tag denoted by \tcode{\exposid{deduce-abi-t}}, \item otherwise, disabled, if \tcode{T} is not a vectorizable type, @@ -17999,10 +18134,22 @@ In addition only the \tcode{value_type}, \tcode{abi_type}, and \tcode{mask_type} members are present. -If \tcode{basic_vec} is enabled, then \tcode{basic_vec} is -trivially copyable, default-initialization of an object of such a type -default-initializes all elements, and value-initialization value-initializes -all elements\iref{dcl.init.general}. +If \tcode{basic_vec} is enabled, then +\begin{itemize} +\item + \tcode{basic_vec} is trivially copyable, +\item + default-initialization of an object of such a type + default-initializes all elements, +\item + value-initialization value-initializes all elements\iref{dcl.init.general}, +\item + \tcode{basic_vec::mask_type} is an alias + for an enabled specialization of \tcode{basic_mask}, and +\item + \tcode{basic_vec::size()} is equal to + \tcode{basic_vec::mask_type::size()}. +\end{itemize} \pnum \recommended @@ -18024,7 +18171,7 @@ \indexlibraryctor{basic_vec} \begin{itemdecl} -template constexpr explicit(@\seebelow@) basic_vec(U&& value) noexcept; +template constexpr basic_vec(U&& value) noexcept; \end{itemdecl} \begin{itemdescr} @@ -18033,29 +18180,25 @@ \pnum \constraints -\tcode{U} satisfies \tcode{\exposconcept{explicitly-convertible-to}}. +\begin{itemize} +\item +\tcode{U} satisfies \tcode{\libconcept{convertible_to}} and +\tcode{From} is not an arithmetic type and +does not satisfy \exposconcept{constexpr-wrapper-like}, +\item +\tcode{From} is an arithmetic type and +the conversion from \tcode{From} to \tcode{value_type} +is value-preserving\iref{simd.general}, or +\item +\tcode{From} satisfies \exposconcept{constexpr-wrapper-like}, +\tcode{remove_cvref_t} is an arithmetic type, and +\tcode{From::value} is representable by \tcode{value_type}. +\end{itemize} \pnum \effects Initializes each element to the value of the argument after conversion to \tcode{value_type}. - -\pnum -\remarks -The expression inside \tcode{explicit} evaluates to \tcode{false} if and only if -\tcode{U} satisfies \tcode{\libconcept{convertible_to}}, and either -\begin{itemize} - \item - \tcode{From} is not an arithmetic type and does not satisfy - \exposconcept{constexpr-wrapper-like}, - \item - \tcode{From} is an arithmetic type and the conversion from \tcode{From} to - \tcode{value_type} is value-preserving\iref{simd.general}, or - \item - \tcode{From} satisfies \exposconcept{constexpr-wrapper-like}, - \tcode{remove_cvref_t} is an arithmetic type, and - \tcode{From::value} is representable by \tcode{value_type}. -\end{itemize} \end{itemdescr} \indexlibraryctor{basic_vec} @@ -18386,7 +18529,7 @@ A copy of \tcode{*this} before decrementing. \end{itemdescr} -\indexlibrarymember{operator!}{basic_vec} +\indexlibrarymember{operator"!}{basic_vec} \begin{itemdecl} constexpr mask_type operator!() const noexcept; \end{itemdecl} @@ -18402,7 +18545,7 @@ \tcode{!operator[]($i$)} for all $i$ in the range of \range{0}{size()}. \end{itemdescr} -\indexlibrarymember{operator~}{basic_vec} +\indexlibrarymember{operator\~{}}{basic_vec} \begin{itemdecl} constexpr basic_vec operator~() const noexcept; \end{itemdecl} @@ -18459,7 +18602,7 @@ \indexlibrarymember{operator/}{basic_vec} \indexlibrarymember{operator\%}{basic_vec} \indexlibrarymember{operator\&}{basic_vec} -\indexlibrarymember{operator|}{basic_vec} +\indexlibrarymember{operator"|}{basic_vec} \indexlibrarymember{operator\caret}{basic_vec} \indexlibrarymember{operator<<}{basic_vec} \indexlibrarymember{operator>>}{basic_vec} @@ -18523,7 +18666,7 @@ \indexlibrarymember{operator/=}{basic_vec} \indexlibrarymember{operator\%=}{basic_vec} \indexlibrarymember{operator\&=}{basic_vec} -\indexlibrarymember{operator|=}{basic_vec} +\indexlibrarymember{operator"|=}{basic_vec} \indexlibrarymember{operator\caret=}{basic_vec} \indexlibrarymember{operator<<=}{basic_vec} \indexlibrarymember{operator>>=}{basic_vec} @@ -18583,7 +18726,7 @@ \rSec3[simd.comparison]{Comparison operators} \indexlibrarymember{operator==}{basic_vec} -\indexlibrarymember{operator!=}{basic_vec} +\indexlibrarymember{operator"!=}{basic_vec} \indexlibrarymember{operator>=}{basic_vec} \indexlibrarymember{operator<=}{basic_vec} \indexlibrarymember{operator>}{basic_vec} @@ -18713,6 +18856,50 @@ \end{itemize} \end{itemdescr} +\begin{itemdecl} +template> + constexpr T reduce(const T& x, BinaryOperation binary_op = {}); +template> + constexpr T reduce(const T& x, @\libconcept{same_as}@ auto mask, BinaryOperation binary_op = {}, + type_identity_t identity_element = @\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{mask} be \tcode{true} for the overload with no \tcode{mask} parameter. + +\pnum +\constraints +\begin{itemize} +\item \tcode{T} is vectorizable. +\item \tcode{BinaryOperation} models + \tcode{\exposconcept{reduction-binary-operation}}. +\item An argument for \tcode{identity_element} is provided for the invocation, + unless \tcode{BinaryOperation} is one of \tcode{plus<>}, \tcode{multiplies<>}, + \tcode{bit_and<>}, \tcode{bit_or<>}, or \tcode{bit_xor<>}. +\end{itemize} + +\pnum +\returns +If \tcode{mask} is \tcode{false}, returns \tcode{identity_element}. +Otherwise, returns \tcode{x}. + +\pnum +\throws +Nothing. + +\pnum +\remarks +The default argument for \tcode{identity_element} is equal to +\begin{itemize} +\item \tcode{T()} if \tcode{BinaryOperation} is \tcode{plus<>}, +\item \tcode{T(1)} if \tcode{BinaryOperation} is \tcode{multiplies<>}, +\item \tcode{T(\~{}T())} if \tcode{BinaryOperation} is \tcode{bit_and<>}, +\item \tcode{T()} if \tcode{BinaryOperation} is \tcode{bit_or<>}, or +\item \tcode{T()} if \tcode{BinaryOperation} is \tcode{bit_xor<>}. +\end{itemize} +\end{itemdescr} + \indexlibrarymember{reduce_min}{simd} \begin{itemdecl} template constexpr T reduce_min(const basic_vec& x) noexcept; @@ -18787,6 +18974,32 @@ \tcode{mask}. \end{itemdescr} +\begin{itemdecl} +template constexpr T reduce_min(const T& x) noexcept; +template constexpr T reduce_min(const T& x, @\libconcept{same_as}@ auto mask) noexcept; +template constexpr T reduce_max(const T& x) noexcept; +template constexpr T reduce_max(const T& x, @\libconcept{same_as}@ auto mask) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{mask} be \tcode{true} for the overloads with no \tcode{mask} parameter. + +\pnum +\constraints +\begin{itemize} +\item \tcode{T} is vectorizable. +\item \tcode{T} models \tcode{totally_ordered}. +\end{itemize} + +\pnum +\returns +If \tcode{mask} is \tcode{false}, returns \tcode{numeric_limits::max()} for +\tcode{reduce_min} and \tcode{numeric_limits::lowest()} for +\tcode{reduce_max}. +Otherwise, returns \tcode{x}. +\end{itemdescr} + \rSec3[simd.loadstore]{Load and store functions} \indexlibrarymember{unchecked_load}{simd} @@ -19100,8 +19313,8 @@ \begin{itemdecl} template<@\exposid{simd-size-type}@ N = @\seebelow@, @\exposconcept{simd-vec-type}@ V, class IdxMap> constexpr resize_t permute(const V& v, IdxMap&& idxmap); -template<@\exposid{simd-size-type}@ N = @\seebelow@, @\exposconcept{simd-mask-type}@ M, class IdxMap> - constexpr resize_t permute(const M& v, IdxMap&& idxmap); +template<@\exposid{simd-size-type}@ N = @\seebelow@, @\exposconcept{simd-mask-type}@ V, class IdxMap> + constexpr resize_t permute(const V& v, IdxMap&& idxmap); \end{itemdecl} \begin{itemdescr} @@ -19159,8 +19372,8 @@ \begin{itemdecl} template<@\exposconcept{simd-vec-type}@ V, @\exposconcept{simd-integral}@ I> constexpr resize_t permute(const V& v, const I& indices); -template<@\exposconcept{simd-mask-type}@ M, @\exposconcept{simd-integral}@ I> - constexpr resize_t permute(const M& v, const I& indices); +template<@\exposconcept{simd-mask-type}@ V, @\exposconcept{simd-integral}@ I> + constexpr resize_t permute(const V& v, const I& indices); \end{itemdecl} \begin{itemdescr} @@ -19181,8 +19394,8 @@ \begin{itemdecl} template<@\exposconcept{simd-vec-type}@ V> constexpr V compress(const V& v, const typename V::mask_type& selector); -template<@\exposconcept{simd-mask-type}@ M> - constexpr M compress(const M& v, const type_identity_t& selector); +template<@\exposconcept{simd-mask-type}@ V> + constexpr V compress(const V& v, const type_identity_t& selector); \end{itemdecl} \begin{itemdescr} @@ -19214,9 +19427,9 @@ template<@\exposconcept{simd-vec-type}@ V> constexpr V compress(const V& v, const typename V::mask_type& selector, const typename V::value_type& fill_value); -template<@\exposconcept{simd-mask-type}@ M> - constexpr M compress(const M& v, const type_identity_t& selector, - const typename M::value_type& fill_value); +template<@\exposconcept{simd-mask-type}@ V> + constexpr V compress(const V& v, const type_identity_t& selector, + const typename V::value_type& fill_value); \end{itemdecl} \begin{itemdescr} @@ -19243,8 +19456,8 @@ \begin{itemdecl} template<@\exposconcept{simd-vec-type}@ V> constexpr V expand(const V& v, const typename V::mask_type& selector, const V& original = {}); -template<@\exposconcept{simd-mask-type}@ M> - constexpr M expand(const M& v, const type_identity_t& selector, const M& original = {}); +template<@\exposconcept{simd-mask-type}@ V> + constexpr V expand(const V& v, const type_identity_t& selector, const V& original = {}); \end{itemdecl} \begin{itemdescr} @@ -19548,28 +19761,14 @@ \indexlibrarymember{cat}{simd} \begin{itemdecl} template - constexpr vec::size() + ...)> - cat(const basic_vec&... xs) noexcept; + constexpr resize_t<(basic_vec::size() + ...), + basic_vec> cat(const basic_vec&... xs) noexcept; template - constexpr basic_mask, - (basic_mask::size() + ...)>> - cat(const basic_mask&... xs) noexcept; + constexpr resize_t<(basic_mask::size() + ...), + basic_mask> cat(const basic_mask&... xs) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\constraints -\begin{itemize} - \item - For the first overload \tcode{vec::size() + ...)>} - is enabled. - \item - For the second overload - \tcode{basic_mask, - (basic_mask::size() + ...)>>} is enabled. -\end{itemize} - \pnum \returns A data-parallel object initialized with the concatenated values in the @@ -19688,10 +19887,6 @@ \rSec3[simd.math]{Mathematical functions} \indexlibrarymember{ilogb}{simd} -\indexlibrarymember{ldexp}{simd} -\indexlibrarymember{scalbn}{simd} -\indexlibrarymember{scalbln}{simd} -\indexlibrarymember{abs}{simd} \indexlibrarymember{abs}{simd} \indexlibrarymember{fabs}{simd} \indexlibrarymember{ceil}{simd} @@ -19727,15 +19922,6 @@ \begin{itemdecl} template<@\exposconcept{math-floating-point}@ V> constexpr rebind_t> ilogb(const V& x); -template<@\exposconcept{math-floating-point}@ V> - constexpr @\exposid{deduced-vec-t}@ ldexp(const V& x, const rebind_t>& exp); -template<@\exposconcept{math-floating-point}@ V> - constexpr @\exposid{deduced-vec-t}@ scalbn(const V& x, const rebind_t>& n); -template<@\exposconcept{math-floating-point}@ V> - constexpr @\exposid{deduced-vec-t}@ - scalbln(const V& x, const rebind_t>& n); -template<@\libconcept{signed_integral}@ T, class Abi> - constexpr basic_vec abs(const basic_vec& j); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ abs(const V& j); template<@\exposconcept{math-floating-point}@ V> @@ -19758,24 +19944,67 @@ constexpr rebind_t> lround(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr rebind_t> llround(const V& x); -template - constexpr @\exposid{math-common-simd-t}@ fmod(const V0& x, const V1& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmod(const V& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmod(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmod(const V& x, const @\exposid{deduced-vec-t}@& y); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ trunc(const V& x); -template - constexpr @\exposid{math-common-simd-t}@ remainder(const V0& x, const V1& y); -template - constexpr @\exposid{math-common-simd-t}@ copysign(const V0& x, const V1& y); -template - constexpr @\exposid{math-common-simd-t}@ nextafter(const V0& x, const V1& y); -template - constexpr @\exposid{math-common-simd-t}@ fdim(const V0& x, const V1& y); -template - constexpr @\exposid{math-common-simd-t}@ fmax(const V0& x, const V1& y); -template - constexpr @\exposid{math-common-simd-t}@ fmin(const V0& x, const V1& y); -template - constexpr @\exposid{math-common-simd-t}@ fma(const V0& x, const V1& y, const V2& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ remainder(const V& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ remainder(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ remainder(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ copysign(const V& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ copysign(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ copysign(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ nextafter(const V& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ nextafter(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ nextafter(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fdim(const V& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fdim(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fdim(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmax(const V& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmax(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmax(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmin(const V& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmin(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fmin(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fma(const V& x, const V& y, const V& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fma(const @\exposid{deduced-vec-t}@& x, const V& y, const V& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fma(const V& x, const @\exposid{deduced-vec-t}@& y, const V& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ fma(const V& x, const V& y, const @\exposid{deduced-vec-t}@& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ + fma(const @\exposid{deduced-vec-t}@& x, const @\exposid{deduced-vec-t}@& y, const V& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ + fma(const @\exposid{deduced-vec-t}@& x, const V& y, const @\exposid{deduced-vec-t}@& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ + fma(const V& x, const @\exposid{deduced-vec-t}@& y, const @\exposid{deduced-vec-t}@& z); template<@\exposconcept{math-floating-point}@ V> constexpr rebind_t> fpclassify(const V& x); template<@\exposconcept{math-floating-point}@ V> @@ -19788,19 +20017,57 @@ constexpr typename @\exposid{deduced-vec-t}@::mask_type isnormal(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr typename @\exposid{deduced-vec-t}@::mask_type signbit(const V& x); -template - constexpr typename @\exposid{math-common-simd-t}@::mask_type isgreater(const V0& x, const V1& y); -template - constexpr typename @\exposid{math-common-simd-t}@::mask_type - isgreaterequal(const V0& x, const V1& y); -template - constexpr typename @\exposid{math-common-simd-t}@::mask_type isless(const V0& x, const V1& y); -template - constexpr typename @\exposid{math-common-simd-t}@::mask_type islessequal(const V0& x, const V1& y); -template - constexpr typename @\exposid{math-common-simd-t}@::mask_type islessgreater(const V0& x, const V1& y); -template - constexpr typename @\exposid{math-common-simd-t}@::mask_type isunordered(const V0& x, const V1& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type isgreater(const V& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type isgreater(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type isgreater(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isgreaterequal(const V& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isgreaterequal(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isgreaterequal(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isless(const V& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isless(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isless(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + islessequal(const V& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + islessequal(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + islessequal(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + islessgreater(const V& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + islessgreater(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + islessgreater(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isunordered(const V& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isunordered(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr typename @\exposid{deduced-vec-t}@::mask_type + isunordered(const V& x, const @\exposid{deduced-vec-t}@& y); \end{itemdecl} \begin{itemdescr} @@ -19810,9 +20077,49 @@ Let \tcode{\placeholder{math-func-vec}} denote: \begin{codeblock} template -Ret @\placeholder{math-func-vec}@(Args... args) { +Ret @\placeholder{math-func-vec}@(const Args&... args) { + return Ret([&](@\exposid{simd-size-type}@ i) { + return @\placeholder{math-func}@(@\exposid{deduced-vec-t}@(args)[i]...); + }); +} +\end{codeblock} + +\pnum +\returns +A value \tcode{ret} of type \tcode{Ret}, that is element-wise equal to the +result of calling \tcode{\placeholder{math-func-vec}} with the parameters of the above +functions. +If in an invocation of a scalar overload of \tcode{\placeholder{math-func}} for index +\tcode{i} in \tcode{\placeholder{math-func-vec}} a domain, pole, or range error would +occur, the value of \tcode{ret[i]} is unspecified. + +\pnum +\remarks +It is unspecified whether \tcode{errno}\iref{errno} is accessed. +\end{itemdescr} + +\indexlibrarymember{ldexp}{simd} +\indexlibrarymember{scalbn}{simd} +\indexlibrarymember{scalbln}{simd} +\begin{itemdecl} +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ ldexp(const V& x, const rebind_t>& exp); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ scalbn(const V& x, const rebind_t>& n); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ + scalbln(const V& x, const rebind_t>& n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{Ret} be \tcode{\exposid{deduced-vec-t}}. +Let \tcode{\placeholder{math-func}} denote the name of the function template. +Let \tcode{\placeholder{math-func-vec}} denote: +\begin{codeblock} +Ret @\placeholder{math-func-vec}@(const @\exposid{deduced-vec-t}@& a, const auto& b) { return Ret([&](@\exposid{simd-size-type}@ i) { - return @\placeholder{math-func}@(@\exposid{make-compatible-simd-t}@(args)[i]...); + return @\placeholder{math-func}@(a[i], b[i]); }); } \end{codeblock} @@ -19820,7 +20127,7 @@ \pnum \returns A value \tcode{ret} of type \tcode{Ret}, that is element-wise equal to the -result of calling \tcode{\placeholder{math-func-vec}} with the arguments of the above +result of calling \tcode{\placeholder{math-func-vec}} with the parameters of the above functions. If in an invocation of a scalar overload of \tcode{\placeholder{math-func}} for index \tcode{i} in \tcode{\placeholder{math-func-vec}} a domain, pole, or range error would @@ -19831,6 +20138,24 @@ It is unspecified whether \tcode{errno}\iref{errno} is accessed. \end{itemdescr} +\indexlibrarymember{abs}{simd} +\begin{itemdecl} +template<@\libconcept{signed_integral}@ T, class Abi> + constexpr basic_vec abs(const basic_vec& j); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{all_of(j >= -numeric_limits::max())} is \tcode{true}. + +\pnum +\returns +An object where the $i^{\textrm{th}}$ element is initialized to the result of +\tcode{std::abs(j[$i$])} for all $i$ in the range \range{0}{j.size()}. + +\end{itemdescr} + \indexlibrarymember{acos}{simd} \indexlibrarymember{asin}{simd} \indexlibrarymember{atan}{simd} @@ -19862,8 +20187,6 @@ \indexlibrarymember{lgamma}{simd} \indexlibrarymember{tgamma}{simd} \indexlibrarymember{lerp}{simd} -\indexlibrarymember{assoc_laguerre}{simd} -\indexlibrarymember{assoc_legendre}{simd} \indexlibrarymember{beta}{simd} \indexlibrarymember{comp_ellint_1}{simd} \indexlibrarymember{comp_ellint_2}{simd} @@ -19876,19 +20199,16 @@ \indexlibrarymember{ellint_2}{simd} \indexlibrarymember{ellint_3}{simd} \indexlibrarymember{expint}{simd} -\indexlibrarymember{hermite}{simd} -\indexlibrarymember{laguerre}{simd} -\indexlibrarymember{legendre}{simd} -\indexlibrarymember{riemann_zeta}{simd} -\indexlibrarymember{sph_bessel}{simd} -\indexlibrarymember{sph_legendre}{simd} -\indexlibrarymember{sph_neumann}{simd} \begin{itemdecl} template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ acos(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ asin(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ atan(const V& x); -template - constexpr @\exposid{math-common-simd-t}@ atan2(const V0& y, const V1& x); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ atan2(const V& y, const V& x); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ atan2(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ atan2(const V& x, const @\exposid{deduced-vec-t}@& y); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ cos(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ sin(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ tan(const V& x); @@ -19907,61 +20227,123 @@ template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ log2(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ logb(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ cbrt(const V& x); -template - constexpr @\exposid{math-common-simd-t}@ hypot(const V0& x, const V1& y); -template - constexpr @\exposid{math-common-simd-t}@ hypot(const V0& x, const V1& y, const V2& z); -template - constexpr @\exposid{math-common-simd-t}@ pow(const V0& x, const V1& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ hypot(const V& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ hypot(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ hypot(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ hypot(const V& x, const V& y, const V& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ hypot(const @\exposid{deduced-vec-t}@& x, const V& y, const V& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ hypot(const V& x, const @\exposid{deduced-vec-t}@& y, const V& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ hypot(const V& x, const V& y, const @\exposid{deduced-vec-t}@& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ + hypot(const @\exposid{deduced-vec-t}@& x, const @\exposid{deduced-vec-t}@& y, const V& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ + hypot(const @\exposid{deduced-vec-t}@& x, const V& y, const @\exposid{deduced-vec-t}@& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ + hypot(const V& x, const @\exposid{deduced-vec-t}@& y, const @\exposid{deduced-vec-t}@& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ pow(const V& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ pow(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ pow(const V& x, const @\exposid{deduced-vec-t}@& y); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ sqrt(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ erf(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ erfc(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ lgamma(const V& x); template<@\exposconcept{math-floating-point}@ V> constexpr @\exposid{deduced-vec-t}@ tgamma(const V& x); -template - constexpr @\exposid{math-common-simd-t}@ lerp(const V0& a, const V1& b, const V2& t) noexcept; template<@\exposconcept{math-floating-point}@ V> - @\exposid{deduced-vec-t}@ assoc_laguerre(const rebind_t>& n, const - rebind_t>& m, const V& x); + constexpr @\exposid{deduced-vec-t}@ lerp(const V& a, const V& b, const V& t) noexcept; +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ lerp(const @\exposid{deduced-vec-t}@& x, const V& y, const V& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ lerp(const V& x, const @\exposid{deduced-vec-t}@& y, const V& z); template<@\exposconcept{math-floating-point}@ V> - @\exposid{deduced-vec-t}@ assoc_legendre(const rebind_t>& l, const - rebind_t>& m, const V& x); -template - @\exposid{math-common-simd-t}@ beta(const V0& x, const V1& y); + constexpr @\exposid{deduced-vec-t}@ lerp(const V& x, const V& y, const @\exposid{deduced-vec-t}@& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ + lerp(const @\exposid{deduced-vec-t}@& x, const @\exposid{deduced-vec-t}@& y, const V& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ + lerp(const @\exposid{deduced-vec-t}@& x, const V& y, const @\exposid{deduced-vec-t}@& z); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ + lerp(const V& x, const @\exposid{deduced-vec-t}@& y, const @\exposid{deduced-vec-t}@& z); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ beta(const V& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ beta(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ beta(const V& x, const @\exposid{deduced-vec-t}@& y); template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-vec-t}@ comp_ellint_1(const V& k); template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-vec-t}@ comp_ellint_2(const V& k); -template - @\exposid{math-common-simd-t}@ comp_ellint_3(const V0& k, const V1& nu); -template - @\exposid{math-common-simd-t}@ cyl_bessel_i(const V0& nu, const V1& x); -template - @\exposid{math-common-simd-t}@ cyl_bessel_j(const V0& nu, const V1& x); -template - @\exposid{math-common-simd-t}@ cyl_bessel_k(const V0& nu, const V1& x); -template - @\exposid{math-common-simd-t}@ cyl_neumann(const V0& nu, const V1& x); -template - @\exposid{math-common-simd-t}@ ellint_1(const V0& k, const V1& phi); -template - @\exposid{math-common-simd-t}@ ellint_2(const V0& k, const V1& phi); -template - @\exposid{math-common-simd-t}@ ellint_3(const V0& k, const V1& nu, const V2& phi); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ comp_ellint_3(const V& k, const V& nu); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ comp_ellint_3(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ comp_ellint_3(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_i(const V& nu, const V& x); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_i(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_i(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_j(const V& nu, const V& x); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_j(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_j(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_k(const V& nu, const V& x); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_k(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_bessel_k(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_neumann(const V& nu, const V& x); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_neumann(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ cyl_neumann(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_1(const V& k, const V& phi); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_1(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_1(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_2(const V& k, const V& phi); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_2(const @\exposid{deduced-vec-t}@& x, const V& y); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_2(const V& x, const @\exposid{deduced-vec-t}@& y); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_3(const V& k, const V& nu, const V& phi); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_3(const @\exposid{deduced-vec-t}@& x, const V& y, const V& z); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_3(const V& x, const @\exposid{deduced-vec-t}@& y, const V& z); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_3(const V& x, const V& y, const @\exposid{deduced-vec-t}@& z); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_3(const @\exposid{deduced-vec-t}@& x, const @\exposid{deduced-vec-t}@& y, const V& z); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_3(const @\exposid{deduced-vec-t}@& x, const V& y, const @\exposid{deduced-vec-t}@& z); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ ellint_3(const V& x, const @\exposid{deduced-vec-t}@& y, const @\exposid{deduced-vec-t}@& z); template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-vec-t}@ expint(const V& x); -template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-vec-t}@ hermite(const rebind_t>& n, const V& x); -template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-vec-t}@ laguerre(const rebind_t>& n, const V& x); -template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-vec-t}@ legendre(const rebind_t>& l, const V& x); template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-vec-t}@ riemann_zeta(const V& x); -template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-vec-t}@ sph_bessel(const rebind_t>& n, const V& x); -template<@\exposconcept{math-floating-point}@ V> - @\exposid{deduced-vec-t}@ sph_legendre(const rebind_t>& l, - const rebind_t>& m, - const V& theta); -template<@\exposconcept{math-floating-point}@ V> @\exposid{deduced-vec-t}@ sph_neumann(const rebind_t>& n, const V& x); \end{itemdecl} \begin{itemdescr} @@ -19971,9 +20353,9 @@ Let \tcode{\placeholder{math-func-vec}} denote: \begin{codeblock} template -Ret @\placeholder{math-func-vec}@(Args... args) { +Ret @\placeholder{math-func-vec}@(const Args&... args) { return Ret([&](@\exposid{simd-size-type}@ i) { - return @\placeholder{math-func}@(@\exposid{make-compatible-simd-t}@(args)[i]...); + return @\placeholder{math-func}(\exposid{deduced-vec-t}@(args)[i]...); }); } \end{codeblock} @@ -19981,7 +20363,7 @@ \pnum \returns A value \tcode{ret} of type \tcode{Ret}, that is element-wise approximately -equal to the result of calling \tcode{\placeholder{math-func-vec}} with the arguments +equal to the result of calling \tcode{\placeholder{math-func-vec}} with the parameters of the above functions. If in an invocation of a scalar overload of \tcode{\placeholder{math-func}} for index \tcode{i} in \tcode{\placeholder{math-func-vec}} a domain, pole, or range error would @@ -19992,6 +20374,74 @@ It is unspecified whether \tcode{errno}\iref{errno} is accessed. \end{itemdescr} +\indexlibrarymember{assoc_laguerre}{simd} +\indexlibrarymember{assoc_legendre}{simd} +\indexlibrarymember{sph_legendre}{simd} +\begin{itemdecl} +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ assoc_laguerre(const rebind_t>& n, + @\itcorr@ const rebind_t>& m, const V& x); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ assoc_legendre(const rebind_t>& l, + @\itcorr@ const rebind_t>& m, const V& x); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ sph_legendre(const rebind_t>& l, + @\itcorr@ const rebind_t>& m, const V& theta); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{\placeholder{math-func}} denote the name of the function template. +Let \tcode{\placeholder{math-func-vec}} denote: +\begin{codeblock} +auto @\placeholder{math-func-vec}@(const auto& a, const auto& b, const @\exposid{deduced-vec-t}@& c) { + return @\exposid{deduced-vec-t}@([&](@\exposid{simd-size-type}@ i) { + return std::@\placeholder{math-func}@(a[i], b[i], c[i]); + }); +} +\end{codeblock} + +\pnum +\returns +An object that is element-wise approximately equal to the result of calling +\tcode{\placeholder{math-func-vec}} with the parameters of the above functions. +\end{itemdescr} + +\indexlibrarymember{hermite}{simd} +\indexlibrarymember{laguerre}{simd} +\indexlibrarymember{legendre}{simd} +\indexlibrarymember{riemann_zeta}{simd} +\indexlibrarymember{sph_bessel}{simd} +\indexlibrarymember{sph_neumann}{simd} +\begin{itemdecl} +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ hermite(const rebind_t>& n, const V& x); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ laguerre(const rebind_t>& n, const V& x); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ legendre(const rebind_t>& l, const V& x); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ sph_bessel(const rebind_t>& n, const V& x); +template<@\exposconcept{math-floating-point}@ V> + @\exposid{deduced-vec-t}@ sph_neumann(const rebind_t>& n, const V& x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{\placeholder{math-func}} denote the name of the function template. +Let \tcode{\placeholder{math-func-vec}} denote: +\begin{codeblock} +auto @\placeholder{math-func-vec}@(const auto& a, const @\exposid{deduced-vec-t}@& b) { + return @\exposid{deduced-vec-t}@([&](@\exposid{simd-size-type}@ i) { return std::@\placeholder{math-func}@(a[i], b[i]); }); +} +\end{codeblock} + +\pnum +\returns +An object that is element-wise approximately equal to the result of calling +\tcode{\placeholder{math-func-vec}} with the parameters of the above functions. +\end{itemdescr} + \indexlibrarymember{frexp}{simd} \begin{itemdecl} template<@\exposconcept{math-floating-point}@ V> @@ -20004,10 +20454,10 @@ Let \tcode{\placeholder{frexp-vec}} denote: \begin{codeblock} template -pair> @\placeholder{frexp-vec}@(const V& x) { +pair> @\placeholder{frexp-vec}@(const @\exposid{deduced-vec-t}@& x) { int r1[Ret::size()]; Ret r0([&](@\exposid{simd-size-type}@ i) { - return frexp(@\exposid{make-compatible-simd-t}@(x)[i], &r1[i]); + return frexp(x[i], &r1[i]); }); return {r0, rebind_t(r1)}; } @@ -20025,29 +20475,30 @@ \tcode{ret.first}. \end{itemdescr} -\indexlibrarymember{remquo}{simd} \begin{itemdecl} -template - constexpr @\exposid{math-common-simd-t}@ remquo(const V0& x, const V1& y, - rebind_t>* quo); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ remquo(const V& x, const V& y, + rebind_t>* quo); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ + remquo(const @\exposid{deduced-vec-t}@& x, const V& y, rebind_t>* quo); +template<@\exposconcept{math-floating-point}@ V> + constexpr @\exposid{deduced-vec-t}@ + remquo(const V& x, const @\exposid{deduced-vec-t}@& y, rebind_t>* quo); \end{itemdecl} \begin{itemdescr} \pnum -Let \tcode{Ret} be \tcode{\exposid{math-common-simd-t}}. +Let \tcode{V0} be \tcode{\exposid{deduced-vec-t}}. Let \tcode{\placeholder{remquo-vec}} denote: \begin{codeblock} -template -pair> @\placeholder{remquo-vec}@(const V0& x, const V1& y) { - int r1[Ret::size()]; - Ret r0([&](@\exposid{simd-size-type}@ i) { - return remquo(@\exposid{make-compatible-simd-t}@(x)[i], - @\exposid{make-compatible-simd-t}@(y)[i], &r1[i]); - }); - return {r0, rebind_t(r1)}; +pair> @\placeholder{remquo-vec}@(const V0& x, const V0& y) { + int r1[V0::size()]; + V0 r0([&](@\exposid{simd-size-type}@ i) { return remquo(x[i], y[i], &r1[i]); }); + return {r0, rebind_t(r1)}; } \end{codeblock} -Let \tcode{ret} be a value of type \tcode{pair>} +Let \tcode{ret} be a value of type \tcode{pair>} that is the same value as the result of calling \tcode{\placeholder{remquo-vec}(x, y)}. If in an invocation of a scalar overload of \tcode{remquo} for index \tcode{i} @@ -20143,7 +20594,7 @@ \pnum \remarks A function call expression that violates the precondition in the \expects -element is not a core constant expression\iref{expr.const}. +element is not a core constant expression\iref{expr.const.core}. \end{itemdescr} \indexlibrarymember{bit_floor}{simd} @@ -20383,8 +20834,7 @@ constexpr default_sentinel_t @\libmember{end}{basic_mask}@() const noexcept { return {}; } constexpr default_sentinel_t @\libmember{cend}{basic_mask}@() const noexcept { return {}; } - static constexpr integral_constant<@\exposid{simd-size-type}@, @\exposid{simd-size-v}@<@\exposid{integer-from}@, Abi>> - @\libmember{size}{basic_mask}@ {}; + static constexpr integral_constant<@\exposid{simd-size-type}@, @\exposid{mask-size-v}@> @\libmember{size}{basic_mask}@ {}; constexpr basic_mask() noexcept = default; @@ -20472,9 +20922,9 @@ is equal to \tcode{sizeof(T)}, \item otherwise, enabled, if there exists a vectorizable type \tcode{T} and a - value \tcode{N} in the range \crange{1}{64} such that \tcode{Bytes} is equal - to \tcode{sizeof(T)} and \tcode{Abi} is \tcode{\exposid{deduce-abi-t}}, + value \tcode{N} in the range \crange{1}{64} + such that \tcode{Bytes} is equal to \tcode{sizeof(T)} and + \tcode{Abi} names the ABI tag denoted by \tcode{\exposid{decude-abi-t}}, \item otherwise, it is \impldef{set of enabled \tcode{basic_mask} specializations} if such a specialization is enabled. @@ -20617,10 +21067,10 @@ \rSec3[simd.mask.unary]{Unary operators} -\indexlibrarymember{operator!}{basic_mask} +\indexlibrarymember{operator"!}{basic_mask} \indexlibrarymember{operator+}{basic_mask} \indexlibrarymember{operator-}{basic_mask} -\indexlibrarymember{operator~}{basic_mask} +\indexlibrarymember{operator\~{}}{basic_mask} \begin{itemdecl} constexpr basic_mask operator!() const noexcept; constexpr @\seebelow@ operator+() const noexcept; @@ -20711,9 +21161,9 @@ \rSec3[simd.mask.binary]{Binary operators} \indexlibrarymember{operator\&\&}{basic_mask} -\indexlibrarymember{operator||}{basic_mask} +\indexlibrarymember{operator"|"|}{basic_mask} \indexlibrarymember{operator\&}{basic_mask} -\indexlibrarymember{operator|}{basic_mask} +\indexlibrarymember{operator"|}{basic_mask} \indexlibrarymember{operator\caret}{basic_mask} \begin{itemdecl} friend constexpr basic_mask @@ -20742,7 +21192,7 @@ \rSec3[simd.mask.cassign]{Compound assignment} \indexlibrarymember{operator\&=}{basic_mask} -\indexlibrarymember{operator|=}{basic_mask} +\indexlibrarymember{operator"|=}{basic_mask} \indexlibrarymember{operator\caret=}{basic_mask} \begin{itemdecl} friend constexpr basic_mask& @@ -20770,7 +21220,7 @@ \rSec3[simd.mask.comparison]{Comparisons} \indexlibrarymember{operator==}{basic_mask} -\indexlibrarymember{operator!=}{basic_mask} +\indexlibrarymember{operator"!=}{basic_mask} \indexlibrarymember{operator>=}{basic_mask} \indexlibrarymember{operator<=}{basic_mask} \indexlibrarymember{operator<}{basic_mask} diff --git a/source/overloading.tex b/source/overloading.tex index fe6c4d0852..0a0bfbd5fb 100644 --- a/source/overloading.tex +++ b/source/overloading.tex @@ -1056,7 +1056,8 @@ class. The argument list is the \grammarterm{expression-list} or \grammarterm{assignment-expression} -of the \grammarterm{initializer}. +of the \grammarterm{initializer}; +for default-initialization, the argument list is empty. For default-initialization in the context of copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed. @@ -1431,6 +1432,21 @@ \end{codeblock} \end{example} +\pnum +When resolving a placeholder for a deduced class type +where the \grammarterm{template-name} +designates a type template template parameter \tcode{P}, +the type template template argument for \tcode{P} +shall be a deducible template. +Let \tcode{A} be an alias template +whose template parameter list is that of \tcode{P} and +whose \grammarterm{defining-type-id} is a \grammarterm{simple-template-id} +whose \grammarterm{template-name} designates the type template template argument and +whose \grammarterm{template-argument-list} is the template argument list of \tcode{P}. +The alias template \tcode{A} is then used +instead of the original \grammarterm{template-name} +to resolve the placeholder. + \pnum When resolving a placeholder for a deduced class type\iref{dcl.type.simple} where @@ -1688,6 +1704,25 @@ \indextext{overloading!argument lists|)}% \indextext{overloading!candidate functions|)} +\pnum +\begin{example} +\begin{codeblock} +template +struct Y { + Y(); + Y(Ts ...); +}; +template class X> +void f() { + X x; // OK, deduces \tcode{Y} + X x0{}; // OK, deduces \tcode{Y} + X x1{1}; // OK, deduces \tcode{Y} + X x2{1, 2}; // error: cannot deduce \tcode{X} from \tcode{Y} +} +template void f(); +\end{codeblock} +\end{example} + \rSec2[over.match.viable]{Viable functions}% \indextext{overloading!resolution!viable functions|(} @@ -3898,7 +3933,7 @@ \pnum For every pair of types \tcode{\placeholder{L}} and \tcode{\placeholder{R}}, where each of \tcode{\placeholder{L}} and \tcode{\placeholder{R}} is a -floating-point or promoted integral type, +cv-unqualified floating-point or promoted integral type, there exist candidate operator functions of the form \begin{codeblock} @\placeholder{LR}@ operator*(@\placeholder{L}@, @\placeholder{R}@); @@ -3920,14 +3955,14 @@ \tcode{\placeholder{R}}. \pnum -For every integral type \tcode{\placeholder{T}} +For every cv-unqualified integral type \tcode{\placeholder{T}} there exists a candidate operator function of the form \begin{codeblock} std::strong_ordering operator<=>(@\placeholder{T}@, @\placeholder{T}@); \end{codeblock} \pnum -For every pair of floating-point types +For every pair of cv-unqualified floating-point types \tcode{\placeholder{L}} and \tcode{\placeholder{R}}, there exists a candidate operator function of the form \begin{codeblock} @@ -4004,8 +4039,9 @@ \pnum For every triple (\tcode{\placeholder{L}}, \cvqual{vq}, \tcode{\placeholder{R}}), -where \tcode{\placeholder{L}} is an arithmetic type, -and \tcode{\placeholder{R}} is a floating-point or promoted integral type, +where \tcode{\placeholder{L}} is a cv-unqualified arithmetic type +and \tcode{\placeholder{R}} is +a cv-unqualified floating-point or promoted integral type, there exist candidate operator functions of the form \begin{codeblock} @\cvqual{vq} \placeholder{L}@& operator=(@\cvqual{vq} \placeholder{L}@&, @\placeholder{R}@); @@ -4055,7 +4091,7 @@ \tcode{\placeholder{R}}), where \tcode{\placeholder{L}} -is an integral type, and +is a cv-unqualified integral type and \tcode{\placeholder{R}} is a promoted integral type, there exist candidate operator functions of the form @@ -4079,7 +4115,7 @@ \pnum For every pair of types \tcode{\placeholder{L}} and \tcode{\placeholder{R}}, where each of \tcode{\placeholder{L}} and \tcode{\placeholder{R}} is a -floating-point or promoted integral type, +cv-unqualified floating-point or promoted integral type, there exist candidate operator functions of the form \begin{codeblock} @\placeholder{LR}@ operator?:(bool, @\placeholder{L}@, @\placeholder{R}@); @@ -4132,7 +4168,7 @@ The first form of \grammarterm{literal-operator-id} is deprecated\iref{depr.lit}. Some literal suffix identifiers are reserved for future standardization; see~\ref{usrlit.suffix}. A declaration whose \grammarterm{literal-operator-id} uses -such a literal suffix identifier is ill-formed, no diagnostic required. +such a literal suffix identifier is ill-formed, no diagnostic required\ifndrdef{over.literal.reserved}. \pnum A declaration whose \grammarterm{declarator-id} is a diff --git a/source/preprocessor.tex b/source/preprocessor.tex index b9809ae664..c05a798b76 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -229,15 +229,6 @@ The last preprocessing token in the sequence is the first preprocessing token within the sequence that is immediately followed by whitespace containing a new-line character. -\begin{footnote} -Thus, -preprocessing directives are commonly called ``lines''. -These ``lines'' have no other syntactic significance, -as all whitespace is equivalent except in certain situations -during preprocessing (see the -\tcode{\#} -character string literal creation operator in~\ref{cpp.stringize}, for example). -\end{footnote} \begin{note} A new-line character ends the preprocessing directive even if it occurs within what would otherwise be an invocation of a function-like macro. @@ -508,12 +499,6 @@ The identifiers \xname{has_include}, \xname{has_embed}, and \xname{has_cpp_attribute} shall not appear in any context not mentioned in this subclause. -\pnum -Each preprocessing token that remains (in the list of preprocessing tokens that -will become the controlling expression) -after all macro replacements have occurred -shall be in the lexical form of a token\iref{lex.token}. - \pnum Preprocessing directives of the forms \begin{ncsimplebnf} @@ -542,12 +527,12 @@ as a macro\iref{cpp.replace.general}, the program is ill-formed. If the preprocessing token \tcode{defined} -is generated as a result of this replacement process +is generated as a result of this replacement process\ifndrdef{cpp.cond.defined.after.macro} or use of the \tcode{defined} unary operator does not match one of the two specified forms prior to macro replacement, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{cpp.cond.defined.malformed}. \pnum After all replacements due to macro expansion and @@ -574,7 +559,7 @@ \pnum The resulting tokens comprise the controlling constant expression -which is evaluated according to the rules of~\ref{expr.const} +which is evaluated according to the rules of~\ref{expr.const.core} using arithmetic that has at least the ranges specified in~\ref{support.limits}. For the purposes of this token conversion and evaluation all signed and unsigned integer types @@ -772,7 +757,8 @@ is \impldef{treatment of whitespace when processing a \tcode{\#include} directive}. If the attempt succeeds, the directive with the so-formed \grammarterm{header-name} is processed as specified for the previous form. -Otherwise, the program is ill-formed, no diagnostic required. +Otherwise, the program is +ill-formed, no diagnostic required\ifndrdef{cpp.include.malformed.headername}. \begin{note} Adjacent \grammarterm{string-literal}s are not concatenated into a single \grammarterm{string-literal} @@ -1224,7 +1210,7 @@ \begin{bnf} \nontermdef{pp-module}\br - \opt{\keyword{export}} \keyword{module} \opt{pp-tokens} \terminal{;} new-line + \opt{\keyword{export}} \keyword{module} \opt{pp-tokens} new-line \end{bnf} \pnum @@ -1233,8 +1219,7 @@ \begin{ncsimplebnf} pp-module-name \opt{pp-module-partition} \opt{pp-tokens} \end{ncsimplebnf} -where the \grammarterm{pp-tokens} (if any) shall not begin with -a \tcode{(} preprocessing token and +where the grammar non-terminals are defined as: \begin{ncbnf} \nontermdef{pp-module-name}\br @@ -1251,15 +1236,9 @@ \end{ncbnf} No \grammarterm{identifier} in the \grammarterm{pp-module-name} or \grammarterm{pp-module-partition} -shall currently be defined as an object-like macro. - -\pnum -Any preprocessing tokens after the \tcode{module} preprocessing token -in the \tcode{module} directive are processed just as in normal text. -\begin{note} -Each identifier currently defined as a macro name -is replaced by its replacement list of preprocessing tokens. -\end{note} +shall currently be defined as an object-like macro +or followed by \tcode{(} as the next preprocessing token at +the start of phase 4 of translation\iref{lex.phases}. \pnum The \tcode{module} and \tcode{export} (if it exists) preprocessing tokens @@ -1269,6 +1248,69 @@ This makes the line no longer a directive so it is not removed at the end of phase 4. \end{note} +After this replacement, +the preprocessing tokens that constituted the directive are +a \grammarterm{text-line} and are processed as normal text. +\begin{note} +No macro expansion is possible for +the \grammarterm{pp-module-name} and \grammarterm{pp-module-partition}. +\end{note} +After such processing, +there shall be a \tcode{;} or \tcode{[} preprocessing token following +the \grammarterm{pp-module-name} and +optional \grammarterm{pp-module-partition}. + +\pnum +\begin{example} +\begin{codeblocktu}{Importable header \tcode{"common.h"}} +#define DOT_BAR .bar +#define MOD_ATTR [[vendor::shiny_module]] +\end{codeblocktu} + +\begin{codeblocktu}{Translation unit \tcode{\#1}} +module; +#include "common.h" + +export module foo DOT_BAR; // error: expansion of \tcode{DOT_BAR;} does not begin with \tcode{;} or \tcode{[} +\end{codeblocktu} + +\begin{codeblocktu}{Translation unit \tcode{\#2}} +module; +#include "common.h" + +export module M MOD_ATTR ; // OK +\end{codeblocktu} +\end{example} + +\begin{example} +\begin{codeblock} +export module a +.b; // error: preprocessing token after \grammarterm{pp-module-name} is not \tcode{;} or \tcode{[} +\end{codeblock} +\end{example} + +\begin{example} +\begin{codeblock} +export module M [[ +attr1, +attr2 ]] ; // OK +\end{codeblock} +\end{example} + +\begin{example} +\begin{codeblock} +export module M +[[ attr1, +attr2 ]] ; // OK +\end{codeblock} +\end{example} + +\begin{example} +\begin{codeblock} +export module M; int +n; // OK +\end{codeblock} +\end{example} \rSec1[cpp.import]{Header unit importation} \indextext{header unit!preprocessing}% @@ -1530,7 +1572,7 @@ \indextext{unit!translation}% A translation unit shall not \tcode{\#define} or \tcode{\#undef} macro names lexically identical -to keywords, +to keywords\iref{lex.key}, to the identifiers listed in \tref{lex.name.special}, or to the \grammarterm{attribute-token}{s} described in~\ref{dcl.attr}, except that the macro names \tcode{likely} and \tcode{unlikely} may be @@ -2097,9 +2139,8 @@ the following sequence of source lines begins with a source line that has a line number as specified by the digit sequence (interpreted as a decimal integer). -If the digit sequence specifies zero -or a number greater than 2147483647, -the program is ill-formed. +Digit sequences representing a number +outside of the range \crange{1}{2147483647} are conditionally supported. \pnum A preprocessing directive of the form @@ -2230,7 +2271,9 @@ \item \indextext{__line__@\mname{LINE}}% \mname{LINE}\\ -An integer literal representing the presumed line number of +The integer literal \tcode{0} or a decimal integer literal\iref{lex.icon}, +with no digit separators and no \grammarterm{integer-suffix}, +representing the presumed line number of the current source line within the current source file. \begin{note} The presumed line number can be changed by the \tcode{\#line} directive\iref{cpp.line}. @@ -2368,7 +2411,7 @@ \defnxname{cpp_if_constexpr} & \tcode{201606L} \\ \rowsep \defnxname{cpp_impl_coroutine} & \tcode{201902L} \\ \rowsep \defnxname{cpp_impl_destroying_delete} & \tcode{201806L} \\ \rowsep -\defnxname{cpp_impl_reflection} & \tcode{202506L} \\ \rowsep +\defnxname{cpp_impl_reflection} & \tcode{202603L} \\ \rowsep \defnxname{cpp_impl_three_way_comparison} & \tcode{201907L} \\ \rowsep \defnxname{cpp_implicit_move} & \tcode{202207L} \\ \rowsep \defnxname{cpp_inheriting_constructors} & \tcode{201511L} \\ \rowsep @@ -2400,7 +2443,7 @@ \defnxname{cpp_template_parameters} & \tcode{202502L} \\ \rowsep \defnxname{cpp_template_template_args} & \tcode{201611L} \\ \rowsep \defnxname{cpp_threadsafe_static_init} & \tcode{200806L} \\ \rowsep -\defnxname{cpp_trivial_union} & \tcode{202502L} \\ \rowsep +\defnxname{cpp_trivial_union} & \tcode{202603L} \\ \rowsep \defnxname{cpp_unicode_characters} & \tcode{200704L} \\ \rowsep \defnxname{cpp_unicode_literals} & \tcode{200710L} \\ \rowsep \defnxname{cpp_user_defined_literals} & \tcode{200809L} \\ \rowsep @@ -2446,7 +2489,7 @@ \item \indextext{__stdcpp_threads__@\mname{STDCPP_THREADS}}% \mname{STDCPP_THREADS}\\ -Defined, and has the value integer literal 1, if and only if a program +Defined, and has the value integer literal \tcode{1}, if and only if a program can have more than one thread of execution\iref{intro.multithread}. \end{description} diff --git a/source/ranges.tex b/source/ranges.tex index 6d8022e929..eb12aa773f 100644 --- a/source/ranges.tex +++ b/source/ranges.tex @@ -562,16 +562,16 @@ namespace views { inline constexpr @\unspec@ cache_latest = @\unspec@; } - // \ref{range.to.input}, to input view + // \ref{range.as.input}, as input view template<@\libconcept{input_range}@ V> requires @\libconcept{view}@ - class to_input_view; + class as_input_view; template - constexpr bool enable_borrowed_range> = + constexpr bool enable_borrowed_range> = enable_borrowed_range; - namespace views { inline constexpr @\unspec@ to_input = @\unspec@; } + namespace views { inline constexpr @\unspec@ as_input = @\unspec@; } } namespace std { @@ -1409,7 +1409,7 @@ Pursuant to \ref{namespace.std}, users may specialize \tcode{enable_borrowed_range} for cv-unqualified program-defined types. Such specializations shall be -usable in constant expressions\iref{expr.const} and +usable in constant expressions\iref{expr.const.init} and have type \tcode{const bool}. \pnum @@ -1518,7 +1518,7 @@ users may specialize \tcode{disable_sized_range} for cv-unqualified program-defined types. Such specializations shall -be usable in constant expressions\iref{expr.const} and +be usable in constant expressions\iref{expr.const.init} and have type \tcode{const bool}. \pnum @@ -1623,7 +1623,7 @@ for cv-unqualified program-defined types that model \libconcept{view}, and \tcode{false} for types that do not. Such specializations shall -be usable in constant expressions\iref{expr.const} and +be usable in constant expressions\iref{expr.const.init} and have type \tcode{const bool}. \end{itemdescr} @@ -3119,7 +3119,8 @@ requires @\exposconcept{weakly-equality-comparable-with}@ && @\libconcept{copyable}@ struct iota_view::@\exposid{iterator}@ { private: - W @\exposid{value_}@ = W(); // \expos + W @\exposid{value_}@ = W(); // \expos + constexpr explicit @\exposid{iterator}@(W value); // \expos public: using iterator_concept = @\seebelow@; @@ -3129,7 +3130,6 @@ using difference_type = @\placeholdernc{IOTA-DIFF-T}@(W); @\exposid{iterator}@() requires @\libconcept{default_initializable}@ = default; - constexpr explicit @\exposid{iterator}@(W value); constexpr W operator*() const noexcept(is_nothrow_copy_constructible_v); @@ -3500,11 +3500,11 @@ requires @\exposconcept{weakly-equality-comparable-with}@ && @\libconcept{copyable}@ struct iota_view::@\exposid{sentinel}@ { private: - Bound @\exposid{bound_}@ = Bound(); // \expos + Bound @\exposid{bound_}@ = Bound(); // \expos + constexpr explicit @\exposid{sentinel}@(Bound bound); // \expos public: @\exposid{sentinel}@() = default; - constexpr explicit @\exposid{sentinel}@(Bound bound); friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); @@ -4100,8 +4100,6 @@ using difference_type = ptrdiff_t; using value_type = Val; - constexpr explicit @\exposid{iterator}@(basic_istream_view& parent) noexcept; - @\exposid{iterator}@(const @\exposid{iterator}@&) = delete; @\exposid{iterator}@(@\exposid{iterator}@&&) = default; @@ -4116,7 +4114,8 @@ friend bool operator==(const @\exposid{iterator}@& x, default_sentinel_t); private: - basic_istream_view* @\exposid{parent_}@; // \expos + constexpr explicit @\exposid{iterator}@(basic_istream_view& parent) noexcept; // \expos + basic_istream_view* @\exposid{parent_}@; // \expos }; } \end{codeblock} @@ -4213,7 +4212,7 @@ \rSec2[range.adaptor.object]{Range adaptor objects} -\indexlibrarymisc{\idxcode{operator|}}{range adaptor closure objects}% +\indexlibrarymisc{\idxcode{operator"|}}{range adaptor closure objects}% \pnum A \defnadj{range adaptor closure}{object} is a unary function object that accepts a range argument. For @@ -4796,10 +4795,10 @@ @\exposidnc{movable-box}@ @\exposid{pred_}@; // \expos // \ref{range.filter.iterator}, class \tcode{filter_view::\exposid{iterator}} - class @\exposid{iterator}@; // \expos + template class @\exposid{iterator}@; // \expos // \ref{range.filter.sentinel}, class \tcode{filter_view::\exposid{sentinel}} - class @\exposid{sentinel}@; // \expos + template class @\exposid{sentinel}@; // \expos public: filter_view() requires @\libconcept{default_initializable}@ && @\libconcept{default_initializable}@ = default; @@ -4810,12 +4809,21 @@ constexpr const Pred& pred() const; - constexpr @\exposid{iterator}@ begin(); + constexpr @\exposid{iterator}@ begin(); + constexpr @\exposid{iterator}@ begin() const + requires (@\libconcept{input_range}@ && !@\libconcept{forward_range}@ && + @\libconcept{indirect_unary_predicate}@>); + constexpr auto end() { if constexpr (@\libconcept{common_range}@) - return @\exposid{iterator}@{*this, ranges::end(@\exposid{base_}@)}; + return @\exposid{iterator}@{*this, ranges::end(@\exposid{base_}@)}; else - return @\exposid{sentinel}@{*this}; + return @\exposid{sentinel}@{*this}; + } + constexpr @\exposid{sentinel}@ end() const + requires (@\libconcept{input_range}@ && !@\libconcept{forward_range}@ && + @\libconcept{indirect_unary_predicate}@>) { + return @\exposid{sentinel}@{*this}; } }; @@ -4849,7 +4857,7 @@ \indexlibrarymember{begin}{filter_view}% \begin{itemdecl} -constexpr @\exposid{iterator}@ begin(); +constexpr @\exposid{iterator}@ begin(); \end{itemdecl} \begin{itemdescr} @@ -4870,7 +4878,27 @@ \tcode{filter_view} for use on subsequent calls. \end{itemdescr} -\rSec3[range.filter.iterator]{Class \tcode{filter_view::\exposid{iterator}}} +\indexlibrarymember{begin}{filter_view}% +\begin{itemdecl} +constexpr @\exposid{iterator}@ begin() const + requires (@\libconcept{input_range}@ && !@\libconcept{forward_range}@ && + @\libconcept{indirect_unary_predicate}@>); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{\exposid{pred_}.has_value()} is \tcode{true}. + +\pnum +\returns +\tcode{\{*this, ranges::find_if(\exposid{base_}, ref(*\exposid{pred_}))\}}. +\begin{note} +This function does not cache the result within the \tcode{filter_view}. +\end{note} +\end{itemdescr} + +\rSec3[range.filter.iterator]{Class template \tcode{filter_view::\exposid{iterator}}} \indexlibraryglobal{filter_view::\exposid{iterator}}% \indexlibrarymember{iterator}{filter_view}% @@ -4878,55 +4906,67 @@ namespace std::ranges { template<@\libconcept{input_range}@ V, @\libconcept{indirect_unary_predicate}@> Pred> requires @\libconcept{view}@ && is_object_v + template class filter_view::@\exposid{iterator}@ { private: - iterator_t @\exposid{current_}@ = iterator_t(); // \expos - filter_view* @\exposid{parent_}@ = nullptr; // \expos + using @\exposidnc{Parent}@ = @\exposidnc{maybe-const}@; // \expos + using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos + iterator_t<@\exposidnc{Base}@> @\exposid{current_}@ = iterator_t<@\exposidnc{Base}@>(); // \expos + @\exposidnc{Parent}@* @\exposid{parent_}@ = nullptr; // \expos + constexpr @\exposidnc{iterator}@(@\exposidnc{Parent}@& parent, iterator_t<@\exposidnc{Base}@> current); // \expos public: using iterator_concept = @\seebelownc@; - using iterator_category = @\seebelownc@; // not always present - using value_type = range_value_t; - using difference_type = range_difference_t; + using iterator_category = @\seebelownc@; // not always present + using value_type = range_value_t<@\exposidnc{Base}@>; + using difference_type = range_difference_t<@\exposidnc{Base}@>; - @\exposid{iterator}@() requires @\libconcept{default_initializable}@> = default; - constexpr @\exposid{iterator}@(filter_view& parent, iterator_t current); + @\exposid{iterator}@() requires @\libconcept{default_initializable}@> = default; + constexpr @\exposid{iterator}@(iterator i) + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposidnc{Base}@>>; - constexpr const iterator_t& base() const & noexcept; - constexpr iterator_t base() &&; - constexpr range_reference_t operator*() const; - constexpr iterator_t operator->() const - requires @\exposconcept{has-arrow}@> && @\libconcept{copyable}@>; + constexpr const iterator_t<@\exposidnc{Base}@>& base() const & noexcept; + constexpr iterator_t<@\exposidnc{Base}@> base() &&; + constexpr range_reference_t<@\exposidnc{Base}@> operator*() const; + constexpr iterator_t<@\exposidnc{Base}@> operator->() const + requires @\exposconcept{has-arrow}@> && @\libconcept{copyable}@>; constexpr @\exposid{iterator}@& operator++(); constexpr void operator++(int); - constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@; + constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposidnc{Base}@>; - constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@; - constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@; + constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposidnc{Base}@>; + constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposidnc{Base}@>; friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{equality_comparable}@>; + requires @\libconcept{equality_comparable}@>; - friend constexpr range_rvalue_reference_t iter_move(const @\exposid{iterator}@& i) + friend constexpr range_rvalue_reference_t<@\exposidnc{Base}@> iter_move(const @\exposid{iterator}@& i) noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@))); friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) noexcept(noexcept(ranges::iter_swap(x.@\exposid{current_}@, y.@\exposid{current_}@))) - requires @\libconcept{indirectly_swappable}@>; + requires @\libconcept{indirectly_swappable}@>; }; } \end{codeblock} \pnum -Modification of the element a \tcode{filter_view::\exposid{iterator}} denotes is -permitted, but results in undefined behavior if the resulting value does not -satisfy the filter predicate. +\begin{note} +Modification of the element a \tcode{filter_view::\exposid{iterator}} denotes +can result in undefined behavior +if the underlying range is a \libconcept{forward_range} and +the resulting value does not satisfy the filter predicate +when the predicate is next evaluated for that element\iref{concepts.equality}. +\end{note} \pnum \tcode{\exposid{iterator}::iterator_concept} is defined as follows: \begin{itemize} -\item If \tcode{V} models \libconcept{bidirectional_range}, then +\item If \tcode{Const} is \tcode{true}, +then \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. + +\item Otherwise, if \tcode{V} models \libconcept{bidirectional_range}, then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. \item Otherwise, if \tcode{V} models \libconcept{forward_range}, then @@ -4937,12 +4977,12 @@ \pnum The member \grammarterm{typedef-name} \tcode{iterator_category} is declared -if and only if \tcode{V} models \libconcept{forward_range}. +if and only if \exposid{Base} models \libconcept{forward_range}. In that case, \tcode{\exposid{iterator}::iterator_category} is defined as follows: \begin{itemize} \item Let \tcode{C} denote the type -\tcode{iterator_traits>::iterator_category}. +\tcode{iterator_traits>::iterator_category}. \item If \tcode{C} models \tcode{\libconcept{derived_from}}, @@ -4957,7 +4997,7 @@ \indexlibraryctor{filter_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@(filter_view& parent, iterator_t current); +constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, iterator_t<@\exposid{Base}@> current); \end{itemdecl} \begin{itemdescr} @@ -4967,9 +5007,22 @@ \exposid{parent_} with \tcode{addressof(parent)}. \end{itemdescr} +\indexlibraryctor{filter_view::\exposid{iterator}}% +\begin{itemdecl} +constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) + requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{parent_} with \tcode{i.\exposid{parent_}} and +\exposid{current_} with \tcode{std::move(i.\exposid{current_})}. +\end{itemdescr} + \indexlibrarymember{base}{filter_view::\exposid{iterator}}% \begin{itemdecl} -constexpr const iterator_t& base() const & noexcept; +constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; \end{itemdecl} \begin{itemdescr} @@ -4980,7 +5033,7 @@ \indexlibrarymember{base}{filter_view::\exposid{iterator}}% \begin{itemdecl} -constexpr iterator_t base() &&; +constexpr iterator_t<@\exposid{Base}@> base() &&; \end{itemdecl} \begin{itemdescr} @@ -4991,7 +5044,7 @@ \indexlibrarymember{operator*}{filter_view::\exposid{iterator}}% \begin{itemdecl} -constexpr range_reference_t operator*() const; +constexpr range_reference_t<@\exposid{Base}@> operator*() const; \end{itemdecl} \begin{itemdescr} @@ -5002,8 +5055,8 @@ \indexlibrarymember{operator->}{filter_view::\exposid{iterator}}% \begin{itemdecl} -constexpr iterator_t operator->() const - requires @\exposconcept{has-arrow}@> && @\libconcept{copyable}@>; +constexpr iterator_t<@\exposid{Base}@> operator->() const + requires @\exposconcept{has-arrow}@> && @\libconcept{copyable}@>; \end{itemdecl} \begin{itemdescr} @@ -5041,7 +5094,7 @@ \indexlibrarymember{operator++}{filter_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@; +constexpr @\exposid{iterator}@ operator++(int) requires @\libconcept{forward_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -5057,7 +5110,7 @@ \indexlibrarymember{operator--}{filter_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@; +constexpr @\exposid{iterator}@& operator--() requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -5074,7 +5127,7 @@ \indexlibrarymember{operator--}{filter_view::\exposid{iterator}}% \begin{itemdecl} -constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@; +constexpr @\exposid{iterator}@ operator--(int) requires @\libconcept{bidirectional_range}@<@\exposid{Base}@>; \end{itemdecl} \begin{itemdescr} @@ -5091,7 +5144,7 @@ \indexlibrarymember{operator==}{filter_view::\exposid{iterator}}% \begin{itemdecl} friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) - requires @\libconcept{equality_comparable}@>; + requires @\libconcept{equality_comparable}@>; \end{itemdecl} \begin{itemdescr} @@ -5102,7 +5155,7 @@ \indexlibrarymember{iter_move}{filter_view::\exposid{iterator}}% \begin{itemdecl} -friend constexpr range_rvalue_reference_t iter_move(const @\exposid{iterator}@& i) +friend constexpr range_rvalue_reference_t<@\exposid{Base}@> iter_move(const @\exposid{iterator}@& i) noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@))); \end{itemdecl} @@ -5116,7 +5169,7 @@ \begin{itemdecl} friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) noexcept(noexcept(ranges::iter_swap(x.@\exposid{current_}@, y.@\exposid{current_}@))) - requires @\libconcept{indirectly_swappable}@>; + requires @\libconcept{indirectly_swappable}@>; \end{itemdecl} \begin{itemdescr} @@ -5125,7 +5178,7 @@ Equivalent to \tcode{ranges::iter_swap(x.\exposid{current_}, y.\exposid{current_})}. \end{itemdescr} -\rSec3[range.filter.sentinel]{Class \tcode{filter_view::\exposid{sentinel}}} +\rSec3[range.filter.sentinel]{Class template \tcode{filter_view::\exposid{sentinel}}} \indexlibraryglobal{filter_view::\exposid{sentinel}}% \indexlibrarymember{sentinel}{filter_view}% @@ -5133,24 +5186,42 @@ namespace std::ranges { template<@\libconcept{input_range}@ V, @\libconcept{indirect_unary_predicate}@> Pred> requires @\libconcept{view}@ && is_object_v + template class filter_view::@\exposid{sentinel}@ { private: - sentinel_t @\exposid{end_}@ = sentinel_t(); // \expos + using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos + sentinel_t<@\exposidnc{Base}@> @\exposid{end_}@ = sentinel_t<@\exposidnc{Base}@>(); // \expos + constexpr explicit @\exposidnc{sentinel}@(@\exposidnc{Parent}@& parent); // \expos public: @\exposid{sentinel}@() = default; - constexpr explicit @\exposid{sentinel}@(filter_view& parent); + constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ other) + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposidnc{Base}@>> - constexpr sentinel_t base() const; + constexpr sentinel_t<@\exposidnc{Base}@> base() const; - friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); + template + requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@>> + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); }; } \end{codeblock} \indexlibraryctor{filter_view::\exposid{sentinel}}% \begin{itemdecl} -constexpr explicit @\exposid{sentinel}@(filter_view& parent); +constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ other) + requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposidnc{Base}@>>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{end_} with \tcode{std::move(other.\exposid{end_})}. +\end{itemdescr} + +\indexlibraryctor{filter_view::\exposid{sentinel}}% +\begin{itemdecl} +constexpr explicit @\exposid{sentinel}@(@\exposid{Parent}@& parent); \end{itemdecl} \begin{itemdescr} @@ -5161,7 +5232,7 @@ \indexlibrarymember{base}{filter_view::\exposid{sentinel}}% \begin{itemdecl} -constexpr sentinel_t base() const; +constexpr sentinel_t<@\exposidnc{Base}@> base() const; \end{itemdecl} \begin{itemdescr} @@ -5172,7 +5243,9 @@ \indexlibrarymember{operator==}{filter_view::\exposid{sentinel}}% \begin{itemdecl} -friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); +template + requires @\libconcept{sentinel_for}@, iterator_t<@\exposid{maybe-const}@ >> + friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); \end{itemdecl} \begin{itemdescr} @@ -5380,10 +5453,11 @@ template class transform_view::@\exposid{iterator}@ { private: - using @\exposidnc{Parent}@ = @\exposidnc{maybe-const}@; // \expos - using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos - iterator_t<@\exposidnc{Base}@> @\exposid{current_}@ = iterator_t<@\exposidnc{Base}@>(); // \expos - @\exposidnc{Parent}@* @\exposid{parent_}@ = nullptr; // \expos + using @\exposidnc{Parent}@ = @\exposidnc{maybe-const}@; // \expos + using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos + iterator_t<@\exposidnc{Base}@> @\exposid{current_}@ = iterator_t<@\exposidnc{Base}@>(); // \expos + @\exposidnc{Parent}@* @\exposid{parent_}@ = nullptr; // \expos + constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, iterator_t<@\exposidnc{Base}@> current); // \expos public: using iterator_concept = @\seebelownc@; @@ -5393,7 +5467,6 @@ using difference_type = range_difference_t<@\exposid{Base}@>; @\exposid{iterator}@() requires @\libconcept{default_initializable}@> = default; - constexpr @\exposid{iterator}@(@\exposid{Parent}@& parent, iterator_t<@\exposid{Base}@> current); constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; @@ -5767,10 +5840,10 @@ using @\exposid{Parent}@ = @\exposid{maybe-const}@; // \expos using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos sentinel_t<@\exposid{Base}@> @\exposid{end_}@ = sentinel_t<@\exposid{Base}@>(); // \expos + constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); // \expos public: @\exposid{sentinel}@() = default; - constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ i) requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; @@ -6109,10 +6182,10 @@ template using @\exposid{CI}@ = counted_iterator>>; // \expos sentinel_t<@\exposid{Base}@> @\exposid{end_}@ = sentinel_t<@\exposid{Base}@>(); // \expos + constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); // \expos public: @\exposid{sentinel}@() = default; - constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ s) requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; @@ -6292,14 +6365,14 @@ @\libconcept{indirect_unary_predicate}@> template class take_while_view::@\exposidnc{sentinel}@ { - using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos + using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos - sentinel_t<@\exposidnc{Base}@> @\exposid{end_}@ = sentinel_t<@\exposidnc{Base}@>(); // \expos - const Pred* @\exposid{pred_}@ = nullptr; // \expos + sentinel_t<@\exposidnc{Base}@> @\exposid{end_}@ = sentinel_t<@\exposidnc{Base}@>(); // \expos + const Pred* @\exposid{pred_}@ = nullptr; // \expos + constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end, const Pred* pred); // \expos public: @\exposid{sentinel}@() = default; - constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end, const Pred* pred); constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ s) requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; @@ -7152,11 +7225,11 @@ using @\exposid{Parent}@ = @\exposid{maybe-const}@; // \expos using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos sentinel_t<@\exposid{Base}@> @\exposid{end_}@ = sentinel_t<@\exposid{Base}@>(); // \expos + constexpr explicit @\exposid{sentinel}@(@\exposid{Parent}@& parent); // \expos public: @\exposid{sentinel}@() = default; - constexpr explicit @\exposid{sentinel}@(@\exposid{Parent}@& parent); constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ s) requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; @@ -7925,7 +7998,8 @@ } } - constexpr auto begin() const requires @\libconcept{forward_range}@ && @\libconcept{forward_range}@ { + constexpr auto begin() const requires @\libconcept{forward_range}@ && @\libconcept{forward_range}@ && + @\libconcept{forward_range}@ { return @\exposid{outer-iterator}@{*this, ranges::begin(@\exposid{base_}@)}; } @@ -7935,7 +8009,8 @@ } constexpr auto end() const { - if constexpr (@\libconcept{forward_range}@ && @\libconcept{forward_range}@ && @\libconcept{common_range}@) + if constexpr (@\libconcept{forward_range}@ && @\libconcept{forward_range}@ && @\libconcept{common_range}@ && + @\libconcept{forward_range}@) return @\exposid{outer-iterator}@{*this, ranges::end(@\exposid{base_}@)}; else return default_sentinel; @@ -7998,6 +8073,10 @@ // if \tcode{V} models \libconcept{forward_range} bool @\exposid{trailing_empty_}@ = false; // \expos + constexpr explicit @\exposid{outer-iterator}@(@\exposid{Parent}@& parent) // \expos + requires (!@\libconcept{forward_range}@<@\exposid{Base}@>); + constexpr @\exposid{outer-iterator}@(@\exposid{Parent}@& parent, iterator_t<@\exposid{Base}@> current) // \expos + requires @\libconcept{forward_range}@<@\exposid{Base}@>; public: using iterator_concept = @@ -8011,10 +8090,6 @@ using difference_type = range_difference_t<@\exposid{Base}@>; @\exposid{outer-iterator}@() = default; - constexpr explicit @\exposid{outer-iterator}@(@\exposid{Parent}@& parent) - requires (!@\libconcept{forward_range}@<@\exposid{Base}@>); - constexpr @\exposid{outer-iterator}@(@\exposid{Parent}@& parent, iterator_t<@\exposid{Base}@> current) - requires @\libconcept{forward_range}@<@\exposid{Base}@>; constexpr @\exposid{outer-iterator}@(@\exposid{outer-iterator}@ i) requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; @@ -8232,9 +8307,10 @@ template struct lazy_split_view::@\exposid{inner-iterator}@ { private: - using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos - @\exposidnc{outer-iterator}@ @\exposid{i_}@ = @\exposidnc{outer-iterator}@(); // \expos - bool @\exposid{incremented_}@ = false; // \expos + using @\exposidnc{Base}@ = @\exposidnc{maybe-const}@; // \expos + @\exposidnc{outer-iterator}@ @\exposid{i_}@ = @\exposidnc{outer-iterator}@(); // \expos + bool @\exposid{incremented_}@ = false; // \expos + constexpr explicit @\exposid{inner-iterator}@(@\exposidnc{outer-iterator}@ i); // \expos public: using iterator_concept = @\exposid{outer-iterator}@::iterator_concept; @@ -8245,7 +8321,6 @@ using difference_type = range_difference_t<@\exposid{Base}@>; @\exposid{inner-iterator}@() = default; - constexpr explicit @\exposid{inner-iterator}@(@\exposid{outer-iterator}@ i); constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; constexpr iterator_t<@\exposid{Base}@> base() && requires @\libconcept{forward_range}@; @@ -8556,10 +8631,12 @@ @\libconcept{indirectly_comparable}@, iterator_t, ranges::equal_to> class split_view::@\exposid{iterator}@ { private: - split_view* @\exposid{parent_}@ = nullptr; // \expos - iterator_t @\exposid{cur_}@ = iterator_t(); // \expos - subrange> @\exposid{next_}@ = subrange>(); // \expos - bool @\exposid{trailing_empty_}@ = false; // \expos + split_view* @\exposid{parent_}@ = nullptr; // \expos + iterator_t @\exposid{cur_}@ = iterator_t(); // \expos + subrange> @\exposid{next_}@ = subrange>(); // \expos + bool @\exposid{trailing_empty_}@ = false; // \expos + constexpr @\exposid{iterator}@(split_view& parent, iterator_t current, // \expos + subrange> next); public: using iterator_concept = forward_iterator_tag; @@ -8568,7 +8645,6 @@ using difference_type = range_difference_t; @\exposid{iterator}@() = default; - constexpr @\exposid{iterator}@(split_view& parent, iterator_t current, subrange> next); constexpr iterator_t base() const; constexpr value_type operator*() const; @@ -8683,10 +8759,10 @@ struct split_view::@\exposid{sentinel}@ { private: sentinel_t @\exposid{end_}@ = sentinel_t(); // \expos + constexpr explicit @\exposid{sentinel}@(split_view& parent); // \expos public: @\exposid{sentinel}@() = default; - constexpr explicit @\exposid{sentinel}@(split_view& parent); friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{sentinel}@& y); }; @@ -8789,6 +8865,8 @@ constexpr auto size() requires (@\libconcept{sized_range}@ && ...); constexpr auto size() const requires (@\libconcept{sized_range}@ && ...); + constexpr auto reserve_hint() requires (@\libconcept{approximately_sized_range}@ && ...); + constexpr auto reserve_hint() const requires (@\libconcept{approximately_sized_range}@ && ...); }; template @@ -8961,6 +9039,26 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{reserve_hint}{concat_view}% +\begin{itemdecl} +constexpr auto reserve_hint() requires (@\libconcept{approximately_sized_range}@ && ...); +constexpr auto reserve_hint() const requires (@\libconcept{approximately_sized_range}@ && ...); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return apply( + [](auto... sizes) { + using CT = @\exposid{make-unsigned-like-t}@>; + return (CT(sizes) + ...); + }, + @\exposid{tuple-transform}@(ranges::reserve_hint, @\exposid{views_}@)); +\end{codeblock} +\end{itemdescr} + \rSec3[range.concat.iterator]{Class \tcode{concat_view::\exposid{iterator}}} \indexlibrarymember{iterator}{concat_view}% @@ -8972,7 +9070,6 @@ @\exposconcept{concatable}@ template class concat_view::@\exposid{iterator}@ { - public: using iterator_category = @\seebelow@; // not always present using iterator_concept = @\seebelow@; @@ -10235,7 +10332,10 @@ namespace std::ranges { template concept @\defexposconcept{has-tuple-element}@ = // \expos - @\exposconcept{tuple-like}@ && N < tuple_size_v; + @\exposconcept{tuple-like}@ && N < tuple_size_v && + requires(T t) { + { std::get(t) } -> @\libconcept{convertible_to}@&>; + }; template concept @\defexposconcept{returnable-element}@ = // \expos @@ -10322,6 +10422,7 @@ iterator_t<@\exposid{Base}@> @\exposid{current_}@ = iterator_t<@\exposid{Base}@>(); // \expos static constexpr decltype(auto) @\exposid{get-element}@(const iterator_t<@\exposid{Base}@>& i); // \expos + constexpr explicit @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current); // \expos public: using iterator_concept = @\seebelow@; @@ -10330,7 +10431,6 @@ using difference_type = range_difference_t<@\exposid{Base}@>; @\exposid{iterator}@() requires @\libconcept{default_initializable}@> = default; - constexpr explicit @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current); constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; @@ -10717,12 +10817,12 @@ template class elements_view::@\exposid{sentinel}@ { private: - using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos + using @\exposid{Base}@ = @\exposidnc{maybe-const}@; // \expos sentinel_t<@\exposid{Base}@> @\exposid{end_}@ = sentinel_t<@\exposid{Base}@>(); // \expos + constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); // \expos public: @\exposid{sentinel}@() = default; - constexpr explicit @\exposid{sentinel}@(sentinel_t<@\exposid{Base}@> end); constexpr @\exposid{sentinel}@(@\exposid{sentinel}@ other) requires Const && @\libconcept{convertible_to}@, sentinel_t<@\exposid{Base}@>>; @@ -17752,12 +17852,12 @@ \tcode{x.\exposid{end_} - y.\exposid{current_}}. \end{itemdescr} -\rSec2[range.to.input]{To input view} +\rSec2[range.as.input]{As input view} -\rSec3[range.to.input.overview]{Overview} +\rSec3[range.as.input.overview]{Overview} \pnum -\tcode{to_input_view} presents a view of an underlying sequence +\tcode{as_input_view} presents a view of an underlying sequence as an input-only non-common range. \begin{note} This is useful to avoid overhead @@ -17766,10 +17866,10 @@ \end{note} \pnum -The name \tcode{views::to_input} denotes +The name \tcode{views::as_input} denotes a range adaptor object\iref{range.adaptor.object}. Let \tcode{E} be an expression and let \tcode{T} be \tcode{decltype((E))}. -The expression \tcode{views::to_input(E)} is expression-equivalent to: +The expression \tcode{views::as_input(E)} is expression-equivalent to: \begin{itemize} \item \tcode{views::all(E)} @@ -17777,25 +17877,25 @@ does not satisfy \libconcept{common_range}, and does not satisfy \libconcept{forward_range}. \item -Otherwise, \tcode{to_input_view(E)}. +Otherwise, \tcode{as_input_view(E)}. \end{itemize} -\rSec3[range.to.input.view]{Class template \tcode{to_input_view}} +\rSec3[range.as.input.view]{Class template \tcode{as_input_view}} -\indexlibraryglobal{to_input_view}% +\indexlibraryglobal{as_input_view}% \begin{codeblock} namespace std::ranges { template<@\libconcept{input_range}@ V> requires @\libconcept{view}@ - class to_input_view : public view_interface> { + class as_input_view : public view_interface> { V @\exposid{base_}@ = V(); // \expos - // \ref{range.to.input.iterator}, class template \tcode{to_input_view::\exposid{iterator}} + // \ref{range.as.input.iterator}, class template \tcode{as_input_view::\exposid{iterator}} template class @\exposid{iterator}@; // \expos public: - to_input_view() requires @\libconcept{default_initializable}@ = default; - constexpr explicit to_input_view(V base); + as_input_view() requires @\libconcept{default_initializable}@ = default; + constexpr explicit as_input_view(V base); constexpr V base() const & requires @\libconcept{copy_constructible}@ { return @\exposid{base_}@; } constexpr V base() && { return std::move(@\exposid{base_}@); } @@ -17814,13 +17914,13 @@ }; template - to_input_view(R&&) -> to_input_view>; + as_input_view(R&&) -> as_input_view>; } \end{codeblock} -\indexlibraryctor{to_input_view}% +\indexlibraryctor{as_input_view}% \begin{itemdecl} -constexpr explicit to_input_view(V base); +constexpr explicit as_input_view(V base); \end{itemdecl} \begin{itemdescr} @@ -17829,7 +17929,7 @@ Initializes \exposid{base_} with \tcode{std::move(base)}. \end{itemdescr} -\indexlibrarymember{begin}{to_input_view}% +\indexlibrarymember{begin}{as_input_view}% \begin{itemdecl} constexpr auto begin() requires (!@\exposconcept{simple-view}@); \end{itemdecl} @@ -17840,7 +17940,7 @@ Equivalent to: \tcode{return \exposid{iterator}(ranges::begin(\exposid{base_}));} \end{itemdescr} -\indexlibrarymember{begin}{to_input_view}% +\indexlibrarymember{begin}{as_input_view}% \begin{itemdecl} constexpr auto begin() const requires @\libconcept{range}@; \end{itemdecl} @@ -17851,7 +17951,7 @@ Equivalent to: \tcode{return \exposid{iterator}(ranges::begin(\exposid{base_}));} \end{itemdescr} -\indexlibrarymember{end}{to_input_view}% +\indexlibrarymember{end}{as_input_view}% \begin{itemdecl} constexpr auto end() requires (!@\exposconcept{simple-view}@); constexpr auto end() const requires @\libconcept{range}@; @@ -17863,7 +17963,7 @@ Equivalent to: \tcode{return ranges::end(\exposid{base_});} \end{itemdescr} -\indexlibrarymember{size}{to_input_view}% +\indexlibrarymember{size}{as_input_view}% \begin{itemdecl} constexpr auto size() requires @\libconcept{sized_range}@; constexpr auto size() const requires @\libconcept{sized_range}@; @@ -17875,7 +17975,7 @@ Equivalent to: \tcode{return ranges::size(\exposid{base_});} \end{itemdescr} -\indexlibrarymember{reserve_hint}{to_input_view}% +\indexlibrarymember{reserve_hint}{as_input_view}% \begin{itemdecl} constexpr auto reserve_hint() requires @\libconcept{approximately_sized_range}@; constexpr auto reserve_hint() const requires @\libconcept{approximately_sized_range}@; @@ -17887,15 +17987,15 @@ Equivalent to: \tcode{return ranges::reserve_hint(\exposid{base_});} \end{itemdescr} -\rSec3[range.to.input.iterator]{Class template \tcode{to_input_view::\exposid{iterator}}} +\rSec3[range.as.input.iterator]{Class template \tcode{as_input_view::\exposid{iterator}}} -\indexlibraryglobal{to_input_view::\exposid{iterator}}% +\indexlibraryglobal{as_input_view::\exposid{iterator}}% \begin{codeblock} namespace std::ranges { template<@\libconcept{input_range}@ V> requires @\libconcept{view}@ template - class to_input_view::@\exposid{iterator}@ { + class as_input_view::@\exposid{iterator}@ { using @\exposid{Base}@ = @\exposid{maybe-const}@; // \expos iterator_t<@\exposid{Base}@> @\exposid{current_}@ = iterator_t<@\exposid{Base}@>(); // \expos @@ -17940,7 +18040,7 @@ } \end{codeblock} -\indexlibraryctor{to_input_view::\exposid{iterator}}% +\indexlibraryctor{as_input_view::\exposid{iterator}}% \begin{itemdecl} constexpr explicit @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current); \end{itemdecl} @@ -17951,7 +18051,7 @@ Initializes \exposid{current_} with \tcode{std::move(current)}. \end{itemdescr} -\indexlibraryctor{to_input_view::\exposid{iterator}}% +\indexlibraryctor{as_input_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@(@\exposid{iterator}@ i) requires Const && @\libconcept{convertible_to}@, iterator_t<@\exposid{Base}@>>; @@ -17963,7 +18063,7 @@ Initializes \exposid{current_} with \tcode{std::move(i.\exposid{current_})}. \end{itemdescr} -\indexlibrarymember{base}{to_input_view::\exposid{iterator}}% +\indexlibrarymember{base}{as_input_view::\exposid{iterator}}% \begin{itemdecl} constexpr iterator_t<@\exposid{Base}@> base() &&; \end{itemdecl} @@ -17974,7 +18074,7 @@ \tcode{std::move(\exposid{current_})}. \end{itemdescr} -\indexlibrarymember{base}{to_input_view::\exposid{iterator}}% +\indexlibrarymember{base}{as_input_view::\exposid{iterator}}% \begin{itemdecl} constexpr const iterator_t<@\exposid{Base}@>& base() const & noexcept; \end{itemdecl} @@ -17985,7 +18085,7 @@ \exposid{current_}. \end{itemdescr} -\indexlibrarymember{operator++}{to_input_view::\exposid{iterator}}% +\indexlibrarymember{operator++}{as_input_view::\exposid{iterator}}% \begin{itemdecl} constexpr @\exposid{iterator}@& operator++(); \end{itemdecl} @@ -18000,7 +18100,7 @@ \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator++}{to_input_view::\exposid{iterator}}% +\indexlibrarymember{operator++}{as_input_view::\exposid{iterator}}% \begin{itemdecl} constexpr void operator++(int); \end{itemdecl} @@ -18011,7 +18111,7 @@ Equivalent to: \tcode{++*this;} \end{itemdescr} -\indexlibrarymember{operator==}{to_input_view::\exposid{iterator}}% +\indexlibrarymember{operator==}{as_input_view::\exposid{iterator}}% \begin{itemdecl} friend constexpr bool operator==(const @\exposid{iterator}@& x, const sentinel_t<@\exposid{Base}@>& y); \end{itemdecl} @@ -18022,7 +18122,7 @@ \tcode{x.\exposid{current_} == y}. \end{itemdescr} -\indexlibrarymember{operator-}{to_input_view::\exposid{iterator}}% +\indexlibrarymember{operator-}{as_input_view::\exposid{iterator}}% \begin{itemdecl} friend constexpr difference_type operator-(const sentinel_t<@\exposid{Base}@>& y, const @\exposid{iterator}@& x) requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; @@ -18034,7 +18134,7 @@ \tcode{y - x.\exposid{current_}}. \end{itemdescr} -\indexlibrarymember{operator-}{to_input_view::\exposid{iterator}}% +\indexlibrarymember{operator-}{as_input_view::\exposid{iterator}}% \begin{itemdecl} friend constexpr difference_type operator-(const @\exposid{iterator}@& x, const sentinel_t<@\exposid{Base}@>& y) requires @\libconcept{sized_sentinel_for}@, iterator_t<@\exposid{Base}@>>; @@ -18046,7 +18146,7 @@ \tcode{x.\exposid{current_} - y}. \end{itemdescr} -\indexlibrarymember{iter_move}{to_input_view::\exposid{iterator}}% +\indexlibrarymember{iter_move}{as_input_view::\exposid{iterator}}% \begin{itemdecl} friend constexpr range_rvalue_reference_t<@\exposid{Base}@> iter_move(const @\exposid{iterator}@& i) noexcept(noexcept(ranges::iter_move(i.@\exposid{current_}@))); @@ -18058,7 +18158,7 @@ Equivalent to: \tcode{return ranges::iter_move(i.\exposid{current_});} \end{itemdescr} -\indexlibrarymember{iter_swap}{to_input_view::\exposid{iterator}}% +\indexlibrarymember{iter_swap}{as_input_view::\exposid{iterator}}% \begin{itemdecl} friend constexpr void iter_swap(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y) noexcept(noexcept(ranges::iter_swap(x.@\exposid{current_}@, y.@\exposid{current_}@))) diff --git a/source/statements.tex b/source/statements.tex index 8b9e733dc0..3742c06e8a 100644 --- a/source/statements.tex +++ b/source/statements.tex @@ -35,6 +35,11 @@ \begin{bnf} \nontermdef{condition}\br expression\br + condition-declaration +\end{bnf} + +\begin{bnf} +\nontermdef{condition-declaration}\br \opt{attribute-specifier-seq} decl-specifier-seq declarator brace-or-equal-initializer\br structured-binding-declaration initializer \end{bnf} @@ -143,15 +148,15 @@ \pnum If a \grammarterm{condition} can be syntactically resolved -as either an expression or a declaration, +as either an \grammarterm{expression} or a \grammarterm{condition-declaration}, it is interpreted as the latter. \pnum -Let $D$ be any \grammarterm{condition} or \grammarterm{for-range-declaration}. -In the \grammarterm{decl-specifier-seq} of $D$, +For any \grammarterm{condition} or \grammarterm{for-range-declaration} $D$, +each \grammarterm{decl-specifier} +in the \grammarterm{decl-specifier-seq} of $D$, including that of any \grammarterm{structured-binding-declaration} of $D$, -each -\grammarterm{decl-specifier} shall be either a \grammarterm{type-specifier} +shall be either a \grammarterm{type-specifier} or \keyword{constexpr}. \rSec1[stmt.label]{Label}% @@ -262,7 +267,6 @@ \pnum \begin{note} A compound statement defines a block scope\iref{basic.scope}. -A declaration is a \grammarterm{statement}\iref{stmt.dcl}. \end{note} \rSec1[stmt.select]{Selection statements}% @@ -320,7 +324,7 @@ If the \keyword{if} statement is of the form \tcode{if constexpr}, the value of the condition is contextually converted to \keyword{bool} and -the converted expression shall be a constant expression\iref{expr.const}; +the converted expression shall be a constant expression\iref{expr.const.const}; this form is called a \defn{constexpr if} statement. If the value of the converted condition is \tcode{false}, the first substatement is a @@ -405,7 +409,7 @@ \pnum If a consteval if statement is evaluated in a context -that is manifestly constant-evaluated\iref{expr.const}, +that is manifestly constant-evaluated\iref{expr.const.defns}, the first substatement is executed. \begin{note} The first substatement is an immediate function context. @@ -461,7 +465,7 @@ \keyword{case} constant-expression \terminal{:} \end{ncbnf} where the \grammarterm{constant-expression} shall be -a converted constant expression\iref{expr.const} of the +a converted constant expression\iref{expr.const.const} of the adjusted type of the switch condition. No two of the case constants in the same switch shall have the same value after conversion. @@ -584,7 +588,7 @@ (or \tcode{true}, if the \tcode{for} statement has no \grammarterm{expression}). A \defnadj{trivial infinite}{loop} is a trivially empty iteration statement for which the converted controlling expression is a constant expression, -when interpreted as a \grammarterm{constant-expression}\iref{expr.const}, and +when interpreted as a \grammarterm{constant-expression}\iref{expr.const.const}, and evaluates to \tcode{true}. The \grammarterm{statement} of a trivial infinite loop is replaced with a call to the function \tcode{std::this_thread::yield}\iref{thread.thread.this}; @@ -822,7 +826,7 @@ \tcode{E.begin()} and \tcode{E.end()}, or \item argument-dependent lookups for \tcode{begin(E)} and for \tcode{end(E)} -each find at least one function or function template. +each find at least one viable candidate\iref{over.match.viable}. \end{itemize} \pnum @@ -869,10 +873,8 @@ \begin{codeblock} { @\grammarterm{init-statement}@ - constexpr auto&& @\exposidnc{range}@ = @\grammarterm{expansion-initializer}@; - constexpr auto @\exposidnc{begin}@ = @\exposidnc{begin-expr}@; // see \ref{stmt.ranged} - constexpr auto @\exposidnc{end}@ = @\exposidnc{end-expr}@; // see \ref{stmt.ranged} - + @\opt{constexpr}@ decltype(auto) @\exposidnc{range}@ = (@\grammarterm{expansion-initializer}@); + @\opt{constexpr}@ auto @\exposidnc{begin}@ = @\exposidnc{begin-expr}@; // see \ref{stmt.ranged} @$S_{0}$@ @\vdots@ @$S_{N-1}$@ @@ -880,30 +882,34 @@ \end{codeblock} where $N$ is the result of evaluating the expression \begin{codeblock} -[] consteval { +[&] consteval { std::ptrdiff_t result = 0; - for (auto i = @\exposid{begin}@; i != @\exposid{end}@; ++i) ++result; + auto b = @\exposid{begin-expr}@; + auto e = @\exposid{end-expr}@; + for (; b != e; ++b) ++result; return result; // distance from \exposid{begin} to \exposid{end} }() \end{codeblock} and $S_{i}$ is \begin{codeblock} { - constexpr auto @\exposid{iter}@ = @\exposid{begin}@ + decltype(begin - begin){@\placeholder{i}@}; + @\opt{constexpr}@ auto @\exposid{iter}@ = @\exposid{begin}@ + decltype(begin - begin){@\placeholder{i}@}; @\grammarterm{for-range-declaration}@ = *@\exposid{iter}@; @\grammarterm{compound-statement}@ } \end{codeblock} -The variables \exposid{range}, \exposid{begin}, \exposid{end}, and \exposid{iter} +The variables \exposid{range}, \exposid{begin}, and \exposid{iter} are defined for exposition only. +The keyword \keyword{constexpr} is present in the declarations +of \exposid{range}, \exposid{begin}, and \exposid{iter} +if and only if +\keyword{constexpr} is one of the \grammarterm{decl-specifier}{s} of +the \grammarterm{decl-specifier-seq} of +the \grammarterm{for-range-declaration}. The identifier \tcode{\placeholder{i}} is considered to be a prvalue of type \tcode{std::ptrdiff_t}; the program is ill-formed if \tcode{\placeholder{i}} is not representable as such a value. -\begin{note} -The instantiation is ill-formed if \exposid{range} -is not a constant expression\iref{expr.const}. -\end{note} \item Otherwise, $S$ is a destructuring expansion statement and, @@ -928,11 +934,14 @@ of the \grammarterm{expansion-initializer} and $S_{i}$ is \begin{codeblock} { - @\grammarterm{for-range-declaration}@ = @$u_{i}$@; + @\grammarterm{for-range-declaration}@ = @$v_{i}$@; @\grammarterm{compound-statement}@ } \end{codeblock} -The keyword \keyword{constexpr} is present in the declaration +If the \grammarterm{expansion-initializer} is an lvalue, then +$v_{i}$ is $u_{i}$; +otherwise, $v_{i}$ is \tcode{static_cast($u_{i}$)}. +The keyword \keyword{constexpr} is present in the \grammarterm{structured-binding-declaration} of $u_{0}, u_{1}, \dotsc, u_{N-1}$ if and only if \keyword{constexpr} is one of the \grammarterm{decl-specifier}s of the \grammarterm{decl-specifier-seq} @@ -1121,7 +1130,7 @@ equivalent to a \tcode{return} with no operand. Otherwise, flowing off the end of a function that is neither \tcode{main}\iref{basic.start.main} nor a coroutine\iref{dcl.fct.def.coroutine} -results in undefined behavior. +results in undefined behavior\ubdef{stmt.return.flow.off}. \pnum The copy-initialization of the result of the call is sequenced before the @@ -1217,7 +1226,7 @@ flowing off the end of a coroutine's \grammarterm{function-body} is equivalent to a \keyword{co_return} with no operand; otherwise flowing off the end of a coroutine's \grammarterm{function-body} -results in undefined behavior. +results in undefined behavior\ubdef{stmt.return.coroutine.flow.off}. \rSec2[stmt.goto]{The \keyword{goto} statement}% \indextext{statement!\idxcode{goto}} @@ -1300,7 +1309,8 @@ after its \grammarterm{init-declarator}. \indextext{initialization!jump past}% \indextext{\idxcode{goto}!initialization and}% -Upon each transfer of control (including sequential execution of statements) +Upon each transfer of control (including sequential execution of statements, +but excluding function calls) within a function from point $P$ to point $Q$, all block variables with automatic storage duration that are active at $P$ and not at $Q$ are destroyed in the reverse order of their construction. @@ -1356,7 +1366,7 @@ \end{note} If control re-enters the declaration recursively while -the variable is being initialized, the behavior is undefined. +the variable is being initialized, the behavior is undefined\ubdef{stmt.dcl.local.static.init.recursive}. \begin{example} \begin{codeblock} int foo(int i) { @@ -1448,7 +1458,7 @@ that a name in a template argument is bound to (part of) the declaration being parsed, the program is ill-formed. -No diagnostic is required. +No diagnostic is required\ifndrdef{stmt.ambig.bound.diff.parse}. \begin{example} \begin{codeblock} struct T1 { @@ -1464,7 +1474,7 @@ T1(a) = 3, T2(4), // \tcode{T2} will be declared as a variable of type \tcode{T1}, but this will not (*(*b)(T2(c)))(int(d)); // allow the last part of the declaration to parse properly, - // since it depends on \tcode{T2} being a type-name + // since it depends on \tcode{T2} being a \grammarterm{type-name} } \end{codeblock} \end{example} diff --git a/source/std.tex b/source/std.tex index ab1d082396..7180e68e55 100644 --- a/source/std.tex +++ b/source/std.tex @@ -166,6 +166,8 @@ \include{limits} \include{compatibility} \include{future} +\include{ub} +\include{ifndr} \include{uax31} %%-------------------------------------------------- diff --git a/source/strings.tex b/source/strings.tex index 3bc1e0268a..b8619c9b4b 100644 --- a/source/strings.tex +++ b/source/strings.tex @@ -2014,6 +2014,8 @@ \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}. +The program has undefined behavior if +the null terminator is modified to any value other than \tcode{charT()}. \indexlibraryglobal{basic_string}% @@ -2151,6 +2153,7 @@ 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(const charT* s, size_type pos, size_type n); constexpr basic_string& append(size_type n, charT c); template constexpr basic_string& append(InputIterator first, InputIterator last); @@ -2171,6 +2174,7 @@ 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(const charT* s, size_type pos, size_type n); constexpr basic_string& assign(size_type n, charT c); template constexpr basic_string& assign(InputIterator first, InputIterator last); @@ -3101,10 +3105,7 @@ \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. +\tcode{data()[pos]}. \pnum \throws @@ -3354,6 +3355,18 @@ Equivalent to: \tcode{return append(s, traits::length(s));} \end{itemdescr} +\indexlibrarymember{append}{basic_string}% +\begin{itemdecl} +constexpr basic_string& append(const charT* s, size_type pos, size_type n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return append(basic_string_view(s).substr(pos, n));} +\end{itemdescr} + \indexlibrarymember{append}{basic_string}% \begin{itemdecl} constexpr basic_string& append(size_type n, charT c); @@ -3547,6 +3560,18 @@ Equivalent to: \tcode{return assign(s, traits::length(s));} \end{itemdescr} +\indexlibrarymember{assign}{basic_string}% +\begin{itemdecl} +constexpr basic_string& assign(const charT* s, size_type pos, size_type n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return assign(basic_string_view(s).substr(pos, n));} +\end{itemdescr} + \indexlibrarymember{assign}{basic_string}% \begin{itemdecl} constexpr basic_string& assign(initializer_list il); @@ -4291,42 +4316,17 @@ \begin{itemdecl} constexpr const charT* c_str() const noexcept; constexpr const charT* data() 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()}. - -\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}% -\begin{itemdecl} constexpr charT* data() 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()}. +\tcode{to_address(begin())}. \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}% @@ -4443,7 +4443,11 @@ Equivalent to: \begin{codeblock} basic_string_view s = *this, sv = t; -return s.@\placeholder{G}@(sv, pos); +if (auto result = s.@\placeholder{G}@(sv, pos); result == s.npos) { + return npos; +} else { + return result; +} \end{codeblock} \pnum diff --git a/source/support.tex b/source/support.tex index f4f632944b..e86cf14734 100644 --- a/source/support.tex +++ b/source/support.tex @@ -568,8 +568,8 @@ \begin{codeblock} #define @\defnlibxname{cpp_lib_adaptor_iterator_pair_constructor}@ 202106L // also in \libheader{stack}, \libheader{queue} #define @\defnlibxname{cpp_lib_addressof_constexpr}@ 201603L // freestanding, also in \libheader{memory} -#define @\defnlibxname{cpp_lib_algorithm_default_value_type}@ 202403L - // also in \libheader{algorithm}, \libheader{ranges}, \libheader{string}, \libheader{deque}, \libheader{list}, \libheader{forward_list}, \libheader{vector} +#define @\defnlibxname{cpp_lib_algorithm_default_value_type}@ 202603L + // also in \libheader{algorithm}, \libheader{ranges}, \libheader{string}, \libheader{deque}, \libheader{list}, \libheader{forward_list}, \libheader{vector}, \libheader{memory} #define @\defnlibxname{cpp_lib_algorithm_iterator_requirements}@ 202207L // also in \libheader{algorithm}, \libheader{numeric}, \libheader{memory} #define @\defnlibxname{cpp_lib_aligned_accessor}@ 202411L // freestanding, also in \libheader{mdspan} @@ -594,7 +594,7 @@ #define @\defnlibxname{cpp_lib_atomic_lock_free_type_aliases}@ 201907L // also in \libheader{atomic} #define @\defnlibxname{cpp_lib_atomic_min_max}@ 202506L // freestanding, also in \libheader{atomic} #define @\defnlibxname{cpp_lib_atomic_reductions}@ 202506L // freestanding, also in \libheader{atomic} -#define @\defnlibxname{cpp_lib_atomic_ref}@ 202411L // freestanding, also in \libheader{atomic} +#define @\defnlibxname{cpp_lib_atomic_ref}@ 202603L // freestanding, also in \libheader{atomic} #define @\defnlibxname{cpp_lib_atomic_shared_ptr}@ 201711L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_atomic_value_initialization}@ 201911L // freestanding, also in \libheader{atomic}, \libheader{memory} #define @\defnlibxname{cpp_lib_atomic_wait}@ 201907L // freestanding, also in \libheader{atomic} @@ -620,7 +620,7 @@ #define @\defnlibxname{cpp_lib_complex_udls}@ 201309L // also in \libheader{complex} #define @\defnlibxname{cpp_lib_concepts}@ 202207L // freestanding, also in \libheader{concepts}, \libheader{compare} -#define @\defnlibxname{cpp_lib_constant_wrapper}@ 202506L // freestanding, also in \libheader{type_traits} +#define @\defnlibxname{cpp_lib_constant_wrapper}@ 202603L // freestanding, also in \libheader{utility} #define @\defnlibxname{cpp_lib_constexpr_algorithms}@ 202306L // also in \libheader{algorithm}, \libheader{utility} #define @\defnlibxname{cpp_lib_constexpr_atomic}@ 202411L // also in \libheader{atomic} #define @\defnlibxname{cpp_lib_constexpr_bitset}@ 202207L // also in \libheader{bitset} @@ -671,14 +671,14 @@ #define @\defnlibxname{cpp_lib_erase_if}@ 202002L // also in \libheader{string}, \libheader{deque}, \libheader{forward_list}, \libheader{list}, \libheader{vector}, \libheader{map}, \libheader{set}, \libheader{unordered_map}, // \libheader{unordered_set} -#define @\defnlibxname{cpp_lib_exception_ptr_cast}@ 202506L // also in \libheader{exception} +#define @\defnlibxname{cpp_lib_exception_ptr_cast}@ 202603L // also in \libheader{exception} #define @\defnlibxname{cpp_lib_exchange_function}@ 201304L // freestanding, also in \libheader{utility} #define @\defnlibxname{cpp_lib_execution}@ 201902L // also in \libheader{execution} #define @\defnlibxname{cpp_lib_expected}@ 202211L // also in \libheader{expected} #define @\defnlibxname{cpp_lib_filesystem}@ 201703L // also in \libheader{filesystem} #define @\defnlibxname{cpp_lib_flat_map}@ 202511L // also in \libheader{flat_map} #define @\defnlibxname{cpp_lib_flat_set}@ 202511L // also in \libheader{flat_set} -#define @\defnlibxname{cpp_lib_format}@ 202311L // also in \libheader{format} +#define @\defnlibxname{cpp_lib_format}@ 202603L // also in \libheader{format} #define @\defnlibxname{cpp_lib_format_path}@ 202506L // also in \libheader{filesystem} #define @\defnlibxname{cpp_lib_format_ranges}@ 202207L // also in \libheader{format} #define @\defnlibxname{cpp_lib_format_uchar}@ 202311L // also in \libheader{format} @@ -711,7 +711,7 @@ #define @\defnlibxname{cpp_lib_freestanding_utility}@ 202306L // freestanding, also in \libheader{utility} #define @\defnlibxname{cpp_lib_freestanding_variant}@ 202311L // freestanding, also in \libheader{variant} #define @\defnlibxname{cpp_lib_fstream_native_handle}@ 202306L // also in \libheader{fstream} -#define @\defnlibxname{cpp_lib_function_ref}@ 202511L // freestanding, also in \libheader{functional} +#define @\defnlibxname{cpp_lib_function_ref}@ 202604L // freestanding, also in \libheader{functional} #define @\defnlibxname{cpp_lib_gcd_lcm}@ 201606L // freestanding, also in \libheader{numeric} #define @\defnlibxname{cpp_lib_generator}@ 202207L // also in \libheader{generator} #define @\defnlibxname{cpp_lib_generic_associative_lookup}@ 201304L // also in \libheader{map}, \libheader{set} @@ -727,7 +727,7 @@ #define @\defnlibxname{cpp_lib_indirect}@ 202502L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_initializer_list}@ 202511L // freestanding, also in \libheader{initializer_list} -#define @\defnlibxname{cpp_lib_inplace_vector}@ 202406L // also in \libheader{inplace_vector} +#define @\defnlibxname{cpp_lib_inplace_vector}@ 202603L // also in \libheader{inplace_vector} #define @\defnlibxname{cpp_lib_int_pow2}@ 202002L // freestanding, also in \libheader{bit} #define @\defnlibxname{cpp_lib_integer_comparison_functions}@ 202002L // freestanding, also in \libheader{utility} #define @\defnlibxname{cpp_lib_integer_sequence}@ 202511L // freestanding, also in \libheader{utility} @@ -746,10 +746,12 @@ #define @\defnlibxname{cpp_lib_is_null_pointer}@ 201309L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_pointer_interconvertible}@ 201907L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_scoped_enum}@ 202011L // freestanding, also in \libheader{type_traits} +#define @\defnlibxname{cpp_lib_is_structural}@ 202603L + // freestanding, also in \libheader{meta} and \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_sufficiently_aligned}@ 202411L // freestanding, also in \libheader{memory} #define @\defnlibxname{cpp_lib_is_swappable}@ 201603L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_is_virtual_base_of}@ 202406L // freestanding, also in \libheader{type_traits} -#define @\defnlibxname{cpp_lib_is_within_lifetime}@ 202306L // freestanding, also in \libheader{type_traits} +#define @\defnlibxname{cpp_lib_is_within_lifetime}@ 202603L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_jthread}@ 201911L // also in \libheader{stop_token}, \libheader{thread} #define @\defnlibxname{cpp_lib_latch}@ 201907L // also in \libheader{latch} #define @\defnlibxname{cpp_lib_launder}@ 201606L // freestanding, also in \libheader{new} @@ -789,6 +791,7 @@ #define @\defnlibxname{cpp_lib_ranges}@ 202406L // also in \libheader{algorithm}, \libheader{functional}, \libheader{iterator}, \libheader{memory}, \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_as_const}@ 202311L // freestanding, also in \libheader{ranges} +#define @\defnlibxname{cpp_lib_ranges_as_input}@ 202502L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_as_rvalue}@ 202207L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_cache_latest}@ 202411L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_cartesian_product}@ 202207L // freestanding, also in \libheader{ranges} @@ -797,6 +800,7 @@ #define @\defnlibxname{cpp_lib_ranges_concat}@ 202403L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_contains}@ 202207L // freestanding, also in \libheader{algorithm} #define @\defnlibxname{cpp_lib_ranges_enumerate}@ 202302L // freestanding, also in \libheader{ranges} +#define @\defnlibxname{cpp_lib_ranges_filter}@ 202603L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_find_last}@ 202207L // freestanding, also in \libheader{algorithm} #define @\defnlibxname{cpp_lib_ranges_fold}@ 202207L // freestanding, also in \libheader{algorithm} #define @\defnlibxname{cpp_lib_ranges_generate_random}@ 202403L // also in \libheader{random} @@ -809,7 +813,6 @@ #define @\defnlibxname{cpp_lib_ranges_starts_ends_with}@ 202106L // freestanding, also in \libheader{algorithm} #define @\defnlibxname{cpp_lib_ranges_stride}@ 202207L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_to_container}@ 202202L // freestanding, also in \libheader{ranges} -#define @\defnlibxname{cpp_lib_ranges_to_input}@ 202502L // freestanding, also in \libheader{ranges} #define @\defnlibxname{cpp_lib_ranges_zip}@ 202110L // freestanding, also in \libheader{ranges}, \libheader{tuple}, \libheader{utility} #define @\defnlibxname{cpp_lib_ratio}@ 202306L // freestanding, also in \libheader{ratio} @@ -817,13 +820,15 @@ #define @\defnlibxname{cpp_lib_rcu}@ 202306L // also in \libheader{rcu} #define @\defnlibxname{cpp_lib_reference_from_temporary}@ 202202L // freestanding, also in \libheader{type_traits} #define @\defnlibxname{cpp_lib_reference_wrapper}@ 202403L // freestanding, also in \libheader{functional} -#define @\defnlibxname{cpp_lib_reflection}@ 202506L // also in \libheader{meta} +#define @\defnlibxname{cpp_lib_reflection}@ 202603L // also in \libheader{meta} #define @\defnlibxname{cpp_lib_remove_cvref}@ 201711L // freestanding, also in \libheader{type_traits} +#define @\defnlibxname{cpp_lib_replaceable_contract_violation_handler}@ @\seebelow@ + // freestanding, also in \libheader{contracts} #define @\defnlibxname{cpp_lib_result_of_sfinae}@ 201210L // freestanding, also in \libheader{functional}, \libheader{type_traits} #define @\defnlibxname{cpp_lib_robust_nonmodifying_seq_ops}@ 201304L // freestanding, also in \libheader{algorithm} #define @\defnlibxname{cpp_lib_sample}@ 201603L // freestanding, also in \libheader{algorithm} -#define @\defnlibxname{cpp_lib_saturation_arithmetic}@ 202311L // freestanding, also in \libheader{numeric} +#define @\defnlibxname{cpp_lib_saturation_arithmetic}@ 202603L // freestanding, also in \libheader{numeric} #define @\defnlibxname{cpp_lib_scoped_lock}@ 201703L // also in \libheader{mutex} #define @\defnlibxname{cpp_lib_semaphore}@ 201907L // also in \libheader{semaphore} #define @\defnlibxname{cpp_lib_senders}@ 202506L // also in \libheader{execution} @@ -832,27 +837,29 @@ #define @\defnlibxname{cpp_lib_shared_ptr_weak_type}@ 201606L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_shared_timed_mutex}@ 201402L // also in \libheader{shared_mutex} #define @\defnlibxname{cpp_lib_shift}@ 202202L // also in \libheader{algorithm} -#define @\defnlibxname{cpp_lib_simd}@ 202511L // also in \libheader{simd} +#define @\defnlibxname{cpp_lib_simd}@ 202603L // also in \libheader{simd} #define @\defnlibxname{cpp_lib_simd_complex}@ 202502L // also in \libheader{simd} #define @\defnlibxname{cpp_lib_simd_permutations}@ 202506L // also in \libheader{simd} #define @\defnlibxname{cpp_lib_smart_ptr_for_overwrite}@ 202002L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_smart_ptr_owner_equality}@ 202306L // also in \libheader{memory} #define @\defnlibxname{cpp_lib_source_location}@ 201907L // freestanding, also in \libheader{source_location} #define @\defnlibxname{cpp_lib_span}@ 202311L // freestanding, also in \libheader{span} -#define @\defnlibxname{cpp_lib_span_initializer_list}@ 202311L // freestanding, also in \libheader{span} #define @\defnlibxname{cpp_lib_spanstream}@ 202106L // also in \libheader{iosfwd}, \libheader{spanstream} #define @\defnlibxname{cpp_lib_ssize}@ 201902L // freestanding, also in \libheader{iterator} #define @\defnlibxname{cpp_lib_sstream_from_string_view}@ 202306L // also in \libheader{sstream} #define @\defnlibxname{cpp_lib_stacktrace}@ 202011L // also in \libheader{stacktrace} +#define @\defnlibxname{cpp_lib_start_lifetime}@ 202603L // freestanding, also in \libheader{memory} #define @\defnlibxname{cpp_lib_start_lifetime_as}@ 202207L // freestanding, also in \libheader{memory} #define @\defnlibxname{cpp_lib_starts_ends_with}@ 201711L // also in \libheader{string}, \libheader{string_view} #define @\defnlibxname{cpp_lib_stdatomic_h}@ 202011L // also in \libheader{stdatomic.h} +#define @\defnlibxname{cpp_lib_stdbit_h}@ 202603L // also in \libheader{stdbit.h} +#define @\defnlibxname{cpp_lib_stdckdint_h}@ 202603L // also in \libheader{stdckdint.h} #define @\defnlibxname{cpp_lib_string_contains}@ 202011L // also in \libheader{string}, \libheader{string_view} #define @\defnlibxname{cpp_lib_string_resize_and_overwrite}@ 202110L // also in \libheader{string} #define @\defnlibxname{cpp_lib_string_subview}@ 202506L // also in \libheader{string}, \libheader{string_view} #define @\defnlibxname{cpp_lib_string_udls}@ 201304L // also in \libheader{string} #define @\defnlibxname{cpp_lib_string_view}@ 202403L // also in \libheader{string}, \libheader{string_view} -#define @\defnlibxname{cpp_lib_submdspan}@ 202511L // freestanding, also in \libheader{mdspan} +#define @\defnlibxname{cpp_lib_submdspan}@ 202603L // freestanding, also in \libheader{mdspan} #define @\defnlibxname{cpp_lib_syncbuf}@ 201803L // also in \libheader{iosfwd}, \libheader{syncstream} #define @\defnlibxname{cpp_lib_task}@ 202506L // also in \libheader{execution} #define @\defnlibxname{cpp_lib_text_encoding}@ 202306L // also in \libheader{text_encoding} @@ -912,6 +919,12 @@ the requirements of a hosted implementation, and to the integer literal \tcode{0} otherwise\iref{new.delete}. +\pnum +The macro \xname{cpp_lib_replaceable_contract_violation_handler} is defined to +the integer literal \tcode{202603L} +if the contract-violation handler is replaceable, and +to the integer literal \tcode{0} otherwise\iref{basic.contract.handler}. + \pnum \recommended Freestanding implementations should only define a macro from \libheader{version} @@ -997,7 +1010,9 @@ \item \indexlibraryglobal{round_to_nearest}% \tcode{round_to_nearest} -if the rounding style is to the nearest representable value +if the rounding style is to the nearest representable value; +if there are two equally near such values, +the one with an even least significant digit is chosen \item \indexlibraryglobal{round_toward_infinity}% \tcode{round_toward_infinity} @@ -1110,11 +1125,6 @@ \pnum \indextext{signal-safe!\idxcode{numeric_limits} members}% Each member function defined in this subclause is signal-safe\iref{support.signal}. -\begin{note} -\indextext{LIA-1}% -The arithmetic specification described in ISO/IEC 10967-1:2012 is -commonly termed LIA-1. -\end{note} \indexlibrarymember{min}{numeric_limits}% \begin{itemdecl} @@ -1324,10 +1334,6 @@ \begin{itemdescr} \pnum Measure of the maximum rounding error. -\begin{footnote} -Rounding error is described in ISO/IEC 10967-1:2012 Section 5.2.4 and -Annex C Rationale Section C.5.2.4 --- Rounding and rounding constants. -\end{footnote} \end{itemdescr} \indexlibrarymember{min_exponent}{numeric_limits}% @@ -1434,9 +1440,6 @@ \pnum \tcode{true} if the type has a representation for a quiet (non-signaling) ``Not a Number''. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} \pnum Meaningful for all floating-point types. @@ -1456,9 +1459,6 @@ \begin{itemdescr} \pnum \tcode{true} if the type has a representation for a signaling ``Not a Number''. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} \pnum Meaningful for all floating-point types. @@ -1478,9 +1478,6 @@ \begin{itemdescr} \pnum Representation of positive infinity, if available. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} \pnum Meaningful for all specializations for which @@ -1497,9 +1494,6 @@ \begin{itemdescr} \pnum Representation of a quiet ``Not a Number'', if available. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} \pnum Meaningful for all specializations for which @@ -1516,9 +1510,6 @@ \begin{itemdescr} \pnum Representation of a signaling ``Not a Number'', if available. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} \pnum Meaningful for all specializations for which @@ -1536,9 +1527,6 @@ \indextext{number!subnormal}% \pnum Minimum positive subnormal value, if available. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} Otherwise, minimum positive normalized value. \pnum @@ -1574,9 +1562,6 @@ \begin{itemdescr} \pnum \tcode{true} if the set of values representable by the type is finite. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} \begin{note} All fundamental types\iref{basic.fundamental} are bounded. This member would be \tcode{false} for arbitrary precision types. @@ -1594,9 +1579,6 @@ \begin{itemdescr} \pnum \tcode{true} if the type is modulo. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} A type is modulo if, for any operation involving \tcode{+}, \tcode{-}, or \tcode{*} on values of that type whose result would fall outside the range \crange{min()}{max()}, the value returned differs from the true value by an @@ -1623,9 +1605,6 @@ \tcode{true} if, at the start of the program, there exists a value of the type that would cause an arithmetic operation using that value to trap. -\begin{footnote} -Required by ISO/IEC 10967-1:2012. -\end{footnote} \pnum Meaningful for all specializations. @@ -1643,7 +1622,6 @@ \begin{footnote} Refer to \IsoFloatUndated{}. -Required by ISO/IEC 10967-1:2012. \end{footnote} \pnum @@ -1660,7 +1638,6 @@ The rounding style for the type. \begin{footnote} Equivalent to \tcode{FLT_ROUNDS}. -Required by ISO/IEC 10967-1:2012. \end{footnote} \pnum @@ -2407,8 +2384,8 @@ constexpr void* operator new (std::size_t size, void* ptr) noexcept; constexpr void* operator new[](std::size_t size, void* ptr) noexcept; -void operator delete (void* ptr, void*) noexcept; -void operator delete[](void* ptr, void*) noexcept; +constexpr void operator delete (void* ptr, void*) noexcept; +constexpr void operator delete[](void* ptr, void*) noexcept; \end{codeblock} \rSec2[new.delete]{Storage allocation and deallocation} @@ -2978,7 +2955,7 @@ \indexlibrarymember{delete}{operator}% \begin{itemdecl} -void operator delete(void* ptr, void*) noexcept; +constexpr void operator delete(void* ptr, void*) noexcept; \end{itemdecl} \begin{itemdescr} @@ -2996,7 +2973,7 @@ \indexlibrarymember{delete}{operator}% \begin{itemdecl} -void operator delete[](void* ptr, void*) noexcept; +constexpr void operator delete[](void* ptr, void*) noexcept; \end{itemdecl} \begin{itemdescr} @@ -3181,9 +3158,12 @@ \pnum \expects \tcode{p} represents the address \placeholder{A} of a byte in memory. -An object \placeholder{X} that is within its lifetime\iref{basic.life} -and whose type is similar\iref{conv.qual} to \tcode{T} -is located at the address \placeholder{A}. +An object \placeholder{X} +whose type is similar\iref{conv.qual} to \tcode{T} +is located at the address \placeholder{A}, and +is either within its lifetime\iref{basic.life} or +is an array element subobject +whose containing array object is within its lifetime. All bytes of storage that would be reachable through\iref{basic.compound} the result are reachable through \tcode{p}. @@ -3657,6 +3637,9 @@ static consteval source_location current() noexcept; constexpr source_location() noexcept; + constexpr source_location(const source_location&) noexcept = default; + constexpr source_location& operator=(const source_location&) noexcept = default; + // source location field access constexpr uint_least32_t line() const noexcept; constexpr uint_least32_t column() const noexcept; @@ -3673,25 +3656,14 @@ \end{codeblock} \pnum -The type \tcode{source_location} meets the -\oldconcept{DefaultConstructible}, -\oldconcept{CopyConstructible}, -\oldconcept{Copy\-Assignable}, -\oldconcept{Swappable}, and -\oldconcept{Destructible} -requirements\iref{utility.arg.requirements,swappable.requirements}. -All of the following conditions are \tcode{true}: -\begin{itemize} -\item \tcode{is_nothrow_move_constructible_v} -\item \tcode{is_nothrow_move_assignable_v} -\item \tcode{is_nothrow_swappable_v} -\end{itemize} +The type \tcode{source_location} models \libconcept{semiregular}. +\tcode{is_nothrow_swappable_v} is \tcode{true}. \begin{note} The intent of \tcode{source_location} is to have a small size and efficient copying. It is unspecified whether the copy/move constructors and the copy/move assignment operators -are trivial and/or constexpr. +are trivial. \end{note} \pnum @@ -3875,18 +3847,20 @@ terminate_handler set_terminate(terminate_handler f) noexcept; [[noreturn]] void terminate() noexcept; - constexpr int uncaught_exceptions() noexcept; + int uncaught_exceptions() noexcept; using exception_ptr = @\unspec@; - constexpr exception_ptr current_exception() noexcept; + constexpr exception_ptr @\exposid{current-exception}@() noexcept; // \expos + exception_ptr current_exception() noexcept; [[noreturn]] constexpr void rethrow_exception(exception_ptr p); template constexpr exception_ptr make_exception_ptr(E e) noexcept; - template constexpr const E* exception_ptr_cast(const exception_ptr& p) noexcept; + template + constexpr optional exception_ptr_cast(const exception_ptr& p) noexcept; template void exception_ptr_cast(const exception_ptr&&) = delete; - template [[noreturn]] constexpr void throw_with_nested(T&& t); - template constexpr void rethrow_if_nested(const E& e); + template [[noreturn]] void throw_with_nested(T&& t); + template void rethrow_if_nested(const E& e); } \end{codeblock} @@ -4111,7 +4085,7 @@ \indexlibraryglobal{uncaught_exceptions}% \begin{itemdecl} -constexpr int uncaught_exceptions() noexcept; +int uncaught_exceptions() noexcept; \end{itemdecl} \begin{itemdescr} @@ -4180,7 +4154,8 @@ \indexlibraryglobal{current_exception}% \begin{itemdecl} -constexpr exception_ptr current_exception() noexcept; +constexpr exception_ptr @\exposid{current-exception}@() noexcept; +exception_ptr current_exception() noexcept; \end{itemdecl} \begin{itemdescr} @@ -4250,20 +4225,15 @@ try { throw e; } catch(...) { - return current_exception(); + return @\exposid{current-exception}@(); } \end{codeblock} - -\pnum -\begin{note} -This function is provided for convenience and -efficiency reasons. -\end{note} \end{itemdescr} \indexlibraryglobal{exception_ptr_cast}% \begin{itemdecl} -template constexpr const E* exception_ptr_cast(const exception_ptr& p) noexcept; +template + constexpr optional exception_ptr_cast(const exception_ptr& p) noexcept; \end{itemdecl} \begin{itemdescr} @@ -4280,11 +4250,12 @@ \pnum \returns -A pointer to the exception object referred to by \tcode{p}, +An \tcode{optional} containing a reference +to the exception object referred to by \tcode{p}, if \tcode{p} is not null and a handler of type \tcode{const E\&} would be a match\iref{except.handle} for that exception object. -Otherwise, \tcode{nullptr}. +Otherwise, \tcode{nullopt}. \end{itemdescr} \rSec2[except.nested]{\tcode{nested_exception}} @@ -4294,18 +4265,18 @@ namespace std { class nested_exception { public: - constexpr nested_exception() noexcept; - constexpr nested_exception(const nested_exception&) noexcept = default; - constexpr nested_exception& operator=(const nested_exception&) noexcept = default; - constexpr virtual ~nested_exception() = default; + nested_exception() noexcept; + nested_exception(const nested_exception&) noexcept = default; + nested_exception& operator=(const nested_exception&) noexcept = default; + virtual ~nested_exception() = default; // access functions - [[noreturn]] constexpr void rethrow_nested() const; - constexpr exception_ptr nested_ptr() const noexcept; + [[noreturn]] void rethrow_nested() const; + exception_ptr nested_ptr() const noexcept; }; - template [[noreturn]] constexpr void throw_with_nested(T&& t); - template constexpr void rethrow_if_nested(const E& e); + template [[noreturn]] void throw_with_nested(T&& t); + template void rethrow_if_nested(const E& e); } \end{codeblock} @@ -4322,7 +4293,7 @@ \indexlibraryctor{nested_exception}% \begin{itemdecl} -constexpr nested_exception() noexcept; +nested_exception() noexcept; \end{itemdecl} \begin{itemdescr} @@ -4333,7 +4304,7 @@ \indexlibrarymember{rethrow_nested}{nested_exception}% \begin{itemdecl} -[[noreturn]] constexpr void rethrow_nested() const; +[[noreturn]] void rethrow_nested() const; \end{itemdecl} \begin{itemdescr} @@ -4345,7 +4316,7 @@ \indexlibrarymember{nested_ptr}{nested_exception}% \begin{itemdecl} -constexpr exception_ptr nested_ptr() const noexcept; +exception_ptr nested_ptr() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -4356,7 +4327,7 @@ \indexlibrarymember{throw_with_nested}{nested_exception}% \begin{itemdecl} -template [[noreturn]] constexpr void throw_with_nested(T&& t); +template [[noreturn]] void throw_with_nested(T&& t); \end{itemdecl} \begin{itemdescr} @@ -4379,7 +4350,7 @@ \indexlibrarymember{rethrow_if_nested}{nested_exception}% \begin{itemdecl} -template constexpr void rethrow_if_nested(const E& e); +template void rethrow_if_nested(const E& e); \end{itemdecl} \begin{itemdescr} @@ -5703,7 +5674,7 @@ \pnum There is an \impldef{total ordering of all types} total ordering of all types. For any (possibly incomplete) types \tcode{X} and \tcode{Y}, -the expression \tcode{\exposid{TYPE-ORDER}(X, Y)} is a constant expression\iref{expr.const} +the expression \tcode{\exposid{TYPE-ORDER}(X, Y)} is a constant expression\iref{expr.const.const} of type \tcode{strong_ordering}\iref{cmp.strongord}. Its value is \tcode{strong_ordering::less} if \tcode{X} precedes \tcode{Y} in this implementation-defined total order, @@ -5737,6 +5708,10 @@ If an explicit specialization or partial specialization of \tcode{type_order} is declared, the program is ill-formed. +\pnum +The templates \tcode{type_order} and \tcode{type_order_v} +may be instantiated with incomplete types as arguments. + \pnum \recommended The order should be lexicographical on parameter-type-lists and template argument lists. @@ -5832,8 +5807,7 @@ \begin{codeblock} namespace std { template<> - struct coroutine_handle - { + struct coroutine_handle { // \ref{coroutine.handle.con}, construct/reset constexpr coroutine_handle() noexcept; constexpr coroutine_handle(nullptr_t) noexcept; @@ -5857,8 +5831,7 @@ }; template - struct coroutine_handle - { + struct coroutine_handle { // \ref{coroutine.handle.con}, construct/reset constexpr coroutine_handle() noexcept; constexpr coroutine_handle(nullptr_t) noexcept; @@ -6170,8 +6143,7 @@ \begin{codeblock} namespace std { template<> - struct coroutine_handle - { + struct coroutine_handle { // \ref{coroutine.handle.noop.conv}, conversion constexpr operator coroutine_handle<>() const noexcept; diff --git a/source/templates.tex b/source/templates.tex index 6cf798ea56..f2d3172095 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -193,7 +193,8 @@ \begin{itemize} \item a template, \item an entity defined\iref{basic.def} or created\iref{class.temporary} - within the \grammarterm{compound-statement} + within the + \grammarterm{for-range-declaration} or \grammarterm{compound-statement} of an \grammarterm{expansion-statement}\iref{stmt.expand}, \item an entity defined or created in a templated entity, \item a member of a templated entity, @@ -248,7 +249,7 @@ shall be reachable from the end of every definition domain\iref{basic.def.odr} in which it is implicitly instantiated\iref{temp.inst} unless the corresponding specialization is explicitly instantiated\iref{temp.explicit} -in some translation unit; no diagnostic is required. +in some translation unit; no diagnostic is required\ifndrdef{temp.pre.reach.def}. \rSec1[temp.param]{Template parameters} @@ -531,6 +532,8 @@ There can be template parameter objects of array type\iref{meta.define.static}, but such an object is never denoted by an \grammarterm{id-expression} that names a constant template parameter. +Such an object can have an address that +is not unique among all other in-lifetime objects\iref{intro.object}. \end{note} \begin{note} If an \grammarterm{id-expression} names @@ -1137,7 +1140,7 @@ template void f(); void g() { - f(); // \tcode{int()} is a type-id: call the first \tcode{f()} + f(); // \tcode{int()} is a \grammarterm{type-id}: call the first \tcode{f()} } \end{codeblock} \end{example} @@ -1320,7 +1323,7 @@ is determined from its template argument $A$ as follows. If \tcode{T} is not a class type and $A$ is not a \grammarterm{braced-init-list}, -$A$ shall be a converted constant expression\iref{expr.const} +$A$ shall be a converted constant expression\iref{expr.const.const} of type \tcode{T}; the value of $P$ is $A$ (as converted). \pnum @@ -1349,7 +1352,7 @@ \item the full-expression of an invented \grammarterm{init-declarator} for the initialization would not be a constant expression -when interpreted as a \grammarterm{constant-expression}\iref{expr.const}, or +when interpreted as a \grammarterm{constant-expression}\iref{expr.const.const}, or \item the initialization would cause $P$ to not be template-argument-equivalent\iref{temp.type} to \tcode{v}, \end{itemize} @@ -1511,7 +1514,7 @@ specialization based on the template template parameter is instantiated. If a specialization is not reachable from the point of instantiation, and it would have been selected had it been reachable, the program is ill-formed, -no diagnostic required. +no diagnostic required\ifndrdef{temp.arg.template.sat.constraints}. \begin{example} \begin{codeblock} template class A { // primary template @@ -1868,7 +1871,7 @@ if the validity or meaning of the program depends on whether two constructs are equivalent, and they are functionally equivalent but not equivalent, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{temp.constr.atomic.equiv.but.not.equiv}. \begin{example} \begin{codeblock} template void f2() @@ -1899,7 +1902,7 @@ results in \tcode{true}. If, at different points in the program, the satisfaction result is different for identical atomic constraints and template arguments, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{temp.constr.atomic.sat.result.diff}. \begin{example} \begin{codeblock} template concept C = @@ -2193,7 +2196,7 @@ in the normal form \tcode{N} of \tcode{CE}, appearances of \tcode{C}{'s} template parameters in the parameter mappings of the atomic constraints in \tcode{N} -with their respective arguments from \tcode{C}. +with their respective arguments from \tcode{CI}. If any such substitution results in an invalid type or expression, the program is ill-formed; no diagnostic is required. \end{itemize} @@ -2252,7 +2255,7 @@ after substituting in \tcode{E$_i$} the respective $i^\text{th}$ concept argument of each \tcode{P$_k$}. If any such substitution results in an invalid type or expression, - the program is ill-formed; no diagnostic is required. + the program is ill-formed; no diagnostic is required\ifndrdef{temp.constr.normal.invalid}. \item Otherwise, the normal form of \tcode{F} is @@ -2573,7 +2576,9 @@ they are of reference type and they refer to the same object or function, or \item -they are of array type and their corresponding elements are template-argument-equivalent, +they are of array type and their corresponding elements are either +both within their lifetimes and template-argument-equivalent or +both not within their lifetimes, \begin{footnote} An array as a \grammarterm{template-parameter} decays to a pointer. \end{footnote} @@ -2677,31 +2682,30 @@ which shall be a class or variable template. \pnum +A \defnadj{separately instantiated}{construct} +of a templated function \tcode{F} is a +\begin{itemize} +\item default argument, +\item \grammarterm{noexcept-specifier}, or +\item \grammarterm{function-contract-specifier} +\end{itemize} +of \tcode{F}. For purposes of name lookup and instantiation, -default arguments, -\grammarterm{type-constraint}{s}, -\grammarterm{requires-clause}{s}\iref{temp.pre}, -and -\grammarterm{noexcept-specifier}{s} -of function templates -and -of member functions of class templates +separately instantiated constructs, +\grammarterm{type-constraint}{s}, and +\grammarterm{requires-clause}{s}\iref{temp.pre} are considered definitions; each -default argument, -\grammarterm{type-constraint}, -\grammarterm{requires-clause}, -or -\grammarterm{noexcept-specifier} +separately instantiated construct, +\grammarterm{type-constraint}, or +\grammarterm{requires-clause} is a separate definition which is unrelated to the templated function definition or to any other -default arguments, -\grammarterm{type-constraint}{s}, -\grammarterm{requires-clause}{s}, -or -\grammarterm{noexcept-specifier}{s}. +separately instantiated constructs, +\grammarterm{type-constraint}{s}, or +\grammarterm{requires-clause}{s}. For the purpose of instantiation, the substatements of a constexpr if statement\iref{stmt.if} are considered definitions. For the purpose of name lookup and instantiation, @@ -3735,7 +3739,7 @@ that template. A partial specialization shall be reachable from any use of a template specialization that would make use of the partial specialization as the result of -an implicit or explicit instantiation; no diagnostic is required. +an implicit or explicit instantiation; no diagnostic is required\ifndrdef{temp.spec.partial.general.partial.reachable}. \pnum Two partial specialization declarations declare the same entity @@ -4288,7 +4292,7 @@ \end{codeblock} \end{example} \indextext{expression!functionally equivalent|see{functionally equivalent, expressions}}% -Two potentially-evaluated expressions involving template parameters that are not equivalent are +Two potentially evaluated expressions involving template parameters that are not equivalent are \defnx{functionally equivalent}{functionally equivalent!expressions} if, for any given set of template arguments, the evaluation of the expression results in the same value. @@ -4345,7 +4349,7 @@ If the validity or meaning of the program depends on whether two constructs are equivalent, and they are functionally equivalent but not equivalent, the program is ill-formed, -no diagnostic required. +no diagnostic required\ifndrdef{temp.over.link.equiv.not.equiv}. Furthermore, if two declarations $A$ and $B$ of function templates \begin{itemize} \item @@ -4404,10 +4408,10 @@ \item when the address of a function template specialization is taken; \item -when a placement operator delete that is a +when a placement deallocation function that is a function template specialization -is selected to match a placement operator new\iref{basic.stc.dynamic.deallocation,expr.new}; +is selected to match a placement allocation function\iref{basic.stc.dynamic.deallocation,expr.new}; \item when a friend function declaration\iref{temp.friend}, an explicit instantiation\iref{temp.explicit} or an explicit specialization\iref{temp.expl.spec} refers to @@ -4911,7 +4915,7 @@ introduced in a declaration that is reachable from the point of instantiation of a specialization\iref{temp.point} but is not found by lookup for the specialization, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{temp.res.general.default.but.not.found}. \begin{bnf} \nontermdef{typename-specifier}\br @@ -5130,7 +5134,7 @@ \item an instantiation uses a default argument or default template argument that had not been defined at the point at which the template was defined, or -\item constant expression evaluation\iref{expr.const} within the template +\item constant expression evaluation\iref{expr.const.core} within the template instantiation uses \begin{itemize} \item the value of a const object of integral or unscoped enumeration type or @@ -5361,7 +5365,7 @@ \defnx{type-dependent}{expression!type-dependent} (that is, its type may depend on a template parameter) or \defnx{value-dependent}{expression!value-dependent} -(that is, its value when evaluated as a constant expression\iref{expr.const} +(that is, its value when evaluated as a constant expression\iref{expr.const.const} may depend on a template parameter) as described below. @@ -5557,7 +5561,7 @@ its lookup context, if it is a qualified name, is the current instantiation, and \item -lookup for it finds any member of a class that is the current instantiation +lookup for it finds any member of a class that is the current instantiation. \end{itemize} \begin{example} \begin{codeblock} @@ -5660,7 +5664,9 @@ is dependent if \begin{itemize} \item -it has a dependent initializer, or +it has a dependent initializer, +\item +it refers to a type template template parameter, or \item it refers to an alias template that is a member of the current instantiation and @@ -5953,7 +5959,7 @@ it names a static member function that is a dependent member of the current instantiation, or \item -it names a potentially-constant variable\iref{expr.const} +it names a potentially-constant variable\iref{expr.const.init} that is initialized with an expression that is value-dependent. \end{itemize} @@ -6022,7 +6028,7 @@ instantiation is value-dependent. An expression of the form \tcode{\&}\grammarterm{cast-expression} is also value-dependent if evaluating \grammarterm{cast-expression} -as a core constant expression\iref{expr.const} succeeds and +as a core constant expression\iref{expr.const.core} succeeds and the result of the evaluation refers to a templated entity that is an object with static or thread storage duration or a member function. @@ -6031,12 +6037,13 @@ \begin{itemize} \item it is of the form \tcode{\caret\caret \grammarterm{reflection-name}} and -the \grammarterm{reflection-name} +either lookup for the \grammarterm{reflection-name} finds a declaration that +inhabits a scope corresponding to a templated entity or +the \grammarterm{reflection-name} is \begin{itemize} -\item is a dependent qualified name, -\item is a dependent \grammarterm{namespace-name}, -\item is the name of a template parameter, or -\item names a dependent member of the current instantiation\iref{temp.dep.type}, +\item a dependent qualified name, +\item a dependent \grammarterm{namespace-name}, or +\item the name of a template parameter, \end{itemize} \item it is of the form \tcode{\caret\caret \grammarterm{type-id}} and @@ -6165,11 +6172,13 @@ For a function template specialization, a member function template specialization, or a specialization for a member function or static data member of a class template, -if the specialization is implicitly instantiated because it is referenced -from within another template specialization and -the context from which it is referenced depends on a template parameter, the point of instantiation of the specialization is the point of instantiation -of the enclosing specialization. +of the enclosing specialization if +\begin{itemize} +\item the specialization is implicitly instantiated +because it is referenced from within another template specialization and +\item the context from which it is referenced depends on a template parameter. +\end{itemize} Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization. @@ -6183,12 +6192,16 @@ \pnum For a \grammarterm{noexcept-specifier} of a function template -specialization or specialization of a member function of a class template, if -the \grammarterm{noexcept-specifier} is implicitly instantiated because -it is needed by another template specialization and the context that requires -it depends on a template parameter, the point of instantiation of the +specialization or specialization of a member function of a class template, +the point of instantiation of the \grammarterm{noexcept-specifier} is the point of instantiation of the -specialization that requires it. Otherwise, the point of instantiation for such +specialization that requires it if +\begin{itemize} +\item the \grammarterm{noexcept-specifier} is implicitly instantiated +because it is needed by another template specialization and +\item the context that requires it depends on a template parameter. +\end{itemize} +Otherwise, the point of instantiation for such a \grammarterm{noexcept-specifier} immediately follows the namespace scope declaration or definition that requires the \grammarterm{noexcept-specifier}. @@ -6196,14 +6209,16 @@ \pnum For a class template specialization, a class member template specialization, or a specialization for a class member of a class template, -if the specialization is implicitly instantiated because it is referenced -from within another template specialization, -if the context from which the specialization is referenced depends on a -template parameter, -and if the specialization is not instantiated previous to the instantiation of -the enclosing template, the point of instantiation is immediately before the point of instantiation of -the enclosing template. +the enclosing template if +\begin{itemize} +\item the specialization is implicitly instantiated +because it is referenced from within another template specialization, +\item the context from which the specialization is referenced +depends on a template parameter, and +\item the specialization is not instantiated +previous to the instantiation of the enclosing template. +\end{itemize} Otherwise, the point of instantiation for such a specialization immediately precedes the namespace scope declaration or definition that refers to the specialization. @@ -6246,7 +6261,7 @@ translation units. If two different points of instantiation give a template specialization different meanings according to the one-definition rule\iref{basic.def.odr}, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{temp.point.diff.pt.diff.meaning}. \pnum For the \grammarterm{compound-statement} @@ -6266,7 +6281,7 @@ introduced in the associated namespaces in all translation units, not just considering those declarations found in the template definition and template instantiation contexts\iref{basic.lookup.argdep}, -then the program is ill-formed, no diagnostic required. +then the program is ill-formed, no diagnostic required\ifndrdef{temp.dep.candidate.different.lookup.different}. \pnum \begin{example} @@ -6585,7 +6600,7 @@ declared with a type deduced from its initializer or return value\iref{dcl.spec.auto}, \item -a potentially-constant variable\iref{expr.const}, or +a potentially-constant variable\iref{expr.const.init}, or \item a specialization of a templated class. \end{itemize} @@ -6635,19 +6650,6 @@ X ch; // error: incomplete type \tcode{X} \end{codeblock} \end{example} -\begin{note} -Within a template declaration, -a local class\iref{class.local} or enumeration and the members of -a local class are never considered to be entities that can be separately -instantiated (this includes their default arguments, -\grammarterm{noexcept-specifier}{s}, and non-static data member -initializers, if any, -but not their \grammarterm{type-constraint}{s} or \grammarterm{requires-clause}{s}). -As a result, the dependent names are looked up, the -semantic constraints are checked, and any templates used are instantiated as -part of the instantiation of the entity within which the local class or -enumeration is declared. -\end{note} \pnum The implicit instantiation of a class template specialization causes @@ -6667,10 +6669,6 @@ unscoped member enumerations, and member anonymous unions. \end{itemize} -The implicit instantiation of a class template specialization -does not cause the implicit instantiation of -default arguments or \grammarterm{noexcept-specifier}{s} -of the class member functions. \begin{example} \begin{codeblock} template @@ -6734,11 +6732,6 @@ implicitly instantiated when it is referenced in a context that requires a function definition to exist or if the existence of the definition affects the semantics of the program. -Unless a call is to a function template explicit specialization or -to a member function of an explicitly specialized class template, -a default argument for a function template or a member function of a -class template is implicitly instantiated when the function is -called in a context that requires the value of the default argument. \begin{note} An inline function that is the subject of an explicit instantiation declaration @@ -6795,7 +6788,7 @@ The existence of a definition of a variable or function is considered to affect the semantics of the program if the variable or function -is needed for constant evaluation by an expression\iref{expr.const}, +is needed for constant evaluation by an expression\iref{expr.const.defns}, even if constant evaluation of the expression is not required or if constant expression evaluation does not use the definition. @@ -6869,7 +6862,25 @@ causes specializations in the default member initializer to be instantiated. \pnum -If a templated function +The separately instantiated constructs\iref{temp.decls.general} +of a templated function \tcode{F} that is either +\begin{itemize} +\item +a member of a local class or +\item +the function call operator of the closure type +of a non-generic \grammarterm{lambda-expression} +\end{itemize} +are instantiated when the declaration of \tcode{F} is instantiated. +\begin{note} +For the purposes of instantiation, +these constructs are still considered separately +from the function to which they belong. +\end{note} + +\pnum +Other than as specified above, +when a templated function \tcode{f} is called in a way that requires a default argument to be used, the dependent names are looked up, the semantics constraints are checked, @@ -6888,7 +6899,9 @@ \tcode{f}. \pnum +\begin{note} Each default argument is instantiated independently. +\end{note} \begin{example} \begin{codeblock} template void f(T x, T y = ydef(T()), T z = zdef(T())); @@ -6906,16 +6919,16 @@ \end{example} \pnum -The \grammarterm{noexcept-specifier} and \grammarterm{function-contract-specifier}s -of a function template specialization -are not instantiated along with the function declaration; -they are instantiated -when needed\iref{except.spec,dcl.contract.func}. If such a -specifier is needed but has not yet been -instantiated, the dependent names are looked up, the semantics constraints are -checked, and the instantiation of any template used in the -specifier is done as if it were being done as part -of instantiating the declaration of the specialization at that point. +Other than as specified above, +the separately instantiated constructs +of a specialization of a templated function +are instantiated only when needed\iref{except.spec,dcl.contract.func}. +When such a construct is instantiated, +the dependent names are looked up, +the semantics constraints are checked, and +the instantiation of any template used in the construct +is done as if it were being done as part of instantiating the declaration +of the specialization at that point. \pnum \begin{note} @@ -6926,7 +6939,7 @@ There is an \impldef{maximum depth of recursive template instantiations} quantity that specifies the limit on the total depth of recursive instantiations\iref{implimits}, which could involve more than one template. -The result of an infinite recursion in instantiation is undefined. +The result of an infinite recursion in instantiation is undefined\ubdef{temp.inst.inf.recursion}. \begin{example} \begin{codeblock} template class X { @@ -7155,7 +7168,7 @@ in a way that would otherwise cause an implicit instantiation\iref{temp.inst} in the translation unit shall be the subject of an explicit instantiation definition somewhere in the -program; otherwise the program is ill-formed, no diagnostic required. +program; otherwise the program is ill-formed, no diagnostic requiredi\ifndrdef{temp.explicit.decl.implicit.inst}. \begin{note} This rule does apply to inline functions even though an explicit instantiation declaration of such an entity has no other normative @@ -7357,11 +7370,11 @@ every use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; -no diagnostic is required. +no diagnostic is required\ifndrdef{temp.expl.spec.unreachable.declaration}. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, -the program is ill-formed, no diagnostic required. +the program is ill-formed, no diagnostic required\ifndrdef{temp.expl.spec.missing.definition}. An implicit instantiation is never generated for an explicit specialization that is declared but not defined. \begin{example} @@ -7726,7 +7739,7 @@ int j = f(5.6); // error: \tcode{X} cannot be deduced f(f); // \tcode{Y} for outer \tcode{f} deduced as \tcode{int (*)(bool)} f(f); // error: \tcode{f} does not denote a single function template specialization - int k = g(5.6); // \tcode{Y} deduced as double; \tcode{Z} deduced as an empty sequence + int k = g(5.6); // \tcode{Y} deduced as \tcode{double}; \tcode{Z} deduced as an empty sequence f(g); // \tcode{Y} for outer \tcode{f} deduced as \tcode{int (*)(bool)}, // \tcode{Z} deduced as an empty sequence } @@ -7998,7 +8011,7 @@ a condition that causes deduction to fail is encountered. If substitution into different declarations of the same function template would cause template instantiations to occur in a different order or not at all, -the program is ill-formed; no diagnostic required. +the program is ill-formed; no diagnostic required\ifndrdef{temp.deduct.general.diff.order}. \begin{note} The equivalent substitution in exception specifications\iref{except.spec} @@ -8039,20 +8052,40 @@ \end{note} Invalid types and expressions can result in a deduction failure only in the immediate context of the deduction substitution loci. +The \defnadj{immediate}{context} of a deduction substitution locus +is that deduction substitution locus, +excluding bodies of \grammarterm{lambda-expression}s and separately instantiated constructs. +\begin{example} +\begin{codeblock} +template +T* fun(T&& v); // \#1: the deduction substitution locus is the function type + // ``function of (rvalue reference to \tcode{T}) returning pointer to \tcode{T}'' + +void fun(...); // \#2 + +void test() +{ + int i; + fun(i); // selects \#2 (forming the type ``pointer to reference to \tcode{int}'' fails in \#1) +} +\end{codeblock} +\end{example} +\begin{note} +Separately instantiated constructs are excluded from the immediate contexts +even if they are instantiated at the same time. +\end{note} \begin{note} The substitution into types and expressions can result -in effects such as the instantiation of class template specializations and/or -function template specializations, the generation of implicitly-defined functions, -etc. Such effects are not in the ``immediate context'' and can result in the -program being ill-formed. +in effects such as the instantiation of template specializations, +the generation of implicitly-defined functions, etc. +Such effects are not in the immediate context +and can result in the program being ill-formed. \end{note} \pnum -When substituting into a \grammarterm{lambda-expression}, -substitution into its body is not in the immediate context. \begin{note} -The intent is to avoid requiring implementations to deal with -substitution failure involving arbitrary statements. +No \grammarterm{statement} is ever in the immediate context +of a deduction substitution locus. \begin{example} \begin{codeblock} template @@ -8592,7 +8625,7 @@ \tcode{P}) with the type specified by the \grammarterm{conversion-type-id} of the \grammarterm{conversion-function-id} being looked up -(call it \tcode{A}) as described in~\ref{temp.deduct.type}. +(call it \tcode{A}), as described in~\ref{temp.deduct.type}. If the \grammarterm{conversion-function-id} is constructed during overload resolution\iref{over.match.funcs}, the rules in the remainder of this subclause apply. @@ -8772,18 +8805,16 @@ \end{itemize} \pnum -Using the resulting types -\tcode{P} -and -\tcode{A}, +If \tcode{A} was transformed from a function parameter pack and +\tcode{P} is not a parameter pack, +type deduction fails. +Otherwise, using the resulting types \tcode{P} and \tcode{A}, the deduction is then done as described in~\ref{temp.deduct.type}. If \tcode{P} is a function parameter pack, the type \tcode{A} of each remaining parameter type of the argument template is compared with the type \tcode{P} of the \grammarterm{declarator-id} of the function parameter pack. Each comparison deduces template arguments for subsequent positions in the template parameter packs expanded by the function parameter pack. -Similarly, if \tcode{A} was transformed from a function parameter pack, -it is compared with each remaining parameter type of the parameter template. If deduction succeeds for a given type, the type from the argument template is considered to be at least as specialized as the type from the parameter template. @@ -9631,12 +9662,12 @@ for explicit instantiations\iref{temp.explicit}, explicit specializations\iref{temp.expl.spec}, and certain friend declarations\iref{temp.friend}. This is also done to determine whether a deallocation function template specialization matches a placement -\tcode{operator new}\iref{basic.stc.dynamic.deallocation,expr.new}. +allocation function\iref{basic.stc.dynamic.deallocation,expr.new}. In all these cases, \tcode{P} is the type of the function template being considered as a potential match and \tcode{A} is either the function type from the declaration or the type of the deallocation function that would match the placement -\tcode{operator new} as described in~\ref{expr.new}. The +allocation function as described in~\ref{expr.new}. The deduction is done as described in~\ref{temp.deduct.type}. \pnum diff --git a/source/text.tex b/source/text.tex index b89eaa3ea4..8c08f20295 100644 --- a/source/text.tex +++ b/source/text.tex @@ -1305,7 +1305,7 @@ \pnum The \tcode{put()} members make no provision for error reporting. -(Any failures of the OutputIterator argument can be extracted from +(Any failures of the \tcode{OutputIterator} argument can be extracted from the returned iterator.) The \tcode{get()} members take an \tcode{ios_base::iostate\&} argument whose value they ignore, @@ -5026,7 +5026,7 @@ \begin{codeblock} namespace std { struct text_encoding { - static constexpr size_t max_name_length = 63; + static constexpr size_t @\libmember{max_name_length}{text_encoding}@ = 63; // \ref{text.encoding.id}, enumeration \tcode{text_encoding::id} enum class id : int_least32_t { @@ -5432,264 +5432,264 @@ \begin{codeblock} namespace std { enum class text_encoding::id : int_least32_t { - other = 1, - unknown = 2, - ASCII = 3, - ISOLatin1 = 4, - ISOLatin2 = 5, - ISOLatin3 = 6, - ISOLatin4 = 7, - ISOLatinCyrillic = 8, - ISOLatinArabic = 9, - ISOLatinGreek = 10, - ISOLatinHebrew = 11, - ISOLatin5 = 12, - ISOLatin6 = 13, - ISOTextComm = 14, - HalfWidthKatakana = 15, - JISEncoding = 16, - ShiftJIS = 17, - EUCPkdFmtJapanese = 18, - EUCFixWidJapanese = 19, - ISO4UnitedKingdom = 20, - ISO11SwedishForNames = 21, - ISO15Italian = 22, - ISO17Spanish = 23, - ISO21German = 24, - ISO60DanishNorwegian = 25, - ISO69French = 26, - ISO10646UTF1 = 27, - ISO646basic1983 = 28, - INVARIANT = 29, - ISO2IntlRefVersion = 30, - NATSSEFI = 31, - NATSSEFIADD = 32, - ISO10Swedish = 35, - KSC56011987 = 36, - ISO2022KR = 37, - EUCKR = 38, - ISO2022JP = 39, - ISO2022JP2 = 40, - ISO13JISC6220jp = 41, - ISO14JISC6220ro = 42, - ISO16Portuguese = 43, - ISO18Greek7Old = 44, - ISO19LatinGreek = 45, - ISO25French = 46, - ISO27LatinGreek1 = 47, - ISO5427Cyrillic = 48, - ISO42JISC62261978 = 49, - ISO47BSViewdata = 50, - ISO49INIS = 51, - ISO50INIS8 = 52, - ISO51INISCyrillic = 53, - ISO54271981 = 54, - ISO5428Greek = 55, - ISO57GB1988 = 56, - ISO58GB231280 = 57, - ISO61Norwegian2 = 58, - ISO70VideotexSupp1 = 59, - ISO84Portuguese2 = 60, - ISO85Spanish2 = 61, - ISO86Hungarian = 62, - ISO87JISX0208 = 63, - ISO88Greek7 = 64, - ISO89ASMO449 = 65, - ISO90 = 66, - ISO91JISC62291984a = 67, - ISO92JISC62991984b = 68, - ISO93JIS62291984badd = 69, - ISO94JIS62291984hand = 70, - ISO95JIS62291984handadd = 71, - ISO96JISC62291984kana = 72, - ISO2033 = 73, - ISO99NAPLPS = 74, - ISO102T617bit = 75, - ISO103T618bit = 76, - ISO111ECMACyrillic = 77, - ISO121Canadian1 = 78, - ISO122Canadian2 = 79, - ISO123CSAZ24341985gr = 80, - ISO88596E = 81, - ISO88596I = 82, - ISO128T101G2 = 83, - ISO88598E = 84, - ISO88598I = 85, - ISO139CSN369103 = 86, - ISO141JUSIB1002 = 87, - ISO143IECP271 = 88, - ISO146Serbian = 89, - ISO147Macedonian = 90, - ISO150 = 91, - ISO151Cuba = 92, - ISO6937Add = 93, - ISO153GOST1976874 = 94, - ISO8859Supp = 95, - ISO10367Box = 96, - ISO158Lap = 97, - ISO159JISX02121990 = 98, - ISO646Danish = 99, - USDK = 100, - DKUS = 101, - KSC5636 = 102, - Unicode11UTF7 = 103, - ISO2022CN = 104, - ISO2022CNEXT = 105, - UTF8 = 106, - ISO885913 = 109, - ISO885914 = 110, - ISO885915 = 111, - ISO885916 = 112, - GBK = 113, - GB18030 = 114, - OSDEBCDICDF0415 = 115, - OSDEBCDICDF03IRV = 116, - OSDEBCDICDF041 = 117, - ISO115481 = 118, - KZ1048 = 119, - UCS2 = 1000, - UCS4 = 1001, - UnicodeASCII = 1002, - UnicodeLatin1 = 1003, - UnicodeJapanese = 1004, - UnicodeIBM1261 = 1005, - UnicodeIBM1268 = 1006, - UnicodeIBM1276 = 1007, - UnicodeIBM1264 = 1008, - UnicodeIBM1265 = 1009, - Unicode11 = 1010, - SCSU = 1011, - UTF7 = 1012, - UTF16BE = 1013, - UTF16LE = 1014, - UTF16 = 1015, - CESU8 = 1016, - UTF32 = 1017, - UTF32BE = 1018, - UTF32LE = 1019, - BOCU1 = 1020, - UTF7IMAP = 1021, - Windows30Latin1 = 2000, - Windows31Latin1 = 2001, - Windows31Latin2 = 2002, - Windows31Latin5 = 2003, - HPRoman8 = 2004, - AdobeStandardEncoding = 2005, - VenturaUS = 2006, - VenturaInternational = 2007, - DECMCS = 2008, - PC850Multilingual = 2009, - PCp852 = 2010, - PC8CodePage437 = 2011, - PC8DanishNorwegian = 2012, - PC862LatinHebrew = 2013, - PC8Turkish = 2014, - IBMSymbols = 2015, - IBMThai = 2016, - HPLegal = 2017, - HPPiFont = 2018, - HPMath8 = 2019, - HPPSMath = 2020, - HPDesktop = 2021, - VenturaMath = 2022, - MicrosoftPublishing = 2023, - Windows31J = 2024, - GB2312 = 2025, - Big5 = 2026, - Macintosh = 2027, - IBM037 = 2028, - IBM038 = 2029, - IBM273 = 2030, - IBM274 = 2031, - IBM275 = 2032, - IBM277 = 2033, - IBM278 = 2034, - IBM280 = 2035, - IBM281 = 2036, - IBM284 = 2037, - IBM285 = 2038, - IBM290 = 2039, - IBM297 = 2040, - IBM420 = 2041, - IBM423 = 2042, - IBM424 = 2043, - IBM500 = 2044, - IBM851 = 2045, - IBM855 = 2046, - IBM857 = 2047, - IBM860 = 2048, - IBM861 = 2049, - IBM863 = 2050, - IBM864 = 2051, - IBM865 = 2052, - IBM868 = 2053, - IBM869 = 2054, - IBM870 = 2055, - IBM871 = 2056, - IBM880 = 2057, - IBM891 = 2058, - IBM903 = 2059, - IBM904 = 2060, - IBM905 = 2061, - IBM918 = 2062, - IBM1026 = 2063, - IBMEBCDICATDE = 2064, - EBCDICATDEA = 2065, - EBCDICCAFR = 2066, - EBCDICDKNO = 2067, - EBCDICDKNOA = 2068, - EBCDICFISE = 2069, - EBCDICFISEA = 2070, - EBCDICFR = 2071, - EBCDICIT = 2072, - EBCDICPT = 2073, - EBCDICES = 2074, - EBCDICESA = 2075, - EBCDICESS = 2076, - EBCDICUK = 2077, - EBCDICUS = 2078, - Unknown8BiT = 2079, - Mnemonic = 2080, - Mnem = 2081, - VISCII = 2082, - VIQR = 2083, - KOI8R = 2084, - HZGB2312 = 2085, - IBM866 = 2086, - PC775Baltic = 2087, - KOI8U = 2088, - IBM00858 = 2089, - IBM00924 = 2090, - IBM01140 = 2091, - IBM01141 = 2092, - IBM01142 = 2093, - IBM01143 = 2094, - IBM01144 = 2095, - IBM01145 = 2096, - IBM01146 = 2097, - IBM01147 = 2098, - IBM01148 = 2099, - IBM01149 = 2100, - Big5HKSCS = 2101, - IBM1047 = 2102, - PTCP154 = 2103, - Amiga1251 = 2104, - KOI7switched = 2105, - BRF = 2106, - TSCII = 2107, - CP51932 = 2108, - windows874 = 2109, - windows1250 = 2250, - windows1251 = 2251, - windows1252 = 2252, - windows1253 = 2253, - windows1254 = 2254, - windows1255 = 2255, - windows1256 = 2256, - windows1257 = 2257, - windows1258 = 2258, - TIS620 = 2259, - CP50220 = 2260 + @\libmember{other}{text_encoding}@ = 1, + @\libmember{unknown}{text_encoding}@ = 2, + @\libmember{ASCII}{text_encoding}@ = 3, + @\libmember{ISOLatin1}{text_encoding}@ = 4, + @\libmember{ISOLatin2}{text_encoding}@ = 5, + @\libmember{ISOLatin3}{text_encoding}@ = 6, + @\libmember{ISOLatin4}{text_encoding}@ = 7, + @\libmember{ISOLatinCyrillic}{text_encoding}@ = 8, + @\libmember{ISOLatinArabic}{text_encoding}@ = 9, + @\libmember{ISOLatinGreek}{text_encoding}@ = 10, + @\libmember{ISOLatinHebrew}{text_encoding}@ = 11, + @\libmember{ISOLatin5}{text_encoding}@ = 12, + @\libmember{ISOLatin6}{text_encoding}@ = 13, + @\libmember{ISOTextComm}{text_encoding}@ = 14, + @\libmember{HalfWidthKatakana}{text_encoding}@ = 15, + @\libmember{JISEncoding}{text_encoding}@ = 16, + @\libmember{ShiftJIS}{text_encoding}@ = 17, + @\libmember{EUCPkdFmtJapanese}{text_encoding}@ = 18, + @\libmember{EUCFixWidJapanese}{text_encoding}@ = 19, + @\libmember{ISO4UnitedKingdom}{text_encoding}@ = 20, + @\libmember{ISO11SwedishForNames}{text_encoding}@ = 21, + @\libmember{ISO15Italian}{text_encoding}@ = 22, + @\libmember{ISO17Spanish}{text_encoding}@ = 23, + @\libmember{ISO21German}{text_encoding}@ = 24, + @\libmember{ISO60DanishNorwegian}{text_encoding}@ = 25, + @\libmember{ISO69French}{text_encoding}@ = 26, + @\libmember{ISO10646UTF1}{text_encoding}@ = 27, + @\libmember{ISO646basic1983}{text_encoding}@ = 28, + @\libmember{INVARIANT}{text_encoding}@ = 29, + @\libmember{ISO2IntlRefVersion}{text_encoding}@ = 30, + @\libmember{NATSSEFI}{text_encoding}@ = 31, + @\libmember{NATSSEFIADD}{text_encoding}@ = 32, + @\libmember{ISO10Swedish}{text_encoding}@ = 35, + @\libmember{KSC56011987}{text_encoding}@ = 36, + @\libmember{ISO2022KR}{text_encoding}@ = 37, + @\libmember{EUCKR}{text_encoding}@ = 38, + @\libmember{ISO2022JP}{text_encoding}@ = 39, + @\libmember{ISO2022JP2}{text_encoding}@ = 40, + @\libmember{ISO13JISC6220jp}{text_encoding}@ = 41, + @\libmember{ISO14JISC6220ro}{text_encoding}@ = 42, + @\libmember{ISO16Portuguese}{text_encoding}@ = 43, + @\libmember{ISO18Greek7Old}{text_encoding}@ = 44, + @\libmember{ISO19LatinGreek}{text_encoding}@ = 45, + @\libmember{ISO25French}{text_encoding}@ = 46, + @\libmember{ISO27LatinGreek1}{text_encoding}@ = 47, + @\libmember{ISO5427Cyrillic}{text_encoding}@ = 48, + @\libmember{ISO42JISC62261978}{text_encoding}@ = 49, + @\libmember{ISO47BSViewdata}{text_encoding}@ = 50, + @\libmember{ISO49INIS}{text_encoding}@ = 51, + @\libmember{ISO50INIS8}{text_encoding}@ = 52, + @\libmember{ISO51INISCyrillic}{text_encoding}@ = 53, + @\libmember{ISO54271981}{text_encoding}@ = 54, + @\libmember{ISO5428Greek}{text_encoding}@ = 55, + @\libmember{ISO57GB1988}{text_encoding}@ = 56, + @\libmember{ISO58GB231280}{text_encoding}@ = 57, + @\libmember{ISO61Norwegian2}{text_encoding}@ = 58, + @\libmember{ISO70VideotexSupp1}{text_encoding}@ = 59, + @\libmember{ISO84Portuguese2}{text_encoding}@ = 60, + @\libmember{ISO85Spanish2}{text_encoding}@ = 61, + @\libmember{ISO86Hungarian}{text_encoding}@ = 62, + @\libmember{ISO87JISX0208}{text_encoding}@ = 63, + @\libmember{ISO88Greek7}{text_encoding}@ = 64, + @\libmember{ISO89ASMO449}{text_encoding}@ = 65, + @\libmember{ISO90}{text_encoding}@ = 66, + @\libmember{ISO91JISC62291984a}{text_encoding}@ = 67, + @\libmember{ISO92JISC62991984b}{text_encoding}@ = 68, + @\libmember{ISO93JIS62291984badd}{text_encoding}@ = 69, + @\libmember{ISO94JIS62291984hand}{text_encoding}@ = 70, + @\libmember{ISO95JIS62291984handadd}{text_encoding}@ = 71, + @\libmember{ISO96JISC62291984kana}{text_encoding}@ = 72, + @\libmember{ISO2033}{text_encoding}@ = 73, + @\libmember{ISO99NAPLPS}{text_encoding}@ = 74, + @\libmember{ISO102T617bit}{text_encoding}@ = 75, + @\libmember{ISO103T618bit}{text_encoding}@ = 76, + @\libmember{ISO111ECMACyrillic}{text_encoding}@ = 77, + @\libmember{ISO121Canadian1}{text_encoding}@ = 78, + @\libmember{ISO122Canadian2}{text_encoding}@ = 79, + @\libmember{ISO123CSAZ24341985gr}{text_encoding}@ = 80, + @\libmember{ISO88596E}{text_encoding}@ = 81, + @\libmember{ISO88596I}{text_encoding}@ = 82, + @\libmember{ISO128T101G2}{text_encoding}@ = 83, + @\libmember{ISO88598E}{text_encoding}@ = 84, + @\libmember{ISO88598I}{text_encoding}@ = 85, + @\libmember{ISO139CSN369103}{text_encoding}@ = 86, + @\libmember{ISO141JUSIB1002}{text_encoding}@ = 87, + @\libmember{ISO143IECP271}{text_encoding}@ = 88, + @\libmember{ISO146Serbian}{text_encoding}@ = 89, + @\libmember{ISO147Macedonian}{text_encoding}@ = 90, + @\libmember{ISO150}{text_encoding}@ = 91, + @\libmember{ISO151Cuba}{text_encoding}@ = 92, + @\libmember{ISO6937Add}{text_encoding}@ = 93, + @\libmember{ISO153GOST1976874}{text_encoding}@ = 94, + @\libmember{ISO8859Supp}{text_encoding}@ = 95, + @\libmember{ISO10367Box}{text_encoding}@ = 96, + @\libmember{ISO158Lap}{text_encoding}@ = 97, + @\libmember{ISO159JISX02121990}{text_encoding}@ = 98, + @\libmember{ISO646Danish}{text_encoding}@ = 99, + @\libmember{USDK}{text_encoding}@ = 100, + @\libmember{DKUS}{text_encoding}@ = 101, + @\libmember{KSC5636}{text_encoding}@ = 102, + @\libmember{Unicode11UTF7}{text_encoding}@ = 103, + @\libmember{ISO2022CN}{text_encoding}@ = 104, + @\libmember{ISO2022CNEXT}{text_encoding}@ = 105, + @\libmember{UTF8}{text_encoding}@ = 106, + @\libmember{ISO885913}{text_encoding}@ = 109, + @\libmember{ISO885914}{text_encoding}@ = 110, + @\libmember{ISO885915}{text_encoding}@ = 111, + @\libmember{ISO885916}{text_encoding}@ = 112, + @\libmember{GBK}{text_encoding}@ = 113, + @\libmember{GB18030}{text_encoding}@ = 114, + @\libmember{OSDEBCDICDF0415}{text_encoding}@ = 115, + @\libmember{OSDEBCDICDF03IRV}{text_encoding}@ = 116, + @\libmember{OSDEBCDICDF041}{text_encoding}@ = 117, + @\libmember{ISO115481}{text_encoding}@ = 118, + @\libmember{KZ1048}{text_encoding}@ = 119, + @\libmember{UCS2}{text_encoding}@ = 1000, + @\libmember{UCS4}{text_encoding}@ = 1001, + @\libmember{UnicodeASCII}{text_encoding}@ = 1002, + @\libmember{UnicodeLatin1}{text_encoding}@ = 1003, + @\libmember{UnicodeJapanese}{text_encoding}@ = 1004, + @\libmember{UnicodeIBM1261}{text_encoding}@ = 1005, + @\libmember{UnicodeIBM1268}{text_encoding}@ = 1006, + @\libmember{UnicodeIBM1276}{text_encoding}@ = 1007, + @\libmember{UnicodeIBM1264}{text_encoding}@ = 1008, + @\libmember{UnicodeIBM1265}{text_encoding}@ = 1009, + @\libmember{Unicode11}{text_encoding}@ = 1010, + @\libmember{SCSU}{text_encoding}@ = 1011, + @\libmember{UTF7}{text_encoding}@ = 1012, + @\libmember{UTF16BE}{text_encoding}@ = 1013, + @\libmember{UTF16LE}{text_encoding}@ = 1014, + @\libmember{UTF16}{text_encoding}@ = 1015, + @\libmember{CESU8}{text_encoding}@ = 1016, + @\libmember{UTF32}{text_encoding}@ = 1017, + @\libmember{UTF32BE}{text_encoding}@ = 1018, + @\libmember{UTF32LE}{text_encoding}@ = 1019, + @\libmember{BOCU1}{text_encoding}@ = 1020, + @\libmember{UTF7IMAP}{text_encoding}@ = 1021, + @\libmember{Windows30Latin1}{text_encoding}@ = 2000, + @\libmember{Windows31Latin1}{text_encoding}@ = 2001, + @\libmember{Windows31Latin2}{text_encoding}@ = 2002, + @\libmember{Windows31Latin5}{text_encoding}@ = 2003, + @\libmember{HPRoman8}{text_encoding}@ = 2004, + @\libmember{AdobeStandardEncoding}{text_encoding}@ = 2005, + @\libmember{VenturaUS}{text_encoding}@ = 2006, + @\libmember{VenturaInternational}{text_encoding}@ = 2007, + @\libmember{DECMCS}{text_encoding}@ = 2008, + @\libmember{PC850Multilingual}{text_encoding}@ = 2009, + @\libmember{PCp852}{text_encoding}@ = 2010, + @\libmember{PC8CodePage437}{text_encoding}@ = 2011, + @\libmember{PC8DanishNorwegian}{text_encoding}@ = 2012, + @\libmember{PC862LatinHebrew}{text_encoding}@ = 2013, + @\libmember{PC8Turkish}{text_encoding}@ = 2014, + @\libmember{IBMSymbols}{text_encoding}@ = 2015, + @\libmember{IBMThai}{text_encoding}@ = 2016, + @\libmember{HPLegal}{text_encoding}@ = 2017, + @\libmember{HPPiFont}{text_encoding}@ = 2018, + @\libmember{HPMath8}{text_encoding}@ = 2019, + @\libmember{HPPSMath}{text_encoding}@ = 2020, + @\libmember{HPDesktop}{text_encoding}@ = 2021, + @\libmember{VenturaMath}{text_encoding}@ = 2022, + @\libmember{MicrosoftPublishing}{text_encoding}@ = 2023, + @\libmember{Windows31J}{text_encoding}@ = 2024, + @\libmember{GB2312}{text_encoding}@ = 2025, + @\libmember{Big5}{text_encoding}@ = 2026, + @\libmember{Macintosh}{text_encoding}@ = 2027, + @\libmember{IBM037}{text_encoding}@ = 2028, + @\libmember{IBM038}{text_encoding}@ = 2029, + @\libmember{IBM273}{text_encoding}@ = 2030, + @\libmember{IBM274}{text_encoding}@ = 2031, + @\libmember{IBM275}{text_encoding}@ = 2032, + @\libmember{IBM277}{text_encoding}@ = 2033, + @\libmember{IBM278}{text_encoding}@ = 2034, + @\libmember{IBM280}{text_encoding}@ = 2035, + @\libmember{IBM281}{text_encoding}@ = 2036, + @\libmember{IBM284}{text_encoding}@ = 2037, + @\libmember{IBM285}{text_encoding}@ = 2038, + @\libmember{IBM290}{text_encoding}@ = 2039, + @\libmember{IBM297}{text_encoding}@ = 2040, + @\libmember{IBM420}{text_encoding}@ = 2041, + @\libmember{IBM423}{text_encoding}@ = 2042, + @\libmember{IBM424}{text_encoding}@ = 2043, + @\libmember{IBM500}{text_encoding}@ = 2044, + @\libmember{IBM851}{text_encoding}@ = 2045, + @\libmember{IBM855}{text_encoding}@ = 2046, + @\libmember{IBM857}{text_encoding}@ = 2047, + @\libmember{IBM860}{text_encoding}@ = 2048, + @\libmember{IBM861}{text_encoding}@ = 2049, + @\libmember{IBM863}{text_encoding}@ = 2050, + @\libmember{IBM864}{text_encoding}@ = 2051, + @\libmember{IBM865}{text_encoding}@ = 2052, + @\libmember{IBM868}{text_encoding}@ = 2053, + @\libmember{IBM869}{text_encoding}@ = 2054, + @\libmember{IBM870}{text_encoding}@ = 2055, + @\libmember{IBM871}{text_encoding}@ = 2056, + @\libmember{IBM880}{text_encoding}@ = 2057, + @\libmember{IBM891}{text_encoding}@ = 2058, + @\libmember{IBM903}{text_encoding}@ = 2059, + @\libmember{IBM904}{text_encoding}@ = 2060, + @\libmember{IBM905}{text_encoding}@ = 2061, + @\libmember{IBM918}{text_encoding}@ = 2062, + @\libmember{IBM1026}{text_encoding}@ = 2063, + @\libmember{IBMEBCDICATDE}{text_encoding}@ = 2064, + @\libmember{EBCDICATDEA}{text_encoding}@ = 2065, + @\libmember{EBCDICCAFR}{text_encoding}@ = 2066, + @\libmember{EBCDICDKNO}{text_encoding}@ = 2067, + @\libmember{EBCDICDKNOA}{text_encoding}@ = 2068, + @\libmember{EBCDICFISE}{text_encoding}@ = 2069, + @\libmember{EBCDICFISEA}{text_encoding}@ = 2070, + @\libmember{EBCDICFR}{text_encoding}@ = 2071, + @\libmember{EBCDICIT}{text_encoding}@ = 2072, + @\libmember{EBCDICPT}{text_encoding}@ = 2073, + @\libmember{EBCDICES}{text_encoding}@ = 2074, + @\libmember{EBCDICESA}{text_encoding}@ = 2075, + @\libmember{EBCDICESS}{text_encoding}@ = 2076, + @\libmember{EBCDICUK}{text_encoding}@ = 2077, + @\libmember{EBCDICUS}{text_encoding}@ = 2078, + @\libmember{Unknown8BiT}{text_encoding}@ = 2079, + @\libmember{Mnemonic}{text_encoding}@ = 2080, + @\libmember{Mnem}{text_encoding}@ = 2081, + @\libmember{VISCII}{text_encoding}@ = 2082, + @\libmember{VIQR}{text_encoding}@ = 2083, + @\libmember{KOI8R}{text_encoding}@ = 2084, + @\libmember{HZGB2312}{text_encoding}@ = 2085, + @\libmember{IBM866}{text_encoding}@ = 2086, + @\libmember{PC775Baltic}{text_encoding}@ = 2087, + @\libmember{KOI8U}{text_encoding}@ = 2088, + @\libmember{IBM00858}{text_encoding}@ = 2089, + @\libmember{IBM00924}{text_encoding}@ = 2090, + @\libmember{IBM01140}{text_encoding}@ = 2091, + @\libmember{IBM01141}{text_encoding}@ = 2092, + @\libmember{IBM01142}{text_encoding}@ = 2093, + @\libmember{IBM01143}{text_encoding}@ = 2094, + @\libmember{IBM01144}{text_encoding}@ = 2095, + @\libmember{IBM01145}{text_encoding}@ = 2096, + @\libmember{IBM01146}{text_encoding}@ = 2097, + @\libmember{IBM01147}{text_encoding}@ = 2098, + @\libmember{IBM01148}{text_encoding}@ = 2099, + @\libmember{IBM01149}{text_encoding}@ = 2100, + @\libmember{Big5HKSCS}{text_encoding}@ = 2101, + @\libmember{IBM1047}{text_encoding}@ = 2102, + @\libmember{PTCP154}{text_encoding}@ = 2103, + @\libmember{Amiga1251}{text_encoding}@ = 2104, + @\libmember{KOI7switched}{text_encoding}@ = 2105, + @\libmember{BRF}{text_encoding}@ = 2106, + @\libmember{TSCII}{text_encoding}@ = 2107, + @\libmember{CP51932}{text_encoding}@ = 2108, + @\libmember{windows874}{text_encoding}@ = 2109, + @\libmember{windows1250}{text_encoding}@ = 2250, + @\libmember{windows1251}{text_encoding}@ = 2251, + @\libmember{windows1252}{text_encoding}@ = 2252, + @\libmember{windows1253}{text_encoding}@ = 2253, + @\libmember{windows1254}{text_encoding}@ = 2254, + @\libmember{windows1255}{text_encoding}@ = 2255, + @\libmember{windows1256}{text_encoding}@ = 2256, + @\libmember{windows1257}{text_encoding}@ = 2257, + @\libmember{windows1258}{text_encoding}@ = 2258, + @\libmember{TIS620}{text_encoding}@ = 2259, + @\libmember{CP50220}{text_encoding}@ = 2260 }; } \end{codeblock} @@ -5698,7 +5698,7 @@ The \tcode{text_encoding::id} enumeration contains an enumerator for each known registered character encoding. For each encoding, the corresponding enumerator is derived from -the alias beginning with ``\tcode{cs}'', as follows +the alias beginning with ``\tcode{cs}'', as follows: \begin{itemize} \item \tcode{csUnicode} is mapped to \tcode{text_encoding::id::UCS2}, @@ -5751,18 +5751,18 @@ template struct basic_format_string; - template struct @\exposid{runtime-format-string}@ { // \expos + template struct @\exposid{dynamic-format-string}@ { // \expos private: basic_string_view @\exposid{str}@; // \expos public: - constexpr @\exposid{runtime-format-string}@(basic_string_view s) noexcept : @\exposid{str}@(s) {} - @\exposid{runtime-format-string}@(const @\exposid{runtime-format-string}@&) = delete; - @\exposid{runtime-format-string}@& operator=(const @\exposid{runtime-format-string}@&) = delete; + constexpr @\exposid{dynamic-format-string}@(basic_string_view s) noexcept : @\exposid{str}@(s) {} + @\exposid{dynamic-format-string}@(const @\exposid{dynamic-format-string}@&) = delete; + @\exposid{dynamic-format-string}@& operator=(const @\exposid{dynamic-format-string}@&) = delete; }; - constexpr @\exposid{runtime-format-string}@ - runtime_format(string_view fmt) noexcept { return fmt; } - constexpr @\exposid{runtime-format-string}@ - runtime_format(wstring_view fmt) noexcept { return fmt; } + constexpr @\exposid{dynamic-format-string}@ + dynamic_format(string_view fmt) noexcept { return fmt; } + constexpr @\exposid{dynamic-format-string}@ + dynamic_format(wstring_view fmt) noexcept { return fmt; } template using @\libglobal{format_string}@ = basic_format_string...>; @@ -6394,19 +6394,31 @@ \item For integral types, the locale-specific form causes the context's locale to be used -to insert the appropriate digit group separator characters. +to insert the appropriate digit group separator characters +as if obtained with +\tcode{numpunct::grouping} and +\tcode{numpunct::thousands_sep}. \item For floating-point types, the locale-specific form causes the context's locale to be used -to insert the appropriate digit group and radix separator characters. +to insert the appropriate digit group and radix separator characters +as if obtained with +\tcode{numpunct::grouping}, +\tcode{numpunct::thousands_sep}, and +\tcode{numpunct::decimal_point}. \item For the textual representation of \tcode{bool}, the locale-specific form causes the context's locale to be used to insert the appropriate string as if obtained -with \tcode{numpunct::truename} or \tcode{numpunct::falsename}. +with \tcode{numpunct::truename} or \tcode{numpunct::\brk{}falsename}. \end{itemize} +If the string literal encoding is a Unicode encoding form and +the locale is among an implementation-defined set of locales, +each replacement that depends on the locale is performed as if +the replacement character sequence is converted to +the string literal encoding. \pnum The \fmtgrammarterm{type} determines how the data should be presented. @@ -6434,7 +6446,9 @@ let \range{first}{last} be a range large enough to hold the \tcode{to_chars} output and \tcode{value} be the formatting argument value. -Formatting is done as if by calling \tcode{to_chars} as specified +Formatting is done as if by calling \tcode{to_chars} as specified, +transcoding the \tcode{to_chars} output to the wide literal encoding if +\tcode{charT} is \tcode{wchar_t}, and copying the output through the output iterator of the format context. \begin{note} Additional padding and adjustments are performed @@ -6678,7 +6692,7 @@ public: template consteval basic_format_string(const T& s); - constexpr basic_format_string(@\exposid{runtime-format-string}@ s) noexcept : str(s.@\exposid{str}@) {} + constexpr basic_format_string(@\exposid{dynamic-format-string}@ s) noexcept : str(s.@\exposid{str}@) {} constexpr basic_string_view get() const noexcept { return @\exposid{str}@; } }; @@ -6700,7 +6714,7 @@ \pnum \remarks -A call to this function is not a core constant expression\iref{expr.const} +A call to this function is not a core constant expression\iref{expr.const.core} unless there exist \tcode{args} of types \tcode{Args} such that \exposid{str} is a format string for \tcode{args}. \end{itemdescr} @@ -6722,7 +6736,7 @@ \indexlibraryglobal{format}% \begin{itemdecl} template - string format(format_string fmt, Args&&... args); + constexpr string format(format_string fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -6737,7 +6751,7 @@ \indexlibraryglobal{format}% \begin{itemdecl} template - wstring format(wformat_string fmt, Args&&... args); + constexpr wstring format(wformat_string fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -6781,8 +6795,8 @@ \indexlibraryglobal{vformat}% \begin{itemdecl} -string vformat(string_view fmt, format_args args); -wstring vformat(wstring_view fmt, wformat_args args); +constexpr string vformat(string_view fmt, format_args args); +constexpr wstring vformat(wstring_view fmt, wformat_args args); string vformat(const locale& loc, string_view fmt, format_args args); wstring vformat(const locale& loc, wstring_view fmt, wformat_args args); \end{itemdecl} @@ -6803,7 +6817,7 @@ \indexlibraryglobal{format_to}% \begin{itemdecl} template - Out format_to(Out out, format_string fmt, Args&&... args); + constexpr Out format_to(Out out, format_string fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -6818,7 +6832,7 @@ \indexlibraryglobal{format_to}% \begin{itemdecl} template - Out format_to(Out out, wformat_string fmt, Args&&... args); + constexpr Out format_to(Out out, wformat_string fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -6863,9 +6877,9 @@ \indexlibraryglobal{vformat_to}% \begin{itemdecl} template - Out vformat_to(Out out, string_view fmt, format_args args); + constexpr Out vformat_to(Out out, string_view fmt, format_args args); template - Out vformat_to(Out out, wstring_view fmt, wformat_args args); + constexpr Out vformat_to(Out out, wstring_view fmt, wformat_args args); template Out vformat_to(Out out, const locale& loc, string_view fmt, format_args args); template @@ -6905,11 +6919,13 @@ \indexlibraryglobal{format_to_n}% \begin{itemdecl} template - format_to_n_result format_to_n(Out out, iter_difference_t n, - format_string fmt, Args&&... args); + constexpr format_to_n_result format_to_n(Out out, iter_difference_t n, + format_string fmt, + Args&&... args); template - format_to_n_result format_to_n(Out out, iter_difference_t n, - wformat_string fmt, Args&&... args); + constexpr format_to_n_result format_to_n(Out out, iter_difference_t n, + wformat_string fmt, + Args&&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, const locale& loc, format_string fmt, @@ -6962,9 +6978,9 @@ \indexlibraryglobal{formatted_size}% \begin{itemdecl} template - size_t formatted_size(format_string fmt, Args&&... args); + constexpr size_t formatted_size(format_string fmt, Args&&... args); template - size_t formatted_size(wformat_string fmt, Args&&... args); + constexpr size_t formatted_size(wformat_string fmt, Args&&... args); template size_t formatted_size(const locale& loc, format_string fmt, Args&&... args); template @@ -7107,7 +7123,7 @@ Pursuant to \ref{namespace.std}, users may specialize \tcode{enable_nonlocking_formatter_optimization} for cv-unqualified program-defined types. -Such specializations shall be usable in constant expressions\iref{expr.const} +Such specializations shall be usable in constant expressions\iref{expr.const.init} and have type \tcode{const bool}. \end{itemdescr} @@ -7606,7 +7622,7 @@ \remarks Let \tcode{\placeholder{cur-arg-id}} be the value of \tcode{next_arg_id_} prior to this call. Call expressions where \tcode{\placeholder{cur-arg-id} >= num_args_} is \tcode{true} -are not core constant expressions\iref{expr.const}. +are not core constant expressions\iref{expr.const.core}. \end{itemdescr} \indexlibrarymember{check_arg_id}{basic_format_parse_context}% @@ -7633,7 +7649,7 @@ \pnum \remarks -A call to this function is a core constant expression\iref{expr.const} only if +A call to this function is a core constant expression\iref{expr.const.core} only if \tcode{id < num_args_} is \tcode{true}. \end{itemdescr} @@ -7761,7 +7777,7 @@ \recommended For a given type \tcode{charT}, implementations should provide -a single instantiation of \tcode{basic_format_context} +a single specialization of \tcode{basic_format_context} for appending to \tcode{basic_string}, \tcode{vector}, @@ -7771,7 +7787,7 @@ \indexlibrarymember{arg}{basic_format_context}% \begin{itemdecl} -basic_format_arg arg(size_t id) const noexcept; +constexpr basic_format_arg arg(size_t id) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -7795,7 +7811,7 @@ \indexlibrarymember{out}{basic_format_context}% \begin{itemdecl} -iterator out(); +constexpr iterator out(); \end{itemdecl} \begin{itemdescr} @@ -7806,7 +7822,7 @@ \indexlibrarymember{advance_to}{basic_format_context}% \begin{itemdecl} -void advance_to(iterator it); +constexpr void advance_to(iterator it); \end{itemdecl} \begin{itemdescr} @@ -7912,7 +7928,7 @@ Pursuant to \ref{namespace.std}, users may specialize \tcode{format_kind} for cv-unqualified program-defined types that model \tcode{ranges::\libconcept{input_range}}. -Such specializations shall be usable in constant expressions\iref{expr.const} +Such specializations shall be usable in constant expressions\iref{expr.const.init} and have type \tcode{const range_format}. \end{itemdescr} @@ -8114,7 +8130,7 @@ template requires @\libconcept{formattable}@, charT> && @\libconcept{same_as}@>, T> - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(R&& r, FormatContext& ctx) const; \end{itemdecl} @@ -8222,7 +8238,7 @@ \indexlibrarymemberexpos{format}{range-default-formatter}% \begin{itemdecl} template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\exposid{maybe-const-r}@& elems, FormatContext& ctx) const; \end{itemdecl} @@ -8302,7 +8318,7 @@ \indexlibrarymemberexpos{format}{range-default-formatter}% \begin{itemdecl} template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\exposid{maybe-const-map}@& r, FormatContext& ctx) const; \end{itemdecl} @@ -8368,7 +8384,7 @@ \indexlibrarymemberexpos{format}{range-default-formatter}% \begin{itemdecl} template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\exposid{maybe-const-set}@& r, FormatContext& ctx) const; \end{itemdecl} @@ -8459,13 +8475,13 @@ class handle; private: - using char_type = Context::char_type; // \expos + using @\exposid{char-type}@ = Context::char_type; // \expos - variant, - const void*, handle> value; // \expos + const @\exposid{char-type}@*, basic_string_view<@\exposid{char-type}@>, + const void*, handle> @\exposid{value_}@; // \expos template constexpr explicit basic_format_arg(T& v) noexcept; // \expos @@ -8492,7 +8508,7 @@ \indexlibrary{\idxcode{basic_format_arg}!constructor|(}% \begin{itemdecl} -basic_format_arg() noexcept; +constexpr basic_format_arg() noexcept; \end{itemdecl} \begin{itemdescr} @@ -8502,7 +8518,7 @@ \end{itemdescr} \begin{itemdecl} -template explicit basic_format_arg(T& v) noexcept; +template constexpr explicit basic_format_arg(T& v) noexcept; \end{itemdecl} \begin{itemdescr} @@ -8512,56 +8528,56 @@ \pnum \expects -If \tcode{decay_t} is \tcode{char_type*} or \tcode{const char_type*}, -\tcode{static_cast(v)} points to an NTCTS\iref{defns.ntcts}. +If \tcode{decay_t} is \tcode{\exposid{char-type}*} or \tcode{const \exposid{char-type}*}, +\tcode{static_cast(v)} points to an NTCTS\iref{defns.ntcts}. \pnum \effects Let \tcode{TD} be \tcode{remove_const_t}. \begin{itemize} \item -If \tcode{TD} is \tcode{bool} or \tcode{char_type}, -initializes \tcode{value} with \tcode{v}; +If \tcode{TD} is \tcode{bool} or \exposid{char-type}, +initializes \exposid{value_} with \tcode{v}; \item -otherwise, if \tcode{TD} is \tcode{char} and \tcode{char_type} is -\keyword{wchar_t}, initializes \tcode{value} with +otherwise, if \tcode{TD} is \tcode{char} and \exposid{char-type} is +\keyword{wchar_t}, initializes \exposid{value_} with \tcode{static_cast(static_cast(v))}; \item otherwise, if \tcode{TD} is a signed integer type\iref{basic.fundamental} and \tcode{sizeof(TD) <= sizeof(int)}, -initializes \tcode{value} with \tcode{static_cast(v)}; +initializes \exposid{value_} with \tcode{static_cast(v)}; \item otherwise, if \tcode{TD} is an unsigned integer type and \tcode{sizeof(TD) <= sizeof(unsigned int)}, initializes -\tcode{value} with \tcode{static_cast(v)}; +\exposid{value_} with \tcode{static_cast(v)}; \item otherwise, if \tcode{TD} is a signed integer type and \tcode{sizeof(TD) <= sizeof(long long int)}, initializes -\tcode{value} with \tcode{static_cast(v)}; +\exposid{value_} with \tcode{static_cast(v)}; \item otherwise, if \tcode{TD} is an unsigned integer type and \tcode{sizeof(TD) <= sizeof(unsigned long long int)}, initializes -\tcode{value} with +\exposid{value_} with \tcode{static_cast(v)}; \item otherwise, if \tcode{TD} is a standard floating-point type, -initializes \tcode{value} with \tcode{v}; +initializes \exposid{value_} with \tcode{v}; \item otherwise, if \tcode{TD} is a specialization of \tcode{basic_string_view} or \tcode{basic_string} and -\tcode{TD::value_type} is \tcode{char_type}, -initializes \tcode{value} with -\tcode{basic_string_view(v.data(), v.size())}; +\tcode{TD::value_type} is \exposid{char-type}, +initializes \exposid{value_} with +\tcode{basic_string_view<\exposid{char-type}>(v.data(), v.size())}; \item otherwise, if \tcode{decay_t} is -\tcode{char_type*} or \tcode{const char_type*}, -initializes \tcode{value} with \tcode{static_cast(v)}; +\tcode{\exposid{char-type}*} or \tcode{const \exposid{char-type}*}, +initializes \exposid{value_} with \tcode{static_cast(v)}; \item otherwise, if \tcode{is_void_v>} is \tcode{true} or \tcode{is_null_pointer_v} is \tcode{true}, -initializes \tcode{value} with \tcode{static_cast(v)}; +initializes \exposid{value_} with \tcode{static_cast(v)}; \item -otherwise, initializes \tcode{value} with \tcode{handle(v)}. +otherwise, initializes \exposid{value_} with \tcode{handle(v)}. \end{itemize} \begin{note} Constructing \tcode{basic_format_arg} from a pointer to a member is ill-formed @@ -8574,37 +8590,37 @@ \indexlibrarymember{operator bool}{basic_format_arg}% \begin{itemdecl} -explicit operator bool() const noexcept; +constexpr explicit operator bool() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{!holds_alternative(value)}. +\tcode{!holds_alternative(\exposid{value_})}. \end{itemdescr} \indexlibrarymember{visit}{basic_format_arg}% \begin{itemdecl} template - decltype(auto) visit(this basic_format_arg arg, Visitor&& vis); + constexpr decltype(auto) visit(this basic_format_arg arg, Visitor&& vis); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return arg.value.visit(std::forward(vis));} +Equivalent to: \tcode{return arg.\exposid{value_}.visit(std::forward(vis));} \end{itemdescr} \indexlibrarymember{visit}{basic_format_arg}% \begin{itemdecl} template - R visit(this basic_format_arg arg, Visitor&& vis); + constexpr R visit(this basic_format_arg arg, Visitor&& vis); \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return arg.value.visit(std::forward(vis));} +Equivalent to: \tcode{return arg.\exposid{value_}.visit(std::forward(vis));} \end{itemdescr} \pnum @@ -8616,21 +8632,21 @@ namespace std { template class basic_format_arg::handle { - const void* ptr_; // \expos - void (*format_)(basic_format_parse_context&, + const void* @\exposid{ptr_}@; // \expos + void (*@\exposid{format_}@)(basic_format_parse_context<@\exposid{char-type}@>&, Context&, const void*); // \expos template constexpr explicit handle(T& val) noexcept; // \expos public: - constexpr void format(basic_format_parse_context&, Context& ctx) const; + constexpr void format(basic_format_parse_context<@\exposid{char-type}@>&, Context& ctx) const; }; } \end{codeblock} \indexlibraryctor{basic_format_arg::handle}% \begin{itemdecl} -template explicit handle(T& val) noexcept; +template constexpr explicit handle(T& val) noexcept; \end{itemdecl} \begin{itemdescr} @@ -8652,10 +8668,10 @@ \pnum \effects Initializes -\tcode{ptr_} with \tcode{addressof(val)} and -\tcode{format_} with +\exposid{ptr_} with \tcode{addressof(val)} and +\exposid{format_} with \begin{codeblock} -[](basic_format_parse_context& parse_ctx, +[](basic_format_parse_context<@\exposid{char-type}@>& parse_ctx, Context& format_ctx, const void* ptr) { typename Context::template formatter_type f; parse_ctx.advance_to(f.parse(parse_ctx)); @@ -8667,13 +8683,13 @@ \indexlibrarymember{format}{basic_format_arg::handle}% \begin{itemdecl} -void format(basic_format_parse_context& parse_ctx, Context& format_ctx) const; +constexpr void format(basic_format_parse_context<@\exposid{char-type}@>& parse_ctx, Context& format_ctx) const; \end{itemdecl} \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{format_(parse_ctx, format_ctx, ptr_);} +Equivalent to: \tcode{\exposid{format_}(parse_ctx, format_ctx, \exposid{ptr_});} \end{itemdescr} \rSec3[format.arg.store]{Class template \exposid{format-arg-store}} @@ -8693,7 +8709,8 @@ \indexlibraryglobal{make_format_args}% \begin{itemdecl} template - @\exposid{format-arg-store}@ make_format_args(Args&... fmt_args); + constexpr @\exposid{format-arg-store}@ + make_format_args(Args&... fmt_args); \end{itemdecl} \begin{itemdescr} @@ -8714,7 +8731,8 @@ \indexlibraryglobal{make_wformat_args}% \begin{itemdecl} template - @\exposid{format-arg-store}@ make_wformat_args(Args&... args); + constexpr @\exposid{format-arg-store}@ + make_wformat_args(Args&... args); \end{itemdecl} \begin{itemdescr} @@ -8730,8 +8748,8 @@ namespace std { template class basic_format_args { - size_t size_; // \expos - const basic_format_arg* data_; // \expos + size_t @\exposid{size_}@; // \expos + const basic_format_arg* @\exposid{data_}@; // \expos public: template @@ -8762,26 +8780,26 @@ \indexlibraryctor{basic_format_args}% \begin{itemdecl} template - basic_format_args(const @\exposid{format-arg-store}@& store) noexcept; + constexpr basic_format_args(const @\exposid{format-arg-store}@& store) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Initializes -\tcode{size_} with \tcode{sizeof...(Args)} and -\tcode{data_} with \tcode{store.args.data()}. +\exposid{size_} with \tcode{sizeof...(Args)} and +\exposid{data_} with \tcode{store.\exposid{args}.data()}. \end{itemdescr} \indexlibrarymember{get}{basic_format_args}% \begin{itemdecl} -basic_format_arg get(size_t i) const noexcept; +constexpr basic_format_arg get(size_t i) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{i < size_ ?\ data_[i] :\ basic_format_arg()}. +\tcode{i < \exposid{size_} ?\ \exposid{data_}[i] :\ basic_format_arg()}. \end{itemdescr} \rSec2[format.tuple]{Tuple formatter} @@ -8945,7 +8963,7 @@ \indexlibrarymember{format}{formatter}% \begin{itemdecl} template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\seebelow@& elems, FormatContext& ctx) const; \end{itemdecl} @@ -12633,7 +12651,7 @@ that points to a final sequence of characters at the end of the target sequence. In a suffix iterator the member \tcode{result} holds a pointer to the data -member \tcode{suffix}, the value of the member \tcode{suffix.match} +member \tcode{suffix}, the value of the member \tcode{suffix.matched} is \tcode{true}, \tcode{suffix.first} points to the beginning of the final sequence, and \tcode{suffix.second} points to the end of the final sequence. diff --git a/source/threads.tex b/source/threads.tex index 359af7dcd0..3769ac1a8a 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -293,9 +293,9 @@ \pnum A type \tcode{L} meets the \defnoldconcept{TimedLockable} requirements if it meets the \oldconcept{Lockable} requirements and the following expressions are well-formed and have the specified semantics -(\tcode{m} denotes a value of type \tcode{L}, \tcode{rel_time} denotes a value of an -instantiation of \tcode{duration}\iref{time.duration}, and \tcode{abs_time} denotes a value -of an instantiation of \tcode{time_point}\iref{time.point}). +(\tcode{m} denotes a value of type \tcode{L}, \tcode{rel_time} denotes a value of a +specialization of \tcode{duration}\iref{time.duration}, and \tcode{abs_time} denotes a value +of a specialization of \tcode{time_point}\iref{time.point}). \begin{itemdecl} m.try_lock_for(rel_time) @@ -631,7 +631,6 @@ If the callback invocation was added to stop state's list of callbacks, \tcode{scb} shall be associated with the stop state. \end{itemize} -\item \begin{note} If \tcode{t.stop_possible()} is \tcode{false}, there is no requirement @@ -1981,7 +1980,7 @@ static unsigned int hardware_concurrency() noexcept; private: - stop_source ssource; // \expos + stop_source @\exposid{ssource}@; // \expos }; } \end{codeblock} @@ -2002,7 +2001,7 @@ \pnum \ensures \tcode{get_id() == id()} is \tcode{true} -and \tcode{ssource.stop_possible()} is \tcode{false}. +and \tcode{\exposid{ssource}.stop_possible()} is \tcode{false}. \end{itemdescr} \indexlibraryctor{jthread}% @@ -2026,7 +2025,7 @@ \pnum \effects -Initializes \tcode{ssource}. +Initializes \exposid{ssource}. The new thread of execution executes \begin{codeblock} invoke(auto(std::forward(f)), get_stop_token(), // for \tcode{invoke}, see \ref{func.invoke} @@ -2055,7 +2054,7 @@ \pnum \ensures \tcode{get_id() != id()} is \tcode{true} -and \tcode{ssource.stop_possible()} is \tcode{true} +and \tcode{\exposid{ssource}.stop_possible()} is \tcode{true} and \tcode{*this} represents the newly started thread. \begin{note} The calling thread can make a stop request only once, @@ -2087,9 +2086,9 @@ \tcode{x.get_id() == id()} and \tcode{get_id()} returns the value of \tcode{x.get_id()} prior to the start of construction. -\tcode{ssource} has the value of \tcode{x.ssource} +\exposid{ssource} has the value of \tcode{x.\exposid{ssource}} prior to the start of construction -and \tcode{x.ssource.stop_possible()} is \tcode{false}. +and \tcode{x.\exposid{ssource}.stop_possible()} is \tcode{false}. \end{itemdescr} \indexlibrarydtor{jthread}% @@ -2125,7 +2124,7 @@ \ensures \tcode{get_id()} returns the value of \tcode{x.get_id()} prior to the assignment. -\tcode{ssource} has the value of \tcode{x.ssource} +\exposid{ssource} has the value of \tcode{x.\exposid{ssource}} prior to the assignment. \pnum @@ -2253,7 +2252,7 @@ \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return ssource;} +Equivalent to: \tcode{return \exposid{ssource};} \end{itemdescr} \indexlibrarymember{get_stop_token}{jthread}% @@ -2264,7 +2263,7 @@ \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return ssource.get_token();} +Equivalent to: \tcode{return \exposid{ssource}.get_token();} \end{itemdescr} \indexlibrarymember{request_stop}{jthread}% @@ -2275,7 +2274,7 @@ \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{return ssource.request_stop();} +Equivalent to: \tcode{return \exposid{ssource}.request_stop();} \end{itemdescr} @@ -2398,6 +2397,10 @@ \rSec2[atomics.general]{General} +\pnum +Let \tcode{\placeholdernc{COPYCV}(FROM, TO)} be an alias for type \tcode{TO} +with the addition of \tcode{FROM}'s top-level cv-qualifiers. + \pnum Subclause \ref{atomics} describes components for fine-grained atomic access. This access is provided via operations on atomic objects. @@ -3150,16 +3153,18 @@ namespace std { template struct atomic_ref { private: - T* ptr; // \expos + T* @\exposid{ptr}@; // \expos public: using value_type = remove_cv_t; + using @\exposid{address-return-type}@ = @\placeholdernc{COPYCV}@(T, void)*; // \expos 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; constexpr explicit atomic_ref(T&); + explicit atomic_ref(T&&) = delete; constexpr atomic_ref(const atomic_ref&) noexcept; template constexpr atomic_ref(const atomic_ref&) noexcept; @@ -3184,25 +3189,25 @@ constexpr void wait(value_type, memory_order = memory_order::seq_cst) const noexcept; constexpr void notify_one() const noexcept; constexpr void notify_all() const noexcept; - constexpr T* address() const noexcept; + constexpr @\exposid{address-return-type}@ address() 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, +the object referenced by \tcode{*\exposid{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}. +the object referenced by \tcode{*\exposid{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} +The lifetime\iref{basic.life} of an object referenced by \tcode{*\exposid{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, +that reference the \tcode{*\exposid{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} @@ -3238,6 +3243,9 @@ \pnum The alignment required for an object to be referenced by an atomic reference, which is at least \tcode{alignof(T)}. +For any type \tcode{U} similar to \tcode{T}, +the value of \tcode{required_alignment} +is the same as \tcode{atomic_ref>::required_alignment}. \pnum \begin{note} @@ -3261,6 +3269,9 @@ 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. +For any type \tcode{U} similar to \tcode{T}, +the value of \tcode{is_always_lock_free} +is the same as \tcode{atomic_ref>::is_always_lock_free}. \end{itemdescr} \indexlibrarymember{is_lock_free}{atomic_ref}% @@ -3356,7 +3367,7 @@ \pnum \effects -Atomically replaces the value referenced by \tcode{*ptr} +Atomically replaces the value referenced by \tcode{*\exposid{ptr}} with the value of \tcode{desired}. Memory is affected according to the value of \tcode{order}. \end{itemdescr} @@ -3405,7 +3416,7 @@ \pnum \returns -Atomically returns the value referenced by \tcode{*ptr}. +Atomically returns the value referenced by \tcode{*\exposid{ptr}}. \end{itemdescr} \indexlibrarymember{operator \placeholder{type}}{atomic_ref}% @@ -3438,14 +3449,14 @@ \pnum \effects -Atomically replaces the value referenced by \tcode{*ptr} +Atomically replaces the value referenced by \tcode{*\exposid{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} +Atomically returns the value referenced by \tcode{*\exposid{ptr}} immediately before the effects. \end{itemdescr} @@ -3459,16 +3470,16 @@ \indexlibrarymember{compare_exchange_strong}{atomic_ref<\placeholder{floating-point-type}>}% \begin{itemdecl} constexpr bool compare_exchange_weak(value_type& expected, value_type desired, - memory_order success, memory_order failure) const noexcept; + memory_order success, memory_order failure) const noexcept; constexpr bool compare_exchange_strong(value_type& expected, value_type desired, - memory_order success, memory_order failure) const noexcept; + memory_order success, memory_order failure) const noexcept; constexpr bool compare_exchange_weak(value_type& expected, value_type desired, - memory_order order = memory_order::seq_cst) const noexcept; + memory_order order = memory_order::seq_cst) const noexcept; constexpr bool compare_exchange_strong(value_type& expected, value_type desired, - memory_order order = memory_order::seq_cst) const noexcept; + memory_order order = memory_order::seq_cst) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -3487,9 +3498,9 @@ \effects Retrieves the value in \tcode{expected}. It then atomically compares the value representation of -the value referenced by \tcode{*ptr} for equality +the value referenced by \tcode{*\exposid{ptr}} for equality with that previously retrieved from \tcode{expected}, -and if \tcode{true}, replaces the value referenced by \tcode{*ptr} +and if \tcode{true}, replaces the value referenced by \tcode{*\exposid{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 @@ -3505,11 +3516,11 @@ 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} +the value read from the value referenced by \tcode{*\exposid{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}. +on the value referenced by \tcode{*\exposid{ptr}}. Otherwise, these operations are atomic load operations on that memory. \pnum @@ -3519,11 +3530,11 @@ \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, +That is, even when the value representations referred to +by \tcode{expected} and \exposid{ptr} compare equal, it may return \tcode{false} and -store back to \tcode{expected} the same memory contents -that were originally there. +store back to \tcode{expected} +the same value representation that was 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. @@ -3566,7 +3577,7 @@ \pnum \remarks This function is an atomic waiting operation\iref{atomics.wait} -on atomic object \tcode{*ptr}. +on atomic object \tcode{*\exposid{ptr}}. \end{itemdescr} \indexlibrarymember{notify_one}{atomic_ref}% @@ -3581,14 +3592,14 @@ \pnum \effects -Unblocks the execution of at least one atomic waiting operation on \tcode{*ptr} +Unblocks the execution of at least one atomic waiting operation on \tcode{*\exposid{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}. +on atomic object \tcode{*\exposid{ptr}}. \end{itemdescr} \indexlibrarymember{notify_all}{atomic_ref}% @@ -3603,24 +3614,24 @@ \pnum \effects -Unblocks the execution of all atomic waiting operations on \tcode{*ptr} +Unblocks the execution of all atomic waiting operations on \tcode{*\exposid{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}. +on atomic object \tcode{*\exposid{ptr}}. \end{itemdescr} \indexlibrarymember{address}{atomic_ref}% \begin{itemdecl} -constexpr T* address() const noexcept; +constexpr @\exposid{address-return-type}@ address() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{ptr}. +\exposid{ptr}. \end{itemdescr} \rSec3[atomics.ref.int]{Specializations for integral types} @@ -3646,17 +3657,19 @@ namespace std { template<> struct atomic_ref<@\placeholder{integral-type}@> { private: - @\placeholder{integral-type}@* ptr; // \expos + @\placeholder{integral-type}@* @\exposid{ptr}@; // \expos public: using value_type = remove_cv_t<@\placeholder{integral-type}@>; using difference_type = value_type; + using @\exposid{address-return-type}@ = @\placeholdernc{COPYCV}@(@\placeholder{integral-type}@, void)*; // \expos 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; constexpr explicit atomic_ref(@\placeholder{integral-type}@&); + explicit atomic_ref(@\placeholder{integral-type}@&&) = delete; constexpr atomic_ref(const atomic_ref&) noexcept; template constexpr atomic_ref(const atomic_ref&) noexcept; @@ -3721,7 +3734,7 @@ constexpr void wait(value_type, memory_order = memory_order::seq_cst) const noexcept; constexpr void notify_one() const noexcept; constexpr void notify_all() const noexcept; - constexpr @\placeholder{integral-type}@* address() const noexcept; + constexpr @\exposid{address-return-type}@ address() const noexcept; }; } \end{codeblock} @@ -3754,15 +3767,15 @@ \pnum \effects -Atomically replaces the value referenced by \tcode{*ptr} with -the result of the computation applied to the value referenced by \tcode{*ptr} +Atomically replaces the value referenced by \tcode{*\exposid{ptr}} with +the result of the computation applied to the value referenced by \tcode{*\exposid{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} +Atomically, the value referenced by \tcode{*\exposid{ptr}} immediately before the effects. \pnum @@ -3808,9 +3821,9 @@ \pnum \effects -Atomically replaces the value referenced by \tcode{*ptr} +Atomically replaces the value referenced by \tcode{*\exposid{ptr}} with the result of the computation applied to -the value referenced by \tcode{*ptr} and the given \tcode{operand}. +the value referenced by \tcode{*\exposid{ptr}} and the given \tcode{operand}. Memory is affected according to the value of \tcode{order}. These operations are atomic modify-write operations\iref{atomics.order}. @@ -3818,7 +3831,7 @@ \remarks Except for \tcode{store_max} and \tcode{store_min}, for signed integer types, -the result is as if \tcode{*ptr} and parameters +the result is as if \tcode{*\exposid{ptr}} and parameters were converted to their corresponding unsigned types, the computation performed on those types, and the result converted back to the signed type. @@ -3828,7 +3841,7 @@ For \tcode{store_max} and \tcode{store_min}, the maximum and minimum computation is performed as if by \tcode{max} and \tcode{min} algorithms\iref{alg.min.max}, respectively, -with \tcode{*ptr} and the first parameter as the arguments. +with \tcode{*\exposid{ptr}} and the first parameter as the arguments. \end{itemdescr} \indexlibrarymember{operator+=}{atomic_ref<\placeholder{integral-type}>}% @@ -3870,17 +3883,19 @@ namespace std { template<> struct atomic_ref<@\placeholder{floating-point-type}@> { private: - @\placeholder{floating-point-type}@* ptr; // \expos + @\placeholder{floating-point-type}@* @\exposid{ptr}@; // \expos public: using value_type = remove_cv_t<@\placeholder{floating-point-type}@>; using difference_type = value_type; + using @\exposid{address-return-type}@ = @\placeholdernc{COPYCV}@(@\placeholder{floating-point-type}@, void)*; // \expos 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; constexpr explicit atomic_ref(@\placeholder{floating-point-type}@&); + explicit atomic_ref(@\placeholder{floating-point-type}@&&) = delete; constexpr atomic_ref(const atomic_ref&) noexcept; template constexpr atomic_ref(const atomic_ref&) noexcept; @@ -3941,7 +3956,7 @@ memory_order = memory_order::seq_cst) const noexcept; constexpr void notify_one() const noexcept; constexpr void notify_all() const noexcept; - constexpr @\placeholder{floating-point-type}@* address() const noexcept; + constexpr @\exposid{address-return-type}@ address() const noexcept; }; } \end{codeblock} @@ -3979,19 +3994,19 @@ \begin{itemdescr} \pnum \constraints -\tcode{is_const_v<\exposid{floating-point-type}>} is \tcode{false}. +\tcode{is_const_v<\placeholder{floating-point-type}>} is \tcode{false}. \pnum \effects -Atomically replaces the value referenced by \tcode{*ptr} with -the result of the computation applied to the value referenced by \tcode{*ptr} +Atomically replaces the value referenced by \tcode{*\exposid{ptr}} with +the result of the computation applied to the value referenced by \tcode{*\exposid{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} +Atomically, the value referenced by \tcode{*\exposid{ptr}} immediately before the effects. \pnum @@ -4012,27 +4027,27 @@ For \tcode{fetch_fmaximum} and \tcode{fetch_fminimum}, the maximum and minimum computation is performed as if by \tcode{fmaximum} and \tcode{fminimum}, respectively, -with \tcode{*ptr} and the first parameter as the arguments. +with \tcode{*\exposid{ptr}} and the first parameter as the arguments. \item For \tcode{fetch_fmaximum_num} and \tcode{fetch_fminimum_num}, the maximum and minimum computation is performed as if by \tcode{fmaximum_num} and \tcode{fminimum_num}, respectively, -with \tcode{*ptr} and the first parameter as the arguments. +with \tcode{*\exposid{ptr}} and the first parameter as the arguments. \item For \tcode{fetch_max} and \tcode{fetch_min}, the maximum and minimum computation is performed as if by \tcode{fmaximum_num} and \tcode{fminimum_num}, respectively, -with \tcode{*ptr} and the first parameter as the arguments, except that: +with \tcode{*\exposid{ptr}} and the first parameter as the arguments, except that: \begin{itemize} \item -If both arguments are NaN, an unspecified NaN value is stored at \tcode{*ptr}. +If both arguments are NaN, an unspecified NaN value is stored at \tcode{*\exposid{ptr}}. \item If exactly one argument is a NaN, -either the other argument or an unspecified NaN value is stored at \tcode{*ptr}; +either the other argument or an unspecified NaN value is stored at \tcode{*\exposid{ptr}}; it is unspecified which. \item If the arguments are differently signed zeros, -which of these values is stored at \tcode{*ptr} is unspecified. +which of these values is stored at \tcode{*\exposid{ptr}} is unspecified. \end{itemize} \end{itemize} @@ -4068,9 +4083,9 @@ \pnum \effects -Atomically replaces the value referenced by \tcode{*ptr} +Atomically replaces the value referenced by \tcode{*\exposid{ptr}} with the result of the computation applied to -the value referenced by \tcode{*ptr} and the given \tcode{operand}. +the value referenced by \tcode{*\exposid{ptr}} and the given \tcode{operand}. Memory is affected according to the value of \tcode{order}. These operations are atomic modify-write operations\iref{atomics.order}. @@ -4098,23 +4113,23 @@ For \tcode{store_fmaximum} and \tcode{store_fminimum}, the maximum and minimum computation is performed as if by \tcode{fmaximum} and \tcode{fminimum}, respectively, -with \tcode{*ptr} and the first parameter as the arguments. +with \tcode{*\exposid{ptr}} and the first parameter as the arguments. \item For \tcode{store_fmaximum_num} and \tcode{store_fminimum_num}, the maximum and minimum computation is performed as if by \tcode{fmaximum_num }and \tcode{fminimum_num}, respectively, -with \tcode{*ptr} and the first parameter as the arguments. +with \tcode{*\exposid{ptr}} and the first parameter as the arguments. \item For \tcode{store_max} and \tcode{store_min}, the maximum and minimum computation is performed as if by \tcode{fmaximum_num} and \tcode{fminimum_num}, respectively, -with \tcode{*ptr} and the first parameter as the arguments, except that: +with \tcode{*\exposid{ptr}} and the first parameter as the arguments, except that: \begin{itemize} \item -If both arguments are NaN, an unspecified NaN value is stored at \tcode{*ptr}. +If both arguments are NaN, an unspecified NaN value is stored at \tcode{*\exposid{ptr}}. \item If exactly one argument is a NaN, -either the other argument or an unspecified NaN value is stored at \tcode{*ptr}, +either the other argument or an unspecified NaN value is stored at \tcode{*\exposid{ptr}}, it is unspecified which. \item If the arguments are differently signed zeros, @@ -4137,7 +4152,7 @@ \begin{itemdescr} \pnum \constraints -\tcode{is_const_v<\exposid{floating-point-type}>} is \tcode{false}. +\tcode{is_const_v<\placeholder{floating-point-type}>} is \tcode{false}. \pnum \effects @@ -4164,17 +4179,19 @@ namespace std { template<> struct atomic_ref<@\placeholder{pointer-type}@> { private: - @\placeholder{pointer-type}@* ptr; // \expos + @\placeholder{pointer-type}@* @\exposid{ptr}@; // \expos public: using value_type = remove_cv_t<@\placeholder{pointer-type}@>; using difference_type = ptrdiff_t; + using @\exposid{address-return-type}@ = @\placeholdernc{COPYCV}@(@\placeholder{pointer-type}@, void)*; // \expos 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; constexpr explicit atomic_ref(@\placeholder{pointer-type}@&); + explicit atomic_ref(@\placeholder{pointer-type}@&&) = delete; constexpr atomic_ref(const atomic_ref&) noexcept; template constexpr atomic_ref(const atomic_ref&) noexcept; @@ -4224,7 +4241,7 @@ constexpr void wait(value_type, memory_order = memory_order::seq_cst) const noexcept; constexpr void notify_one() const noexcept; constexpr void notify_all() const noexcept; - constexpr @\placeholder{pointer-type}@* address() const noexcept; + constexpr @\placeholder{address-return-type}@ address() const noexcept; }; } \end{codeblock} @@ -4258,15 +4275,15 @@ \pnum \effects -Atomically replaces the value referenced by \tcode{*ptr} with -the result of the computation applied to the value referenced by \tcode{*ptr} +Atomically replaces the value referenced by \tcode{*\exposid{ptr}} with +the result of the computation applied to the value referenced by \tcode{*\exposid{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} +Atomically, the value referenced by \tcode{*\exposid{ptr}} immediately before the effects. \pnum @@ -4313,9 +4330,9 @@ \pnum \effects -Atomically replaces the value referenced by \tcode{*ptr} +Atomically replaces the value referenced by \tcode{*\exposid{ptr}} with the result of the computation applied to -the value referenced by \tcode{*ptr} and the given \tcode{operand}. +the value referenced by \tcode{*\exposid{ptr}} and the given \tcode{operand}. Memory is affected according to the value of \tcode{order}. These operations are atomic modify-write operations\iref{atomics.order}. @@ -4326,7 +4343,7 @@ For \tcode{store_max} and \tcode{store_min}, the \tcode{maximum} and \tcode{minimum} computation is performed as if by \tcode{max} and \tcode{min} algorithms\iref{alg.min.max}, respectively, -with \tcode{*ptr} and the first parameter as the arguments. +with \tcode{*\exposid{ptr}} and the first parameter as the arguments. \begin{note} If the pointers point to different complete objects (or subobjects thereof), the \tcode{<} operator does not establish @@ -4748,19 +4765,19 @@ bool compare_exchange_weak(T& expected, T desired, memory_order success, memory_order failure) volatile noexcept; constexpr bool compare_exchange_weak(T& expected, T desired, - memory_order success, memory_order failure) noexcept; + memory_order success, memory_order failure) noexcept; bool compare_exchange_strong(T& expected, T desired, memory_order success, memory_order failure) volatile noexcept; constexpr bool compare_exchange_strong(T& expected, T desired, - memory_order success, memory_order failure) noexcept; + memory_order success, memory_order failure) noexcept; bool compare_exchange_weak(T& expected, T desired, memory_order order = memory_order::seq_cst) volatile noexcept; constexpr bool compare_exchange_weak(T& expected, T desired, - memory_order order = memory_order::seq_cst) noexcept; + 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; constexpr bool compare_exchange_strong(T& expected, T desired, - memory_order order = memory_order::seq_cst) noexcept; + memory_order order = memory_order::seq_cst) noexcept; \end{itemdecl} \begin{itemdescr} @@ -4796,7 +4813,7 @@ 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 +operations\iref{intro.races} on the memory pointed to by \keyword{this}. Otherwise, these operations are atomic load operations on that memory. @@ -4840,6 +4857,7 @@ \end{example} \pnum +\recommended 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 @@ -4848,9 +4866,11 @@ \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. +the value representations referred to by \tcode{expected} and \keyword{this} +compare equal, +it may return \tcode{false} and +store back to \tcode{expected} +the same value representation that was originally there. \begin{note} This spurious failure enables implementation of compare-and-exchange on a broader class of @@ -5034,52 +5054,52 @@ @\placeholdernc{integral-type}@ exchange(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; constexpr @\placeholdernc{integral-type}@ exchange(@\placeholdernc{integral-type}@, - memory_order = memory_order::seq_cst) noexcept; + memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_weak(@\placeholder{integral-type}@&, @\placeholdernc{integral-type}@, memory_order, memory_order) volatile noexcept; constexpr bool compare_exchange_weak(@\placeholder{integral-type}@&, @\placeholdernc{integral-type}@, - memory_order, memory_order) noexcept; + memory_order, memory_order) noexcept; bool compare_exchange_strong(@\placeholder{integral-type}@&, @\placeholdernc{integral-type}@, memory_order, memory_order) volatile noexcept; constexpr bool compare_exchange_strong(@\placeholder{integral-type}@&, @\placeholdernc{integral-type}@, - memory_order, memory_order) noexcept; + memory_order, memory_order) noexcept; bool compare_exchange_weak(@\placeholder{integral-type}@&, @\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; constexpr bool compare_exchange_weak(@\placeholder{integral-type}@&, @\placeholdernc{integral-type}@, - memory_order = memory_order::seq_cst) noexcept; + memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_strong(@\placeholder{integral-type}@&, @\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; constexpr bool compare_exchange_strong(@\placeholder{integral-type}@&, @\placeholdernc{integral-type}@, - memory_order = memory_order::seq_cst) noexcept; + memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{integral-type}@ fetch_add(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; constexpr @\placeholdernc{integral-type}@ fetch_add(@\placeholdernc{integral-type}@, - memory_order = memory_order::seq_cst) noexcept; + memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{integral-type}@ fetch_sub(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; constexpr @\placeholdernc{integral-type}@ fetch_sub(@\placeholdernc{integral-type}@, - memory_order = memory_order::seq_cst) noexcept; + memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{integral-type}@ fetch_and(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; constexpr @\placeholdernc{integral-type}@ fetch_and(@\placeholdernc{integral-type}@, - memory_order = memory_order::seq_cst) noexcept; + memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{integral-type}@ fetch_or(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; constexpr @\placeholdernc{integral-type}@ fetch_or(@\placeholdernc{integral-type}@, - memory_order = memory_order::seq_cst) noexcept; + memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{integral-type}@ fetch_xor(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; constexpr @\placeholdernc{integral-type}@ fetch_xor(@\placeholdernc{integral-type}@, - memory_order = memory_order::seq_cst) noexcept; + memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{integral-type}@ fetch_max(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; constexpr @\placeholdernc{integral-type}@ fetch_max(@\placeholdernc{integral-type}@, - memory_order = memory_order::seq_cst) noexcept; + memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{integral-type}@ fetch_min(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; constexpr @\placeholdernc{integral-type}@ fetch_min(@\placeholdernc{integral-type}@, - memory_order = memory_order::seq_cst) noexcept; + memory_order = memory_order::seq_cst) noexcept; void store_add(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; @@ -5745,11 +5765,11 @@ bool compare_exchange_weak(T*&, T*, memory_order = memory_order::seq_cst) volatile noexcept; constexpr bool compare_exchange_weak(T*&, T*, - memory_order = memory_order::seq_cst) noexcept; + memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_strong(T*&, T*, memory_order = memory_order::seq_cst) volatile noexcept; constexpr bool compare_exchange_strong(T*&, T*, - memory_order = memory_order::seq_cst) noexcept; + memory_order = memory_order::seq_cst) noexcept; T* fetch_add(ptrdiff_t, memory_order = memory_order::seq_cst) volatile noexcept; constexpr T* fetch_add(ptrdiff_t, memory_order = memory_order::seq_cst) noexcept; @@ -6138,7 +6158,7 @@ constexpr void notify_all() noexcept; private: - shared_ptr p; // \expos + shared_ptr @\exposid{p}@; // \expos }; } \end{codeblock} @@ -6151,7 +6171,7 @@ \begin{itemdescr} \pnum \effects -Value-initializes \tcode{p}. +Value-initializes \exposid{p}. \end{itemdescr} \indexlibraryctor{atomic>}% @@ -6192,7 +6212,7 @@ \pnum \effects Atomically replaces the value pointed to by \keyword{this} with -the value of \tcode{desired} as if by \tcode{p.swap(desired)}. +the value of \tcode{desired} as if by \tcode{\exposid{p}.swap(desired)}. Memory is affected according to the value of \tcode{order}. \end{itemdescr} @@ -6237,7 +6257,7 @@ \pnum \returns -Atomically returns \tcode{p}. +Atomically returns \exposid{p}. \end{itemdescr} \indexlibrarymember{operator shared_ptr}{atomic>}% @@ -6260,14 +6280,14 @@ \begin{itemdescr} \pnum \effects -Atomically replaces \tcode{p} with \tcode{desired} -as if by \tcode{p.swap(desired)}. +Atomically replaces \exposid{p} with \tcode{desired} +as if by \tcode{\exposid{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. +Atomically returns the value of \exposid{p} immediately before the effects. \end{itemdescr} \indexlibrarymember{compare_exchange_weak}{atomic>}% @@ -6289,15 +6309,15 @@ \pnum \effects -If \tcode{p} is equivalent to \tcode{expected}, -assigns \tcode{desired} to \tcode{p} and +If \exposid{p} is equivalent to \tcode{expected}, +assigns \tcode{desired} to \exposid{p} and has synchronization semantics corresponding to the value of \tcode{success}, -otherwise assigns \tcode{p} to \tcode{expected} and +otherwise assigns \exposid{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{true} if \exposid{p} was equivalent to \tcode{expected}, \tcode{false} otherwise. \pnum @@ -6466,7 +6486,7 @@ constexpr void notify_all() noexcept; private: - weak_ptr p; // \expos + weak_ptr @\exposid{p}@; // \expos }; } \end{codeblock} @@ -6479,7 +6499,7 @@ \begin{itemdescr} \pnum \effects -Value-initializes \tcode{p}. +Value-initializes \exposid{p}. \end{itemdescr} \indexlibraryctor{atomic>}% @@ -6520,7 +6540,7 @@ \pnum \effects Atomically replaces the value pointed to by \keyword{this} with -the value of \tcode{desired} as if by \tcode{p.swap(desired)}. +the value of \tcode{desired} as if by \tcode{\exposid{p}.swap(desired)}. Memory is affected according to the value of \tcode{order}. \end{itemdescr} @@ -6554,7 +6574,7 @@ \pnum \returns -Atomically returns \tcode{p}. +Atomically returns \exposid{p}. \end{itemdescr} \indexlibrarymember{operator weak_ptr}{atomic>}% @@ -6577,14 +6597,14 @@ \begin{itemdescr} \pnum \effects -Atomically replaces \tcode{p} with \tcode{desired} -as if by \tcode{p.swap(desired)}. +Atomically replaces \exposid{p} with \tcode{desired} +as if by \tcode{\exposid{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. +Atomically returns the value of \exposid{p} immediately before the effects. \end{itemdescr} \indexlibrarymember{compare_exchange_weak}{atomic>}% @@ -6605,15 +6625,15 @@ \pnum \effects -If \tcode{p} is equivalent to \tcode{expected}, -assigns \tcode{desired} to \tcode{p} and +If \exposid{p} is equivalent to \tcode{expected}, +assigns \tcode{desired} to \exposid{p} and has synchronization semantics corresponding to the value of \tcode{success}, -otherwise assigns \tcode{p} to \tcode{expected} and +otherwise assigns \exposid{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{true} if \exposid{p} was equivalent to \tcode{expected}, \tcode{false} otherwise. \pnum @@ -7088,6 +7108,7 @@ #define @\libmacro{ATOMIC_BOOL_LOCK_FREE}@ @\seebelow@ #define @\libmacro{ATOMIC_CHAR_LOCK_FREE}@ @\seebelow@ +#define @\libmacro{ATOMIC_CHAR8_T_LOCK_FREE}@ @\seebelow@ #define @\libmacro{ATOMIC_CHAR16_T_LOCK_FREE}@ @\seebelow@ #define @\libmacro{ATOMIC_CHAR32_T_LOCK_FREE}@ @\seebelow@ #define @\libmacro{ATOMIC_WCHAR_T_LOCK_FREE}@ @\seebelow@ @@ -7329,7 +7350,7 @@ The implementation provides lock and unlock operations, as described below. For purposes of determining the existence of a data race, these behave as atomic operations\iref{intro.multithread}. The lock and unlock operations on -a single mutex appears to occur in a single total order. +a single mutex appear to occur in a single total order. \begin{note} This can be viewed as the modification order\iref{intro.multithread} of the @@ -7576,10 +7597,10 @@ \tcode{recursive_timed_mutex}, and \tcode{shared_timed_mutex}. They meet the requirements set out below. In this description, \tcode{m} denotes an object of a mutex type, -\tcode{rel_time} denotes an object of an -instantiation of \tcode{duration}\iref{time.duration}, and \tcode{abs_time} denotes an -object of an -instantiation of \tcode{time_point}\iref{time.point}. +\tcode{rel_time} denotes an object of a +specialization of \tcode{duration}\iref{time.duration}, and \tcode{abs_time} denotes an +object of a +specialization of \tcode{time_point}\iref{time.point}. \begin{note} The timed mutex types meet the \oldconcept{TimedLockable} requirements\iref{thread.req.lockable.timed}. @@ -7970,9 +7991,9 @@ shared mutex types\iref{thread.sharedmutex.requirements}, and additionally meet the requirements set out below. In this description, \tcode{m} denotes an object of a shared timed mutex type, -\tcode{rel_time} denotes an object of an instantiation of +\tcode{rel_time} denotes an object of a specialization of \tcode{duration}\iref{time.duration}, and -\tcode{abs_time} denotes an object of an instantiation of +\tcode{abs_time} denotes an object of a specialization of \tcode{time_point}\iref{time.point}. \begin{note} The shared timed mutex types meet the \oldconcept{SharedTimedLockable} @@ -8152,9 +8173,9 @@ struct adopt_lock_t { }; // assume the calling thread has already // obtained mutex ownership and manage it - inline constexpr defer_lock_t defer_lock { }; - inline constexpr try_to_lock_t try_to_lock { }; - inline constexpr adopt_lock_t adopt_lock { }; + inline constexpr defer_lock_t defer_lock { }; + inline constexpr try_to_lock_t try_to_lock { }; + inline constexpr adopt_lock_t adopt_lock { }; } \end{codeblock} @@ -8176,7 +8197,7 @@ lock_guard& operator=(const lock_guard&) = delete; private: - mutex_type& pm; // \expos + mutex_type& @\exposid{pm}@; // \expos }; } \end{codeblock} @@ -8186,7 +8207,7 @@ within a scope. A \tcode{lock_guard} object maintains ownership of a lockable object throughout the \tcode{lock_guard} object's lifetime\iref{basic.life}. The behavior of a program is undefined if the lockable object referenced by -\tcode{pm} does not exist for the entire lifetime of the \tcode{lock_guard} +\exposid{pm} does not exist for the entire lifetime of the \tcode{lock_guard} object. The supplied \tcode{Mutex} type shall meet the \oldconcept{BasicLockable} requirements\iref{thread.req.lockable.basic}. @@ -8198,7 +8219,7 @@ \begin{itemdescr} \pnum \effects -Initializes \tcode{pm} with \tcode{m}. Calls \tcode{m.lock()}. +Initializes \exposid{pm} with \tcode{m}. Calls \tcode{m.lock()}. \end{itemdescr} \indexlibraryctor{lock_guard}% @@ -8213,7 +8234,7 @@ \pnum \effects -Initializes \tcode{pm} with \tcode{m}. +Initializes \exposid{pm} with \tcode{m}. \pnum \throws @@ -8228,7 +8249,7 @@ \begin{itemdescr} \pnum \effects -Equivalent to: \tcode{pm.unlock()} +Equivalent to: \tcode{\exposid{pm}.unlock()} \end{itemdescr} \rSec3[thread.lock.scoped]{Class template \tcode{scoped_lock}} @@ -8249,7 +8270,7 @@ scoped_lock& operator=(const scoped_lock&) = delete; private: - tuple pm; // \expos + tuple @\exposid{pm}@; // \expos }; } \end{codeblock} @@ -8259,7 +8280,7 @@ within a scope. A \tcode{scoped_lock} object maintains ownership of lockable objects throughout the \tcode{scoped_lock} object's lifetime\iref{basic.life}. The behavior of a program is undefined if the lockable objects referenced by -\tcode{pm} do not exist for the entire lifetime of the \tcode{scoped_lock} +\exposid{pm} do not exist for the entire lifetime of the \tcode{scoped_lock} object. \begin{itemize} \item @@ -8283,7 +8304,7 @@ \begin{itemdescr} \pnum \effects -Initializes \tcode{pm} with \tcode{tie(m...)}. +Initializes \exposid{pm} with \tcode{tie(m...)}. Then if \tcode{sizeof...(MutexTypes)} is \tcode{0}, no effects. Otherwise if \tcode{sizeof...(MutexTypes)} is \tcode{1}, then \tcode{m.lock()}. Otherwise, \tcode{lock(m...)}. @@ -8301,7 +8322,7 @@ \pnum \effects -Initializes \tcode{pm} with \tcode{tie(m...)}. +Initializes \exposid{pm} with \tcode{tie(m...)}. \pnum \throws @@ -8317,7 +8338,7 @@ \pnum \effects For all \tcode{i} in \range{0}{sizeof...(MutexTypes)}, -\tcode{get(pm).unlock()}. +\tcode{get(\exposid{pm}).unlock()}. \end{itemdescr} \rSec3[thread.lock.unique]{Class template \tcode{unique_lock}} @@ -8371,8 +8392,8 @@ mutex_type* mutex() const noexcept; private: - mutex_type* pm; // \expos - bool owns; // \expos + mutex_type* @\exposid{pm}@; // \expos + bool @\exposid{owns}@; // \expos }; } \end{codeblock} @@ -8383,8 +8404,8 @@ construction or after construction, and may be transferred, after acquisition, to another \tcode{unique_lock} object. Objects of type \tcode{unique_lock} are not copyable but are movable. The behavior of a program is undefined if the contained pointer -\tcode{pm} is not null and the lockable object pointed -to by \tcode{pm} does not exist for the entire remaining +\exposid{pm} is not null and the lockable object pointed +to by \exposid{pm} does not exist for the entire remaining lifetime\iref{basic.life} of the \tcode{unique_lock} object. The supplied \tcode{Mutex} type shall meet the \oldconcept{BasicLockable} requirements\iref{thread.req.lockable.basic}. @@ -8409,7 +8430,7 @@ \begin{itemdescr} \pnum \ensures -\tcode{pm == nullptr} and \tcode{owns == false}. +\tcode{\exposid{pm} == nullptr} and \tcode{\exposid{owns} == false}. \end{itemdescr} \indexlibraryctor{unique_lock}% @@ -8424,7 +8445,7 @@ \pnum \ensures -\tcode{pm == addressof(m)} and \tcode{owns == true}. +\tcode{\exposid{pm} == addressof(m)} and \tcode{\exposid{owns} == true}. \end{itemdescr} \indexlibraryctor{unique_lock}% @@ -8435,7 +8456,7 @@ \begin{itemdescr} \pnum \ensures -\tcode{pm == addressof(m)} and \tcode{owns == false}. +\tcode{\exposid{pm} == addressof(m)} and \tcode{\exposid{owns} == false}. \end{itemdescr} \indexlibraryctor{unique_lock}% @@ -8455,7 +8476,7 @@ \pnum \ensures -\tcode{pm == addressof(m)} and \tcode{owns == res}, +\tcode{\exposid{pm} == addressof(m)} and \tcode{o\exposid{owns}wns == res}, where \tcode{res} is the value returned by the call to \tcode{m.try_lock()}. \end{itemdescr} @@ -8471,7 +8492,7 @@ \pnum \ensures -\tcode{pm == addressof(m)} and \tcode{owns == true}. +\tcode{\exposid{pm} == addressof(m)} and \tcode{\exposid{owns} == true}. \pnum \throws @@ -8496,7 +8517,7 @@ \pnum \ensures -\tcode{pm == addressof(m)} and \tcode{owns == res}, +\tcode{\exposid{pm} == addressof(m)} and \tcode{\exposid{owns} == res}, where \tcode{res} is the value returned by the call to \tcode{m.try_lock_until(abs_time)}. \end{itemdescr} @@ -8518,7 +8539,7 @@ \pnum \ensures -\tcode{pm == addressof(m)} and \tcode{owns == res}, +\tcode{\exposid{pm} == addressof(m)} and \tcode{\exposid{owns} == res}, where \tcode{res} is the value returned by the call to \tcode{m.try_lock_for(rel_time)}. \end{itemdescr} @@ -8530,7 +8551,7 @@ \begin{itemdescr} \pnum \ensures -\tcode{pm == u_p.pm} and \tcode{owns == u_p.owns} (where \tcode{u_p} is the state of \tcode{u} just prior to this construction), \tcode{u.pm == 0} and \tcode{u.owns == false}. +\tcode{\exposid{pm} == u_p.\exposid{pm}} and \tcode{\exposid{owns} == u_p.\exposid{owns}} (where \tcode{u_p} is the state of \tcode{u} just prior to this construction), \tcode{u.\exposid{pm} == 0} and \tcode{u.\exposid{owns} == false}. \end{itemdescr} \indexlibrarymember{operator=}{unique_lock}% @@ -8556,7 +8577,7 @@ \begin{itemdescr} \pnum \effects -If \tcode{owns} calls \tcode{pm->unlock()}. +If \exposid{owns} calls \tcode{\exposid{pm}->unlock()}. \end{itemdescr} \rSec4[thread.lock.unique.locking]{Locking} @@ -8569,22 +8590,22 @@ \begin{itemdescr} \pnum \effects -As if by \tcode{pm->lock()}. +As if by \tcode{\exposid{pm}->lock()}. \pnum \ensures -\tcode{owns == true}. +\tcode{\exposid{owns} == true}. \pnum \throws -Any exception thrown by \tcode{pm->lock()}. \tcode{system_error} when an exception +Any exception thrown by \tcode{\exposid{pm}->lock()}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} -\item \tcode{operation_not_permitted} --- if \tcode{pm} is \keyword{nullptr}. -\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} +\item \tcode{operation_not_permitted} --- if \exposid{pm} is \keyword{nullptr}. +\item \tcode{resource_deadlock_would_occur} --- if on entry \exposid{owns} is \tcode{true}. \end{itemize} \end{itemdescr} @@ -8602,27 +8623,27 @@ \pnum \effects -As if by \tcode{pm->try_lock()}. +As if by \tcode{\exposid{pm}->try_lock()}. \pnum \ensures -\tcode{owns == res}, where \tcode{res} is the value returned by -\tcode{pm->try_lock()}. +\tcode{\exposid{owns} == res}, where \tcode{res} is the value returned by +\tcode{\exposid{pm}->try_lock()}. \pnum \returns -The value returned by \tcode{pm->try_lock()}. +The value returned by \tcode{\exposid{pm}->try_lock()}. \pnum \throws -Any exception thrown by \tcode{pm->try_lock()}. \tcode{system_error} when an exception +Any exception thrown by \tcode{\exposid{pm}->try_lock()}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} -\item \tcode{operation_not_permitted} --- if \tcode{pm} is \keyword{nullptr}. -\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} +\item \tcode{operation_not_permitted} --- if \exposid{pm} is \keyword{nullptr}. +\item \tcode{resource_deadlock_would_occur} --- if on entry \exposid{owns} is \tcode{true}. \end{itemize} \end{itemdescr} @@ -8641,27 +8662,27 @@ \pnum \effects -As if by \tcode{pm->try_lock_until(abs_time)}. +As if by \tcode{\exposid{pm}->try_lock_until(abs_time)}. \pnum \ensures -\tcode{owns == res}, where \tcode{res} is the value returned by -\tcode{pm->try_lock_until(abs_time)}. +\tcode{\exposid{owns} == res}, where \tcode{res} is the value returned by +\tcode{\exposid{pm}->try_lock_until(abs_time)}. \pnum \returns -The value returned by \tcode{pm->try_lock_until(abs_time)}. +The value returned by \tcode{\exposid{pm}->try_lock_until(abs_time)}. \pnum \throws -Any exception thrown by \tcode{pm->try_lock_until(abstime)}. \tcode{system_error} when an +Any exception thrown by \tcode{\exposid{pm}->try_lock_until(abstime)}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} -\item \tcode{operation_not_permitted} --- if \tcode{pm} is \keyword{nullptr}. -\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is +\item \tcode{operation_not_permitted} --- if \exposid{pm} is \keyword{nullptr}. +\item \tcode{resource_deadlock_would_occur} --- if on entry \exposid{owns} is \tcode{true}. \end{itemize} \end{itemdescr} @@ -8679,26 +8700,26 @@ \pnum \effects -As if by \tcode{pm->try_lock_for(rel_time)}. +As if by \tcode{\exposid{pm}->try_lock_for(rel_time)}. \pnum \ensures -\tcode{owns == res}, where \tcode{res} is the value returned by \tcode{pm->try_lock_for(rel_time)}. +\tcode{\exposid{owns} == res}, where \tcode{res} is the value returned by \tcode{\exposid{pm}->try_lock_for(rel_time)}. \pnum \returns -The value returned by \tcode{pm->try_lock_for(rel_time)}. +The value returned by \tcode{\exposid{pm}->try_lock_for(rel_time)}. \pnum \throws -Any exception thrown by \tcode{pm->try_lock_for(rel_time)}. \tcode{system_error} when an +Any exception thrown by \tcode{\exposid{pm}->try_lock_for(rel_time)}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} -\item \tcode{operation_not_permitted} --- if \tcode{pm} is \keyword{nullptr}. -\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is +\item \tcode{operation_not_permitted} --- if \exposid{pm} is \keyword{nullptr}. +\item \tcode{resource_deadlock_would_occur} --- if on entry \exposid{owns} is \tcode{true}. \end{itemize} \end{itemdescr} @@ -8711,11 +8732,11 @@ \begin{itemdescr} \pnum \effects -As if by \tcode{pm->unlock()}. +As if by \tcode{\exposid{pm}->unlock()}. \pnum \ensures -\tcode{owns == false}. +\tcode{\exposid{owns} == false}. \pnum \throws @@ -8725,7 +8746,7 @@ \pnum \errors \begin{itemize} -\item \tcode{operation_not_permitted} --- if on entry \tcode{owns} is \tcode{false}. +\item \tcode{operation_not_permitted} --- if on entry \exposid{owns} is \tcode{false}. \end{itemize} \end{itemdescr} @@ -8750,11 +8771,11 @@ \begin{itemdescr} \pnum \ensures -\tcode{pm == 0} and \tcode{owns == false}. +\tcode{\exposid{pm} == 0} and \tcode{\exposid{owns} == false}. \pnum \returns -The previous value of \tcode{pm}. +The previous value of \exposid{pm}. \end{itemdescr} \indexlibrarymember{swap}{unique_lock}% @@ -8779,7 +8800,7 @@ \begin{itemdescr} \pnum \returns -\tcode{owns}. +\exposid{owns}. \end{itemdescr} \indexlibrarymember{operator bool}{unique_lock}% @@ -8801,7 +8822,7 @@ \begin{itemdescr} \pnum \returns -\tcode{pm}. +\exposid{pm}. \end{itemdescr} \rSec3[thread.lock.shared]{Class template \tcode{shared_lock}} @@ -8853,8 +8874,8 @@ mutex_type* mutex() const noexcept; private: - mutex_type* pm; // \expos - bool owns; // \expos + mutex_type* @\exposid{pm}@; // \expos + bool @\exposid{owns}@; // \expos }; } \end{codeblock} @@ -8865,8 +8886,8 @@ acquired at construction or after construction, and may be transferred, after acquisition, to another \tcode{shared_lock} object. Objects of type \tcode{shared_lock} are not copyable but are movable. The behavior of a program -is undefined if the contained pointer \tcode{pm} is not null and the lockable -object pointed to by \tcode{pm} does not exist for the entire remaining +is undefined if the contained pointer \exposid{pm} is not null and the lockable +object pointed to by \exposid{pm} does not exist for the entire remaining lifetime\iref{basic.life} of the \tcode{shared_lock} object. The supplied \tcode{Mutex} type shall meet the \oldconcept{SharedLockable} requirements\iref{thread.req.lockable.shared}. @@ -8891,7 +8912,7 @@ \begin{itemdescr} \pnum \ensures -\tcode{pm == nullptr} and \tcode{owns == false}. +\tcode{\exposid{pm} == nullptr} and \tcode{\exposid{owns} == false}. \end{itemdescr} \indexlibraryctor{shared_lock}% @@ -8906,7 +8927,7 @@ \pnum \ensures -\tcode{pm == addressof(m)} and \tcode{owns == true}. +\tcode{\exposid{pm} == addressof(m)} and \tcode{\exposid{owns} == true}. \end{itemdescr} \indexlibraryctor{shared_lock}% @@ -8917,7 +8938,7 @@ \begin{itemdescr} \pnum \ensures -\tcode{pm == addressof(m)} and \tcode{owns == false}. +\tcode{pm == addressof(m)} and \tcode{\exposid{owns} == false}. \end{itemdescr} \indexlibraryctor{shared_lock}% @@ -8932,7 +8953,7 @@ \pnum \ensures -\tcode{pm == addressof(m)} and \tcode{owns == res} +\tcode{\exposid{pm} == addressof(m)} and \tcode{\exposid{owns} == res} where \tcode{res} is the value returned by the call to \tcode{m.try_lock_shared()}. \end{itemdescr} @@ -8949,7 +8970,7 @@ \pnum \ensures -\tcode{pm == addressof(m)} and \tcode{owns == true}. +\tcode{\exposid{pm} == addressof(m)} and \tcode{\exposid{owns} == true}. \end{itemdescr} \indexlibraryctor{shared_lock}% @@ -8971,7 +8992,7 @@ \pnum \ensures -\tcode{pm == addressof(m)} and \tcode{owns == res} +\tcode{\exposid{pm} == addressof(m)} and \tcode{\exposid{owns} == res} where \tcode{res} is the value returned by the call to \tcode{m.try_lock_shared_until(abs_time)}. \end{itemdescr} @@ -8995,7 +9016,7 @@ \pnum \ensures -\tcode{pm == addressof(m)} and \tcode{owns == res} +\tcode{\exposid{pm} == addressof(m)} and \tcode{\exposid{owns} == res} where \tcode{res} is the value returned by the call to \tcode{m.try_lock_shared_for(rel_time)}. \end{itemdescr} @@ -9008,7 +9029,7 @@ \begin{itemdescr} \pnum \effects -If \tcode{owns} calls \tcode{pm->unlock_shared()}. +If \exposid{owns} calls \tcode{\exposid{pm}->unlock_shared()}. \end{itemdescr} \indexlibraryctor{shared_lock}% @@ -9019,9 +9040,9 @@ \begin{itemdescr} \pnum \ensures -\tcode{pm == sl_p.pm} and \tcode{owns == sl_p.owns} (where +\tcode{\exposid{pm} == sl_p.\exposid{pm}} and \tcode{\exposid{owns} == sl_p.\exposid{owns}} (where \tcode{sl_p} is the state of \tcode{sl} just prior to this construction), -\tcode{sl.pm == nullptr} and \tcode{sl.owns == false}. +\tcode{sl.\exposid{pm} == nullptr} and \tcode{sl.\exposid{owns} == false}. \end{itemdescr} \indexlibrarymember{operator=}{shared_lock}% @@ -9049,22 +9070,22 @@ \begin{itemdescr} \pnum \effects -As if by \tcode{pm->lock_shared()}. +As if by \tcode{\exposid{pm}->lock_shared()}. \pnum \ensures -\tcode{owns == true}. +\tcode{\exposid{owns} == true}. \pnum \throws -Any exception thrown by \tcode{pm->lock_shared()}. +Any exception thrown by \tcode{\exposid{pm}->lock_shared()}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} -\item \tcode{operation_not_permitted} --- if \tcode{pm} is \keyword{nullptr}. -\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is +\item \tcode{operation_not_permitted} --- if \exposid{pm} is \keyword{nullptr}. +\item \tcode{resource_deadlock_would_occur} --- if on entry \exposid{owns} is \tcode{true}. \end{itemize} \end{itemdescr} @@ -9077,27 +9098,27 @@ \begin{itemdescr} \pnum \effects -As if by \tcode{pm->try_lock_shared()}. +As if by \tcode{\exposid{pm}->try_lock_shared()}. \pnum \ensures -\tcode{owns == res}, where \tcode{res} is the value returned by -the call to \tcode{pm->try_lock_shared()}. +\tcode{\exposid{owns} == res}, where \tcode{res} is the value returned by +the call to \tcode{\exposid{pm}->try_lock_shared()}. \pnum \returns -The value returned by the call to \tcode{pm->try_lock_shared()}. +The value returned by the call to \tcode{\exposid{pm}->try_lock_shared()}. \pnum \throws -Any exception thrown by \tcode{pm->try_lock_shared()}. +Any exception thrown by \tcode{\exposid{pm}->try_lock_shared()}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} -\item \tcode{operation_not_permitted} --- if \tcode{pm} is \keyword{nullptr}. -\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is +\item \tcode{operation_not_permitted} --- if \exposid{pm} is \keyword{nullptr}. +\item \tcode{resource_deadlock_would_occur} --- if on entry \exposid{owns} is \tcode{true}. \end{itemize} \end{itemdescr} @@ -9116,28 +9137,28 @@ \pnum \effects -As if by \tcode{pm->try_lock_shared_until(abs_time)}. +As if by \tcode{\exposid{pm}->try_lock_shared_until(abs_time)}. \pnum \ensures -\tcode{owns == res}, where \tcode{res} is the value returned by -the call to \tcode{pm->try_lock_shared_until(abs_time)}. +\tcode{\exposid{owns} == res}, where \tcode{res} is the value returned by +the call to \tcode{\exposid{pm}->try_lock_shared_until(abs_time)}. \pnum \returns The value returned by the call to -\tcode{pm->try_lock_shared_until(abs_time)}. +\tcode{\exposid{pm}->try_lock_shared_until(abs_time)}. \pnum \throws -Any exception thrown by \tcode{pm->try_lock_shared_until(abs_time)}. +Any exception thrown by \tcode{\exposid{pm}->try_lock_shared_until(abs_time)}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} -\item \tcode{operation_not_permitted} --- if \tcode{pm} is \keyword{nullptr}. -\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is +\item \tcode{operation_not_permitted} --- if \exposid{pm} is \keyword{nullptr}. +\item \tcode{resource_deadlock_would_occur} --- if on entry \exposid{owns} is \tcode{true}. \end{itemize} \end{itemdescr} @@ -9156,25 +9177,25 @@ \pnum \effects -As if by \tcode{pm->try_lock_shared_for(rel_time)}. +As if by \tcode{\exposid{pm}->try_lock_shared_for(rel_time)}. \pnum \ensures -\tcode{owns == res}, where \tcode{res} is the value returned by the call to \tcode{pm->try_lock_shared_for(rel_time)}. +\tcode{\exposid{owns} == res}, where \tcode{res} is the value returned by the call to \tcode{\exposid{pm}->try_lock_shared_for(rel_time)}. \pnum \returns -The value returned by the call to \tcode{pm->try_lock_shared_for(rel_time)}. +The value returned by the call to \tcode{\exposid{pm}->try_lock_shared_for(rel_time)}. \pnum \throws -Any exception thrown by \tcode{pm->try_lock_shared_for(rel_time)}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. +Any exception thrown by \tcode{\exposid{pm}->try_lock_shared_for(rel_time)}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} -\item \tcode{operation_not_permitted} --- if \tcode{pm} is \keyword{nullptr}. -\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is +\item \tcode{operation_not_permitted} --- if \exposid{pm} is \keyword{nullptr}. +\item \tcode{resource_deadlock_would_occur} --- if on entry \exposid{owns} is \tcode{true}. \end{itemize} \end{itemdescr} @@ -9187,11 +9208,11 @@ \begin{itemdescr} \pnum \effects -As if by \tcode{pm->unlock_shared()}. +As if by \tcode{\exposid{pm}->unlock_shared()}. \pnum \ensures -\tcode{owns == false}. +\tcode{\exposid{owns} == false}. \pnum \throws @@ -9200,7 +9221,7 @@ \pnum \errors \begin{itemize} -\item \tcode{operation_not_permitted} --- if on entry \tcode{owns} is +\item \tcode{operation_not_permitted} --- if on entry \exposid{owns} is \tcode{false}. \end{itemize} \end{itemdescr} @@ -9226,11 +9247,11 @@ \begin{itemdescr} \pnum \ensures -\tcode{pm == nullptr} and \tcode{owns == false}. +\tcode{\exposid{pm} == nullptr} and \tcode{\exposid{owns} == false}. \pnum \returns -The previous value of \tcode{pm}. +The previous value of \exposid{pm}. \end{itemdescr} \indexlibrarymember{swap}{shared_lock}% @@ -9255,7 +9276,7 @@ \begin{itemdescr} \pnum \returns -\tcode{owns}. +\exposid{owns}. \end{itemdescr} \indexlibrarymember{operator bool}{shared_lock}% @@ -9266,7 +9287,7 @@ \begin{itemdescr} \pnum \returns -\tcode{owns}. +\exposid{owns}. \end{itemdescr} \indexlibrarymember{mutex}{shared_lock}% @@ -9277,7 +9298,7 @@ \begin{itemdescr} \pnum \returns -\tcode{pm}. +\exposid{pm}. \end{itemdescr} \rSec2[thread.lock.algorithm]{Generic locking algorithms} @@ -9491,6 +9512,16 @@ \pnum Condition variable construction and destruction need not be synchronized. +\pnum +The definitions in \ref{thread.condition} +make use of the following exposition-only function: +\begin{codeblock} +template + chrono::steady_clock::time_point @\exposid{rel-to-abs}@(const Dur& rel_time) { + return chrono::steady_clock::now() + chrono::ceil(rel_time); + } +\end{codeblock} + \rSec2[condition.variable.syn]{Header \tcode{} synopsis} \indexheader{condition_variable}% @@ -9837,7 +9868,7 @@ \effects Equivalent to: \begin{codeblock} -return wait_until(lock, chrono::steady_clock::now() + rel_time); +return wait_until(lock, @\exposid{rel-to-abs}@(rel_time)); \end{codeblock} \pnum @@ -9947,7 +9978,7 @@ \effects Equivalent to: \begin{codeblock} -return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred)); +return wait_until(lock, @\exposid{rel-to-abs}@(rel_time), std::move(pred)); \end{codeblock} \pnum @@ -10221,7 +10252,7 @@ \effects Equivalent to: \begin{codeblock} -return wait_until(lock, chrono::steady_clock::now() + rel_time); +return wait_until(lock, @\exposid{rel-to-abs}@(rel_time)); \end{codeblock} \pnum @@ -10289,7 +10320,7 @@ \effects Equivalent to: \begin{codeblock} -return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred)); +return wait_until(lock, @\exposid{rel-to-abs}@(rel_time), std::move(pred)); \end{codeblock} \end{itemdescr} @@ -10408,8 +10439,7 @@ \effects Equivalent to: \begin{codeblock} -return wait_until(lock, std::move(stoken), chrono::steady_clock::now() + rel_time, - std::move(pred)); +return wait_until(lock, std::move(stoken), @\exposid{rel-to-abs}@(rel_time), std::move(pred)); \end{codeblock} \end{itemdescr} @@ -10467,7 +10497,7 @@ bool try_acquire_until(const chrono::time_point& abs_time); private: - ptrdiff_t counter; // \expos + ptrdiff_t @\exposid{counter}@; // \expos }; } \end{codeblock} @@ -10497,7 +10527,7 @@ \begin{itemdescr} \pnum \returns -The maximum value of \tcode{counter}. +The maximum value of \exposid{counter}. This value is greater than or equal to \tcode{least_max_value}. \end{itemdescr} @@ -10514,7 +10544,7 @@ \pnum \effects -Initializes \tcode{counter} with \tcode{desired}. +Initializes \exposid{counter} with \tcode{desired}. \pnum \throws @@ -10530,13 +10560,13 @@ \pnum \expects \tcode{update >= 0} is \tcode{true}, and -\tcode{update <= max() - counter} is \tcode{true}. +\tcode{update <= max() - \exposid{counter}} is \tcode{true}. \pnum \effects -Atomically execute \tcode{counter += update}. +Atomically execute \tcode{\exposid{counter} += update}. Then, unblocks any threads -that are waiting for \tcode{counter} to be greater than zero. +that are waiting for \exposid{counter} to be greater than zero. \pnum \sync @@ -10561,11 +10591,11 @@ \begin{itemdescr} \pnum \effects -Attempts to atomically decrement \tcode{counter} if it is positive, +Attempts to atomically decrement \exposid{counter} if it is positive, without blocking. -If \tcode{counter} is not decremented, there is no effect and +If \exposid{counter} is not decremented, there is no effect and \tcode{try_acquire} immediately returns. -An implementation may fail to decrement \tcode{counter} +An implementation may fail to decrement \exposid{counter} even if it is positive. \begin{note} This spurious failure is normally uncommon, but @@ -10578,7 +10608,7 @@ \pnum \returns -\tcode{true} if \tcode{counter} was decremented, otherwise \tcode{false}. +\tcode{true} if \exposid{counter} was decremented, otherwise \tcode{false}. \end{itemdescr} \indexlibrarymember{acquire}{counting_semaphore}% @@ -10594,7 +10624,7 @@ \item Evaluates \tcode{try_acquire()}. If the result is \tcode{true}, returns. \item \indextext{block (execution)}% -Blocks on \tcode{*this} until \tcode{counter} is greater than zero. +Blocks on \tcode{*this} until \exposid{counter} is greater than zero. \end{itemize} \pnum @@ -10627,7 +10657,7 @@ \item \indextext{block (execution)}% Blocks on \tcode{*this} - until \tcode{counter} is greater than zero or until the timeout expires. + until \exposid{counter} is greater than zero or until the timeout expires. If it is unblocked by the timeout expiring, returns \tcode{false}. \end{itemize} The timeout expires\iref{thread.req.timing} @@ -10697,7 +10727,7 @@ void arrive_and_wait(ptrdiff_t update = 1); private: - ptrdiff_t counter; // \expos + ptrdiff_t @\exposid{counter}@; // \expos }; } \end{codeblock} @@ -10720,7 +10750,7 @@ \begin{itemdescr} \pnum \returns -The maximum value of \tcode{counter} that the implementation supports. +The maximum value of \exposid{counter} that the implementation supports. \end{itemdescr} \indexlibraryctor{latch}% @@ -10736,7 +10766,7 @@ \pnum \effects -Initializes \tcode{counter} with \tcode{expected}. +Initializes \exposid{counter} with \tcode{expected}. \pnum \throws @@ -10752,12 +10782,12 @@ \pnum \expects \tcode{update >= 0} is \tcode{true}, and -\tcode{update <= counter} is \tcode{true}. +\tcode{update <= \exposid{counter}} is \tcode{true}. \pnum \effects -Atomically decrements \tcode{counter} by \tcode{update}. -If \tcode{counter} is equal to zero, +Atomically decrements \exposid{counter} by \tcode{update}. +If \exposid{counter} is equal to zero, unblocks all threads blocked on \tcode{*this}. \pnum @@ -10782,7 +10812,7 @@ \begin{itemdescr} \pnum \returns -With very low probability \tcode{false}. Otherwise \tcode{counter == 0}. +With very low probability \tcode{false}. Otherwise \tcode{\exposid{counter} == 0}. \end{itemdescr} \indexlibrarymember{wait}{latch}% @@ -10794,9 +10824,9 @@ \pnum \indextext{block (execution)}% \effects -If \tcode{counter} equals zero, returns immediately. +If \exposid{counter} equals zero, returns immediately. Otherwise, blocks on \tcode{*this} -until a call to \tcode{count_down} that decrements \tcode{counter} to zero. +until a call to \tcode{count_down} that decrements \exposid{counter} to zero. \pnum \throws @@ -10872,7 +10902,7 @@ void arrive_and_drop(); private: - CompletionFunction completion; // \expos + CompletionFunction @\exposid{completion}@; // \expos }; } \end{codeblock} @@ -10909,7 +10939,7 @@ The \defn{phase completion step} that is executed at the end of each phase has the following effects: \begin{itemize} -\item Invokes the completion function, equivalent to \tcode{completion()}. +\item Invokes the completion function, equivalent to \tcode{\exposid{completion}()}. \item Unblocks all threads that are blocked on the phase synchronization point. \end{itemize} The end of the completion step strongly happens before @@ -10937,7 +10967,7 @@ in addition to satisfying the requirements of \tcode{CompletionFunction}, it meets the \oldconcept{DefaultConstructible} requirements (\tref{cpp17.defaultconstructible}) and -\tcode{completion()} has no effects. +\tcode{\exposid{completion}()} has no effects. \pnum \tcode{barrier::arrival_token} is an unspecified type, @@ -10973,7 +11003,7 @@ \effects Sets both the initial expected count for each barrier phase and the current expected count for the first phase to \tcode{expected}. -Initializes \tcode{completion} with \tcode{std::move(f)}. +Initializes \exposid{completion} with \tcode{std::move(f)}. Starts the first phase. \begin{note} If \tcode{expected} is 0 this object can only be destroyed. @@ -11253,7 +11283,7 @@ const char* what() const noexcept; private: - error_code ec_; // \expos + error_code @\exposid{ec_}@; // \expos }; } \end{codeblock} @@ -11266,7 +11296,7 @@ \begin{itemdescr} \pnum \effects -Initializes \tcode{ec_} with \tcode{make_error_code(e)}. +Initializes \exposid{ec_} with \tcode{make_error_code(e)}. \end{itemdescr} \indexlibrarymember{code}{future_error}% @@ -11277,7 +11307,7 @@ \begin{itemdescr} \pnum \returns -\tcode{ec_}. +\exposid{ec_}. \end{itemdescr} \indexlibrarymember{what}{future_error}% @@ -13217,7 +13247,7 @@ \indexlibraryglobal{rcu_retire}% \begin{itemdecl} template> -void rcu_retire(T* p, D d = D(), rcu_domain& dom = rcu_default_domain()); + void rcu_retire(T* p, D d = D(), rcu_domain& dom = rcu_default_domain()); \end{itemdecl} \begin{itemdescr} diff --git a/source/time.tex b/source/time.tex index 023b13bf6b..a29b08edf7 100644 --- a/source/time.tex +++ b/source/time.tex @@ -160,19 +160,19 @@ minutes* offset = nullptr); // convenience typedefs - using nanoseconds = duration<@\term{signed integer type of at least 64 bits}@, nano>; - using microseconds = duration<@\term{signed integer type of at least 55 bits}@, micro>; - using milliseconds = duration<@\term{signed integer type of at least 45 bits}@, milli>; - using seconds = duration<@\term{signed integer type of at least 35 bits}@>; - using minutes = duration<@\term{signed integer type of at least 29 bits}@, ratio< 60>>; - using hours = duration<@\term{signed integer type of at least 23 bits}@, ratio<3600>>; - using days = duration<@\term{signed integer type of at least 25 bits}@, + using nanoseconds = duration<@\placeholder{signed integer type of at least 64 bits}@, nano>; + using microseconds = duration<@\placeholder{signed integer type of at least 55 bits}@, micro>; + using milliseconds = duration<@\placeholder{signed integer type of at least 45 bits}@, milli>; + using seconds = duration<@\placeholder{signed integer type of at least 35 bits}@>; + using minutes = duration<@\placeholder{signed integer type of at least 29 bits}@, ratio< 60>>; + using hours = duration<@\placeholder{signed integer type of at least 23 bits}@, ratio<3600>>; + using days = duration<@\placeholder{signed integer type of at least 25 bits}@, ratio_multiply, hours::period>>; - using weeks = duration<@\term{signed integer type of at least 22 bits}@, + using weeks = duration<@\placeholder{signed integer type of at least 22 bits}@, ratio_multiply, days::period>>; - using years = duration<@\term{signed integer type of at least 17 bits}@, + using years = duration<@\placeholder{signed integer type of at least 17 bits}@, ratio_multiply, days::period>>; - using months = duration<@\term{signed integer type of at least 20 bits}@, + using months = duration<@\placeholder{signed integer type of at least 20 bits}@, ratio_divide>>; // \ref{time.point.nonmember}, \tcode{time_point} arithmetic @@ -1287,7 +1287,10 @@ \pnum \tcode{Rep} shall be an arithmetic type or a class emulating an arithmetic type. -If \tcode{duration} is instantiated with a \tcode{duration} type as the argument for the template +If a specialization of \tcode{duration} +is instantiated with +a cv-qualified type or a specialization of \tcode{duration} +as the argument for the template parameter \tcode{Rep}, the program is ill-formed. \pnum @@ -9251,11 +9254,11 @@ \begin{codeblock} namespace std::chrono { struct sys_info { - sys_seconds begin; - sys_seconds end; - seconds offset; - minutes save; - string abbrev; + sys_seconds begin; + sys_seconds end; + seconds offset; + minutes save; + string abbrev; }; } \end{codeblock} @@ -10788,11 +10791,17 @@ the locale's alternate time representation. \\ \rowsep \tcode{\%y} & -The last two decimal digits of the year. +The last two decimal digits of the year, +regardless of the sign of the year. If the result is a single digit, it is prefixed by \tcode{0}. The modified command \tcode{\%Oy} produces the locale's alternative representation. The modified command \tcode{\%Ey} produces the locale's alternative representation of offset from \tcode{\%EC} (year only). +\begin{tailexample} +\begin{codeblock} +cout << format("{:%C %y}", -1976y); // prints \tcode{-20 76} +\end{codeblock} +\end{tailexample} \\ \rowsep \tcode{\%Y} & The year as a decimal number. @@ -11465,7 +11474,8 @@ The modified command \tcode{\%EX} interprets the locale's alternate time representation. \\ \rowsep \tcode{\%y} & -The last two decimal digits of the year. +The last two decimal digits of the year, +regardless of the sign of the year. If the century is not otherwise specified (e.g., with \tcode{\%C}), values in the range \crange{69}{99} @@ -11478,6 +11488,12 @@ Leading zeroes are permitted but not required. The modified commands \tcode{\%Ey} and \tcode{\%Oy} interpret the locale's alternative representation. +\begin{tailexample} +\begin{codeblock} +year y; +istringstream{"-20 76"} >> parse("%3C %y", y); // \tcode{y == -1976y} is \tcode{true} +\end{codeblock} +\end{tailexample} \\ \rowsep \tcode{\%Y} & The year as a decimal number. diff --git a/source/ub.tex b/source/ub.tex new file mode 100644 index 0000000000..10fe4ce995 --- /dev/null +++ b/source/ub.tex @@ -0,0 +1,2069 @@ +%!TEX root = std.tex +\infannex{ub}{Enumeration of Core Undefined Behavior} + +\rSec1[ub.general]{General} + +This Annex documents undefined behavior explicitly called out in the main standard text using the +following phrases: the behavior of the program is undefined, has undefined behavior, results in +undefined behavior, the behavior is undefined, have undefined behavior, is undefined, result has +undefined behavior. Undefined behavior that is implicit is not covered by this annex. Each entry contains +a title, a numeric cross reference to the main standard text, a summary of the issue and a code example +demonstrating the issue. The code examples are there to clarify the undefined behavior and will not +exhaustively cover all possible ways of invoking that case. + +\rSec1[ub.basic]{\ref{basic}: Basics} + +\rSec2[ub.intro.object]{Implicitly creating object and undefined behavior} + +\pnum +\ubxref{intro.object.implicit.create} +For each +operation that is specified as implicitly creating objects, that operation implicitly creates and starts the +lifetime of zero or more objects of implicit-lifetime types\iref{basic.types} in its specified region of storage if doing so +would result in the program having defined behavior. If no such set of objects would give the program defined +behavior, the behavior of the program is undefined. + +\pnum +\begin{example} +\begin{codeblock} +void f() +{ + void *p = malloc(sizeof(int) + sizeof(float)); + *reinterpret_cast(p) = 0; + *reinterpret_cast(p) = 0.0f; // undefined behavior, cannot create + // both \tcode{int} and \tcode{float} in same place +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{intro.object.implicit.pointer} +After implicitly creating objects within a specified region of storage, +some operations are described as producing a pointer to a +suitable created object\iref{basic.types}. +These operations select one of the implicitly-created objects +whose address is the address of the start of the region of storage, +and produce a pointer value that points to that object, +if that value would result in the program having defined behavior. +If no such pointer value would give the program defined behavior, +the behavior of the program is undefined. + +\pnum +\begin{example} +\begin{codeblock} +#include +struct X { + int a, b; + ~X() = delete; // deleted destructor makes \tcode{X} a non-implicit-lifetime class +}; + +X* make_x() { + // The call to \tcode{std::malloc} can not implicitly create an object of type \tcode{X} + // because \tcode{X} is not an implicit-lifetime class. + X* p = (X*)std::malloc(sizeof(struct X)); + p->a = 1; // undefined behavior, no set of objects give us defined behavior + return p; +} +\end{codeblock} +\end{example} +\begin{example} +\begin{codeblock} +#include + +struct X { + int a; +}; + +struct Y { + int x; +}; + +*make_y() { + X* p1 = (X*)std::malloc(sizeof(struct X)); + p1->a = 1; + Y* p2 = (Y*)p1; + p2->x = 2; // undefined behavior, lifetime of \tcode{p1} was started but not + // ended and lifetime of \tcode{p2} was not started. + return p2; +} +\end{codeblock} +\end{example} + +%TODO: SY: These comments feel too loose. +%Shouldn't we be saying something along the lines of p1 points to an +%object of type X whose lifetime was started but not ended .... p2 +%points to an object of type Y but its lifetime was not started ..." + +\rSec2[ub.basic.align]{Object alignment} + +\pnum +\ubxref{basic.align.object.alignment} +All instances of a type must be created in storage that meets the alignment +requirement of that type. + +\pnum +\begin{example} +\begin{codeblock} +struct alignas(4) S {}; + +void make_misaligned() +{ + alignas(S) char s[sizeof(S) + 1]; + new (&s+1) S(); // undefined behavior, \tcode{\&s+1} will yield a pointer to + // a \tcode{char} which is $1$ byte away from an address with + // an alignment of $4$ and so cannot have an alignment of $4$. +} +\end{codeblock} +\end{example} + +\rSec2[ub.basic.life]{Object lifetime} + +\pnum +\ubxref{lifetime.outside.pointer.delete} +For a pointer pointing to an object outside of its lifetime, behavior is +undefined if the object will be or was of a class type with a non-trivial destructor +and the pointer is used as the operand of a \grammarterm{delete-expression}. + +\pnum +\begin{example} +\begin{codeblock} +struct S { + float f = 0; + ~S() {} +}; + +void f() { + S* p = new S; + p->~S(); + delete p; // undefined behavior, operand of delete, lifetime has ended and \tcode{S} + // has a non-trivial destructor +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{lifetime.outside.pointer.member} +For a pointer pointing to an object outside of its lifetime, behavior is +undefined if the pointer is used to access a non-static data member or call a +non-static member function of the object. + +\pnum +\begin{example} +\begin{codeblock} +struct S { + float f = 0; +}; + +float f() { + S s; + S* p = &s; + s.~S(); + return p->f; // undefined behavior, accessing non-static data member after + // end of lifetime +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{lifetime.outside.pointer.virtual} +For a pointer pointing to an object outside of its lifetime, behavior is +undefined if the pointer is implicitly converted\iref{conv.ptr} to a pointer +to a virtual base class (or base class of a virtual base class). + +\pnum +\begin{example} +\begin{codeblock} +struct B {}; +struct D : virtual B {}; +void f() { + D d; + D* p = &d; + d.~D(); + B* b = p; // undefined behavior +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{lifetime.outside.pointer.dynamic.cast} +For a pointer pointing to an object outside of its lifetime, behavior is +undefined if the pointer is used as the operand of a +\tcode{dynamic_cast}\iref{expr.dynamic.cast}. + +\pnum +\begin{example} +\begin{codeblock} +struct B { virtual ~B() = default; }; +struct D : B {}; +void f() +{ + D d; + B* bp = &d; + d.~D(); + D* dp = dynamic_cast(bp); // undefined behavior +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{lifetime.outside.glvalue.access} +Behavior is undefined if a glvalue referring to an object outside of its +lifetime is used to access the object. + +\pnum +\begin{example} +\begin{codeblock} +void f() { + int x = int{10}; + using T = int; + x.~T(); + int y = x; // undefined behavior, glvalue used to access the + // object after the lifetime has ended +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{lifetime.outside.glvalue.member} +Behavior is undefined if a glvalue referring to an object outside of its +lifetime is used to call a non-static member function of the object. + +\pnum +\begin{example} +\begin{codeblock} +struct A { + void f() {} +}; + +void f() { + A a; + a.~A(); + a.f(); // undefined behavior, glvalue used to access a + // non-static member function after the lifetime has ended +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{lifetime.outside.glvalue.virtual} +Behavior is undefined if a glvalue referring to an object outside of its +lifetime is bound to a reference to a virtual base class. + +\pnum +\begin{example} +\begin{codeblock} +struct B {}; +struct D : virtual B { +}; + +void f() { + D d; + d.~D(); + B& b = d; // undefined behavior +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{lifetime.outside.glvalue.dynamic.cast} +Behavior is undefined if a glvalue referring to an object outside of its +lifetime is used as the operand of a +\keyword{dynamic_cast} or as the operand of \keyword{typeid}. + +\pnum +\begin{example} +\begin{codeblock} +struct B { virtual ~B(); }; +struct D : virtual B {}; + +void f() { + D d; + B& br = d; + d.~D(); + D& dr = dynamic_cast(br); // undefined behavior +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{original.type.implicit.destructor} +The behavior is undefined if +a non-trivial implicit destructor call +occurs when the type of the object inhabiting the associated storage +is not the original type associated with that storage. + +\pnum +\begin{example} +\begin{codeblock} +class T {}; + +struct B { + ~B(); +}; + +void h() { + B b; + new (&b) T; +} // undefined behavior at block exit +\end{codeblock} +\end{example} + + +\pnum +\ubxref{creating.within.const.complete.obj} +Creating a new object within the storage that a const complete object with static, thread, or automatic +storage duration occupies, or within the storage that such a const object used to occupy before its lifetime +ended, results in undefined behavior + +\pnum +\begin{example} +\begin{codeblock} +struct B { + B(); + ~B(); +}; + +const B b; + +void h() { + b.~B(); + new (const_cast(&b)) const B; // undefined behavior +} +\end{codeblock} +\end{example} + +\rSec2[ub.basic.indet]{Indeterminate and erroneous values} + +\pnum +\ubxref{basic.indet.value} +When the result of an evaluation is +an indeterminate value +(but not just an erroneous value) +the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +void g() { + int x [[ indeterminate ]]; + int y = x; // undefined behavior +} +\end{codeblock} +\end{example} + +\rSec2[ub.basic.stc.dynamic]{Dynamic storage Duration} + +\pnum +\ubxref{basic.stc.alloc.dealloc.constraint} +If the behavior of an allocation or deallocation function does not satisfy the semantic constraints +specified +in~\ref{basic.stc.dynamic.allocation} and~\ref{basic.stc.dynamic.deallocation}. +the behavior is undefined. + + +\pnum +\begin{example} +\begin{codeblock} +#include +void* operator new(std::size_t sz) { + if (sz == 0) + return nullptr; // undefined behavior, should return non-null pointer + + return std::malloc(1); // undefined behavior, if successful should return allocation with + // length in bytes is at least as large as the requested size +} +void operator delete(void* ptr) noexcept { + throw 0; // undefined behavior, terminates by throwing an exception +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{basic.stc.alloc.dealloc.throw} +If a call to a deallocation function +terminates by throwing an exception +the behavior is undefined. +\pnum +\begin{example} +\begin{codeblock} +struct X { + void operator delete(void*) { throw "oops"; } +}; +void f() +{ + X* x = new X(); + delete x; // undefined behavior +} +\end{codeblock} +\end{example} + + + +\rSec2[ub.basic.stc.alloc.zero.dereference]{Zero-sized allocation dereference} + +\pnum +\ubxref{basic.stc.alloc.zero.dereference} +The pointer returned when invoking an allocation function with a size of zero +cannot be dereferenced. + +\pnum +\begin{example} +\begin{codeblock} +void test() +{ + char* c = static_cast(operator new(0z)); + c[0] = 'X'; // undefined behavior +} +\end{codeblock} +\end{example} + +\rSec2[ub.basic.compound]{Compound types} + +\pnum +\ubxref{basic.compound.invalid.pointer} +Indirection or +the invocation of a deallocation function +with a pointer value referencing storage +that has been freed +has undefined behavior. +(Most other uses of such a pointer have +implemention-defined behavior.) + +\pnum +\begin{example} +\begin{codeblock} +void f() +{ + int *x = new int{5}; + delete x; + int y = *x; // undefined behavior + delete x; // undefined behavior +} +\end{codeblock} +\end{example} + + +\rSec2[ub.intro.execution]{Sequential execution} + +\pnum +\ubxref{intro.execution.unsequenced.modification} +If a side effect on a +memory location\iref{intro.memory} is unsequenced relative to either another side effect on the same memory location or +a value computation using the value of any object in the same memory location, and they are not potentially +concurrent\iref{intro.multithread}, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +void g(int i) { + i = 7, i++, i++; // i becomes 9 + + i = i++ + 1; // the value of i is incremented + i = i++ + i; // undefined behavior + i = i + 1; // the value of i is incremented +} +\end{codeblock} +\end{example} + +\rSec2[ub.intro.races]{Data races} + +\pnum +\ubxref{intro.races.data} +The execution of a program contains a data race if it contains two potentially concurrent conflicting actions, +at least one of which is not atomic, and neither happens before the other, except for the special case for +signal handlers described in~\ref{intro.races}. Any such data race results in undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +int count = 0; +auto f = [&] { count++; }; +std::thread t1{f}, t2{f}, t3{f}; +// undefined behavior t1, t2 and t3 have a data race on access of variable count +\end{codeblock} +\end{example} + +\rSec2[ub.intro.progress]{Forward progress} + +\pnum +\ubxref{intro.progress.stops} +The behavior is undefined if a thread of execution that has not terminated stops +making execution steps. + +\pnum +\begin{example} +\begin{codeblock} +bool stop() { return false; } + +void busy_wait_thread() { + while (!stop()); // undefined behavior, thread makes no progress but the loop +} // is not trivial because `stop()` is not a constant expression + +int main() { + std::thread t(busy_wait_thread); + t.join(); +} +\end{codeblock} +\end{example} + +\rSec2[ub.basic.start.main]{main function} + +\pnum +\ubxref{basic.start.main.exit.during.destruction} +If \tcode{std::exit} is called to +end a program during the destruction of an object with static or thread storage duration, the program has +undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include + +struct Exiter { + ~Exiter() { std::exit(0); } +}; + +Exiter ex; + +int main() {} +// undefined behavior when destructor of static variable \tcode{ex} is called it will call \tcode{std::exit} +\end{codeblock} +\end{example} + + +\rSec2[ub.basic.start.term]{Termination} + +\pnum +\ubxref{basic.start.term.use.after.destruction} +If a function contains a block-scope object of static or thread storage duration that has been destroyed and the +function is called during the destruction of an object with static or thread storage duration, the program has +undefined behavior if the flow of control passes through the definition of the previously destroyed block-scope +object. Likewise, the behavior is undefined if the block-scope object is used indirectly (i.e., through a pointer) +after its destruction. + +\pnum +\begin{example} +\begin{codeblock} +struct A {}; +void f() { + static A a; +} + +struct B { + B() { f(); } +}; +struct C { + ~C() { f(); } +}; + +C c; +B b; // call to `f()` in constructor begins lifetime of \tcode{a} + +int main() {} +// undefined behavior, static objects are destructed in reverse order, in this case \tcode{a} then \tcode{b} and +// finally \tcode{c}. When the destructor of \tcode{c} is called, it calls \tcode{f()} which passes through the definition of +// previously destroyed block-scope object +\end{codeblock} +\end{example} + + +\pnum +\ubxref{basic.start.term.signal.handler} +If there is a use of a standard library object or function not permitted within signal handlers\iref{support.runtime} that +does not happen before\iref{intro.multithread} completion of destruction of objects with static storage duration and execution +of std::atexit registered functions\iref{support.start.term}, the program has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +\end{codeblock} +\end{example} + +%TODO: JMB/TD: This is really a general precondition imposed on the Standard +%Library, not a piece of core language undefined behavior. It is also currently +%missing an example. Should we retain this UB? Should we have a core issue +%to move this wording into the library section somewhere? +%TODO: SY: If we keep this, we should have an example. + +\rSec1[ub.expr]{\ref{expr}: Expressions} +\rSec2[ub.expr.eval]{Result of Expression not Mathematically Defined/out of Range} + +\pnum +\ubxref{expr.expr.eval} +If during the evaluation of an expression, the result is not mathematically defined or not in the range of +representable values for its type, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +#include +int main() { + // Assuming 32-bit int the range of values are: $-2,147,483,648$ to $2,147,483,647$ + int x1 = std::numeric_limits::max() + 1; + // undefined behavior, $2,147,483,647 + 1$ is not representable as an int + int x2 = std::numeric_limits::min() / -1; + // undefined behavior, $-2,147,483,648 / -1$ is not representable as an int +} +\end{codeblock} +\end{example} + +\rSec2[ub.basic.lval]{Value category} + +\pnum +\ubxref{expr.basic.lvalue.strict.aliasing.violation} +If a program attempts to access\iref{defns.access} the stored value of an object +whose dynamic type is $T$ through a glvalue whose type is not +similar\iref{conv.rval} to $T$ (or its corresponding signed or unsigned types) +the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +int foo(float* f, int* i) { + *i = 1; + *f = 0.f; // undefined behavior, glvalue is not similar to \tcode{int} + + return *i; +} + +int main() { + int x = 0; + + x = foo(reinterpret_cast(&x), &x); +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.basic.lvalue.union.initialization} +If a program invokes a defaulted copy/move constructor or +defaulted copy/move assignment +operator of a union with an argument that is not an object of a similar type +within its lifetime, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +union U { int x; }; +void f() +{ + char u[sizeof(U)]; + U o = reinterpret_cast(u); // undefined behavior +} +\end{codeblock} +\end{example} + +\rSec2[ub.expr.type]{Type} + +\pnum +\ubxref{expr.type.reference.lifetime} +Evaluating a reference when an equivalent use of a pointer denoting the same object +would be invalid has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +void g() +{ + int* ip = new int(5); + int& i = *ip; + delete ip; + i; // undefined behavior +} +\end{codeblock} +\end{example} + +\rSec2[ub.conv.lval]{Lvalue-to-rvalue conversion} + +\pnum +\ubxref{conv.lval.valid.representation} +Performing an +lvalue-to-rvalue conversion +on an object whose +value representation +is not valid for its type +has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +bool f() { + bool b = true; + char c = 42; + memcpy(&b, &c, 1); + return b; // undefined behavior if \tcode{42} is not a valid value representation for \keyword{bool} +} +\end{codeblock} +\end{example} + + +\rSec2[ub.conv.double]{Floating-point conversions} + +\pnum +\ubxref{conv.double.out.of.range} +Converting a floating point value to a type that cannot represent the value is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include + +int main() { + // Assuming 32-bit int, 32-bit float and 64-bit double + double d2 = std::numeric_limits::max(); + float f = d2; // undefined behavior on systems where the range of + // representable values of float is [-max,+max] on system where + // representable values are [-inf,+inf] this would not be UB + int i = d2; // undefined behavior, the max value of double is not representable as int +} +\end{codeblock} +\end{example} + + +\rSec2[ub.conv.fpint]{Floating-integral conversions} + +\pnum +\ubxref{conv.fpint.int.not.represented} +When converting a floating-point value to an integer type and vice versa if +the value is not representable in the destination type it is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include + +int main() { + // Assuming 32-bit int the range of values are: $-2,147,483,648$ to + // $2,147,483,647$ Assuming 32-bit float and 64-bit double + double d = (double)std::numeric_limits::max() + 1; + int x1 = d; // undefined behavior $2,147,483,647 + 1$ is not representable as int +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{conv.fpint.float.not.represented} +When converting a value of integer or unscoped enumeration type to a +floating-point type, if the value is not representable in the destination type +it is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +int main() { + __uint128_t x2 = -1; + float f = x2; // undefined behavior on systems where the range of + // representable values of float is [-max,+max] on system where + // represetable values are [-inf,+inf] this would not be UB +} +\end{codeblock} +\end{example} + +\rSec2[ub.conv.ptr]{Pointer conversions} + +\pnum +\ubxref{conv.ptr.virtual.base} +Converting +a pointer to a derived class \tcode{D} +to +a pointer to a virtual base class \tcode{B} +that does not point to +a valid object +within its lifetime +has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct B {}; +struct D : virtual B {}; +void f() +{ + D ds[1]; + B* b = &ds[1]; // undefined behavior +} +\end{codeblock} +\end{example} + +\rSec2[ub.conv.mem]{Pointer-to-member conversions} + +\pnum +\ubxref{conv.member.missing.member} +The conversion of +a pointer to a member of a base class +to a pointer to member of a derived class +that could not contain that member +has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct B {}; +struct D1 : B { int d1; }; +struct D2 : B {}; +void f() +{ + int (D1::*pd1) = &D1::d1; + int (B::*pb) = static_cast(pd1); + int (D2::*pd2) = pb; // undefined behavior +} +\end{codeblock} +\end{example} + + + +\rSec2[ub.expr.call]{Function call} + +\pnum +\ubxref{expr.call.different.type} +Calling a function through an expression whose +function type is not call-compatible with +the function type of the called +function's definition results in undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +using f_float = int (*)(float); +using f_int = int (*)(int); + +int f1(float) { return 10; } + +int f2(int) { return 20; } + +int main() { + return reinterpret_cast(f1)(20); // undefined behavior, the function type of the expression + // is different from the called functions definition +} +\end{codeblock} +\end{example} + +\rSec2[ub.expr.ref]{Class member access} + +\pnum +\ubxref{expr.ref.member.not.similar} +If \tcode{E2} is a non-static member and the result of \tcode{E1} is an object whose type +is not similar\iref{conv.qual} to the type of \tcode{E1}, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct A { int i; }; +struct B { int j; }; +struct D : A, B {}; +void f() { + D d; + reinterpret_cast(d).j; // undefined behavior +} +\end{codeblock} +\end{example} + +%TODO: SY: The wording is not great, I don't have a good suggestion but we should +%get some opinions + +\rSec2[ub.expr.dynamic.cast]{Dynamic cast} + + +\pnum +\ubxref{expr.dynamic.cast.pointer.lifetime} +Evaluating a \keyword{dynamic_cast} on a non-null pointer that points to +an object (of polymorphic type) of the wrong type or to an object +not within its lifetime has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct B { virtual ~B(); }; +void f() { + B bs[1]; + B* dp = dynamic_cast(bs+1); // undefined behavior +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{expr.dynamic.cast.glvalue.lifetime} +Evaluating a \keyword{dynamic_cast} on a reference that +denotes an object (of polymorphic type) of the wrong type or an object +not within its lifetime has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct B { virtual ~B(); }; +void f() { + B bs[1]; + B& dr = dynamic_cast(bs[1]); // undefined behavior +} +\end{codeblock} +\end{example} + +\rSec2[ub.expr.static.cast]{Static cast} + +\pnum +\ubxref{expr.static.cast.base.class} +We can cast a base class B to a reference to derived class D (with certain restrictions wrt to cv qualifiers) +as long B is a base class subobject of type D, otherwise the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct B {}; +struct D1 : B {}; +struct D2 : B {}; + +void f() { + D1 d; + B &b = d; + static_cast(b); // undefined behavior, base class object of type \tcode{D1} not \tcode{D2} +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.static.cast.enum.outside.range} +If the enumeration type does not have a fixed underlying +type, the value is unchanged if the original value is within the range of the enumeration values\iref{dcl.enum}, and +otherwise, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +enum A { e1 = 1, e2 }; + +void f() { + enum A a = static_cast(4); // undefined behavior, 4 is not with the range of enumeration values +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.static.cast.fp.outside.range} +An explicit conversion of a +floating-point value that is outside the range of the +target type has undefined behavior. + +\pnum +\begin{example} +If \tcode{float} does not adhere to \IsoFloatUndated{} +and cannot represent positive infinty, +a sufficiently large \tcode{double} value will be +outside the (finite) range of \tcode{float}. +\begin{codeblock} +void f() { + double d = FLT_MAX; + d *= 16; + float f = static_cast(d); // undefined behavior. +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{expr.static.cast.downcast.wrong.derived.type} +Casting from a pointer to a base class to a pointer to a derived class +when there is no enclosing object of that derived class at the +specified location has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct B {}; +struct D1 : B {}; +struct D2 : B {}; + +void f() { + B *bp = new D1; + static_cast(bp); // undefined behavior, base class object of type \tcode{D1} not \tcode{D2} +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.static.cast.does.not.contain.orignal.member} +A +pointer to member of derived class D +can be cast to +a pointer to member of base class B +(with certain restrictions on cv qualifiers) +as long as B contains the original member, +or is a base or derived class of the class +containing the original member; +otherwise the behavior is undefined. + + +\pnum +\begin{example} +\begin{codeblock} +struct A { + char c; +}; + +struct B { + int i; +}; + +struct D : A, B {}; + +int main() { + char D::*p1 = &D::c; + char B::*p2 = static_cast(p1); // undefined behavior, \tcode{B} does not contain the original member \tcode{c} +} +\end{codeblock} +\end{example} + +\rSec2[ub.expr.unary.op]{Unary operators} + +\pnum +\ubxref{expr.unary.dereference} +Dereferencing a pointer that does not point to an object or function +has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +int f() +{ + int *p = nullptr; + return *p; // undefined behavior +} +\end{codeblock} +\end{example} + + +\rSec2[ub.expr.new]{New} + +\pnum +\ubxref{expr.new.non.allocating.null} +If the allocation +function is a non-allocating form\iref{new.delete.placement} that returns null, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +#include +[[nodiscard]] void* operator new(std::size_t size, void* ptr) noexcept { + return nullptr; // undefined behavior, should return non-null pointer +} +\end{codeblock} +\end{example} +\begin{example} +\begin{codeblock} +#include + +struct A { + int x; +}; + +int main() { + char *p = nullptr; + A *a = new (p) A; // undefined behavior, non-allocting new returning nullptr +} +\end{codeblock} +\end{example} + + +\rSec2[ub.expr.delete]{Delete} + +\pnum +\ubxref{expr.delete.mismatch} +Using array delete on the result of a single object new expression is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +int* x = new int; +delete[] x; // undefined behavior, allocated using single object new expression +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.delete.array.mismatch} +Using single object delete on the result of an array new expression is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +int* x = new int[10]; +delete x; // undefined behavior, allocated using array new expression +\end{codeblock} +\end{example} + + +\pnum +\ubxref{expr.delete.dynamic.type.differ} +If the static type of the object to be deleted is different from its dynamic +type and the selected deallocation function is not a destroying operator delete, the static type +shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual +destructor or the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct B { + int a; +}; + +struct D : public B { + int b; +}; + +void f() { + B* b = new D; + delete b; // undefined behavior, no virtual destructor +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{expr.delete.dynamic.array.dynamic.type.differ} +In an array delete expression, if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct B { + virtual ~B(); + void operator delete[](void*, std::size_t); +}; + +struct D : B { + void operator delete[](void*, std::size_t); +}; + +void f(int i) { + D* dp = new D[i]; + delete[] dp; // uses \tcode{D::operator delete[](void*, std::size_t)} + B* bp = new D[i]; + delete[] bp; // undefined behavior +} +\end{codeblock} +\end{example} + + +\rSec2[ub.expr.mptr.oper]{Pointer-to-member operators} + +\pnum +\ubxref{expr.mptr.oper.not.contain.member} +Abbreviating \grammarterm{pm-expression}.*\grammarterm{cast-expression} as \tcode{E1.*E2}, \tcode{E1} is called the object expression. If the dynamic type +of \tcode{E1} does not contain the member to which \tcode{E2} refers, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct B {}; +struct D : B { + int x; +}; + +void f() { + B *b = new B; + D *d = static_cast(b); + int D::*p = &D::x; + (*d).*p = 1; // undefined behavior, dynamic type \tcode{B} does not contain \tcode{x} +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{expr.mptr.oper.member.func.null} +If the second operand in a \tcode{.*} expression is the null +member pointer value\iref{conv.mem}, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct S { + int f(); +}; + +void f() { + S cs; + int (S::*pm)() = nullptr; + (cs.*pm)(); // undefined behavior, the second operand is null +} +\end{codeblock} +\end{example} + + +\rSec2[ub.expr.mul]{Multiplicative operators} + +\pnum +\ubxref{expr.mul.div.by.zero} +Division by zero is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +int main() { + int x = 1 / 0; // undefined behavior, division by zero + double d = 1.0 / 0.0; // undefined behavior on systems where the range of + // representable values of float is [-max,+max] on system where + // represetable values are [-inf,+inf] this would not be UB +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.mul.representable.type.result} +If the +quotient a/b is representable in the type of the result, (a/b)*b + a\%b is equal to a; otherwise, the behavior +of both a/b and a\%b is undefined. + +\pnum +\begin{example} +\begin{codeblock} +#include + +int main() { + int x = std::numeric_limits::min() / -1; + // Assuming LP64 $-2,147,483,648$ which when divided by $-1$ + // gives us $2,147,483,648$ which is not representable by int +} +\end{codeblock} +\end{example} + +\rSec2[ub.expr.add]{Additive operators} + +\pnum +\ubxref{expr.add.out.of.bounds} +Creating an out of bounds pointer is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +static const int arrs[10]{}; + +int main() { + const int *y = arrs + 11; // undefined behavior, creating an out of bounds pointer +} +\end{codeblock} +\end{example} + +\begin{example} +\begin{codeblock} +static const int arrs[10][10]{}; + +int main() { + const int(*y)[10] = arrs + 11; // undefined behavior, creating an out of bounds pointer. + // We can't treat arrs as-if it was a pointer to 100 int, +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.add.sub.diff.pointers} +Subtracting pointers that are not part of the same array is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include +void f() { + int x[2]; + int y[2]; + int* p1 = x; + int* p2 = y; + std::ptrdiff_t off = p1 - p2; // undefined behavior, \tcode{p1} and \tcode{p2} point to different arrays +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{expr.add.not.similar} +For addition or subtraction of two expressions P and Q, +if P or Q have type ``pointer to cv T'', where T and the array +element type are not similar\iref{conv.rval}, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct S { + int i; +}; + +struct T : S { + double d; +}; + +void f(const S* s, std::size_t count) { + for (const S* end = s + count; s != end; ++s) { + ... + } +} + +int main() { + T test[5]; + f(test, 5); +} +\end{codeblock} +\end{example} + + +\rSec2[ub.expr.shift]{Shift operators} + +\pnum +\ubxref{expr.shift.neg.and.width} +Shifting by a negative amount or equal or greater than the bit-width of a type is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +int y = 1 << -1; // undefined behavior, shift is negative + +static_assert(sizeof(int) == 4 && CHAR_BIT == 8); +int y1 = 1 << 32; // undefined behavior, shift is equal to the bit width of int +int y2 = 1 >> 32; // undefined behavior, shift is equal to the bit width of int +\end{codeblock} +\end{example} + + +\rSec2[ub.expr.assign]{Assignment and compound assignment operators} + +\pnum +\ubxref{expr.assign.overlap} +Overlap in the storage between the source and destination may result in undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +int x = 1; +char* c = reinterpret_cast(&x); +x = *c; // undefined behavior, source overlaps storage of destination +\end{codeblock} +\end{example} + +\rSec1[ub.stmt.stmt]{\ref{stmt}: Statements} + +\rSec2[ub.stmt.return]{The return statement} + +\pnum +\ubxref{stmt.return.flow.off} +Flowing off the end of a function other +than main or a coroutine results in undefined behavior if the return type +is not \cv{}~\keyword{void}. + +\pnum +\begin{example} +\begin{codeblock} +int f(int x) { + if (x) + return 1; + // undefined behavior if \tcode{x} is \tcode{0} +} + +void b() { + int x = f(0); // undefined behavior, using 0 as an argument will cause f(...) to flow off the end + // with a return statement +} +\end{codeblock} +\end{example} + +\rSec2[ub.return.coroutine]{The co_return statement} + +\pnum +\ubxref{stmt.return.coroutine.flow.off} +Flowing off the end of a coroutine function body +that does not return void +has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include +#include +#include +#include + +class resumable { + public: + struct promise_type; + using coro_handle = std::coroutine_handle; + resumable(coro_handle handle) : handle_(handle) { assert(handle); } + resumable(resumable&) = delete; + resumable(resumable&&) = delete; + bool resume() { + if (not handle_.done()) + handle_.resume(); + return not handle_.done(); + } + ~resumable() { handle_.destroy(); } + const char* return_val(); + + private: + coro_handle handle_; +}; + +struct resumable::promise_type { + using coro_handle = std::experimental::coroutine_handle; + const char* string_; + auto get_return_object() { return coro_handle::from_promise(*this); } + auto initial_suspend() { return std::experimental::suspend_always(); } + auto final_suspend() noexcept { return std::experimental::suspend_always(); } + void unhandled_exception() { std::terminate(); } + void return_value(const char* string) { string_ = string; } +}; + +const char* resumable::return_val() { + return handle_.promise().string_; +} + +resumable foo() { + std::cout << "Hello" << std::endl; + co_await std::experimental::suspend_always(); + // undefined behavior, falling off the end of coroutine that does not return void +} + +int main() { + resumable res = foo(); + while (res.resume()) + ; + std::cout << res.return_val() << std::endl; +} +\end{codeblock} +\end{example} + +\rSec2[ub.stmt.dcl]{Declaration statement} + +\pnum +\ubxref{stmt.dcl.local.static.init.recursive} +If control re-enters the declaration recursively while the +variable is being initialized, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +int foo(int i) { + static int s = foo(2 * i); // recursive call - undefined + return i + 1; +} +\end{codeblock} +\end{example} + + + + +\rSec1[ub.dcl.dcl]{\ref{dcl}: Declarations} + +\rSec2[ub.dcl.type.cv]{The cv-qualifiers} + +\pnum +\ubxref{dcl.type.cv.modify.const.obj} +Any attempt to modify a const object during its lifetime results in +undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +const int* ciq = new const int(3); // initialized as required +int* iq = const_cast(ciq); // cast required +*iq = 4; // undefined: modifies a const object +\end{codeblock} +\end{example} + + +\pnum +\ubxref{dcl.type.cv.access.volatile} +If an attempt is made to +access an object defined with a volatile-qualified type through the use of a non-volatile glvalue, the behavior +is undefined + +\pnum +\begin{example} +\begin{codeblock} +volatile int x = 0; +int& y = const_cast(x); +std::cout << y; // undefined behavior, accessing volatile through non-volatile glvalue +\end{codeblock} +\end{example} + +\rSec2[ub.dcl.ref]{References} + +\pnum +\ubxref{dcl.ref.incompatible.function} +Initializing a reference to a function +with a value that is a function +that is not call-compatible\iref{expr.call} +with the type of the reference +has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +void f(float x); +void (&g)(int) = reinterpret_cast(f); // undefined behavior +\end{codeblock} +\end{example} + +\pnum +\ubxref{dcl.ref.incompatible.type} +Initializing a reference to an object +with a value that is not +type-accessible\iref{basic.lval} through +the type of the reference +has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +float g; +int& i = reinterpret_cast(g); // undefined behavior +\end{codeblock} +\end{example} + +\pnum +\ubxref{dcl.ref.uninitialized.reference} +Evaluating a reference +prior to initializing that +reference has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +extern int &ir1; +int i2 = ir1; // undefined behavior, \tcode{ir1} not yet initialized +int i3 = 17; +int &ir1 = i3; +\end{codeblock} +\end{example} + + + + +\rSec2[ub.dcl.fct.def.coroutine]{Coroutine definitions} + +\pnum +\ubxref{dcl.fct.def.coroutine.resume.not.suspended} +Invoking a resumption member function for a coroutine that is not suspended results in undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include + +using namespace std::experimental; + +struct minig { + struct promise_type { + int val; + minig get_return_object() { return {*this}; } + constexpr suspend_always initial_suspend() noexcept { return {}; } + constexpr suspend_always final_suspend() noexcept { return {}; } + constexpr void return_void() noexcept {} + [[noreturn]] void unhandled_exception() noexcept { throw; } + suspend_always yield_value(int v) noexcept { + val = v; + return {}; + } + }; + using HDL = coroutine_handle; + HDL coro; + minig(promise_type& p) : coro(HDL::from_promise(p)) {} + ~minig() { coro.destroy(); } + bool move_next() { + coro.resume(); + return !coro.done(); + } + int current_value() { return coro.promise().val; } +}; + +static minig f(int n) { + for (int i = 0; i < n; ++i) + co_yield i; +} + +int main() { + auto g = f(10); + int sum = 0; + while (g.move_next()) + sum += g.current_value(); +#if 0 + // undefined behavior to call move_next(), because coro.resume() is + // UB after final_suspend returns, even when it returns + // suspend_always + g.move_next(); +#endif + return sum; +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{dcl.fct.def.coroutine.destroy.not.suspended} +Invoking destroy() on a coroutine that is not suspended is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include + +using namespace std::experimental; + +struct minig { + struct promise_type { + int val; + minig get_return_object() { return {*this}; } + constexpr suspend_always initial_suspend() noexcept { return {}; } + constexpr suspend_always final_suspend() noexcept { return {}; } + constexpr void return_void() noexcept {} + [[noreturn]] void unhandled_exception() { throw; } + suspend_always yield_value(int v) noexcept { + val = v; + return {}; + } + }; + using HDL = coroutine_handle; + HDL coro; + minig(promise_type& p) : coro(HDL::from_promise(p)) {} + ~minig() { coro.destroy(); } + bool move_next() { + coro.resume(); + return !coro.done(); + } + int current_value() { + // this coroutine is not suspended therefore a call to destroy is undefined + // behaviour + coro.destroy(); + return coro.promise().val; + } +}; + +static minig f(int n) { + for (int i = 0; i < n; ++i) + co_yield i; +} + +int main() { + auto g = f(10); + int sum = 0; + while (g.move_next()) + sum += g.current_value(); + + return sum; +} +\end{codeblock} +\end{example} + +\rSec2[ub.dcl.attr.assume]{Assumption attribute} + +\pnum +\ubxref{dcl.attr.assume.false} +If an assumption expression would not evaluate to true at the point where it +appears the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +int g(int x) { + [[assume(x >= 0)]]; + return x/32; +} + +int f() { + return g(-10); // undefined behavior, assumption in \tcode{g} is \tcode{false} +} +\end{codeblock} +\end{example} + + +\rSec2[ub.dcl.attr.noreturn]{Noreturn attribute} + +\pnum +\ubxref{dcl.attr.noreturn.eventually.returns} +If a function f is called where f was previously declared with the \tcode{noreturn} attribute and f eventually returns, +the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +[[noreturn]] void f(int i) { + if (i > 0) + throw "positive"; +} + +int main() { + f(0); // undefined behavior, returns from a [[noreturn]] function +} +\end{codeblock} +\end{example} + + +\rSec1[ub.class]{\ref{class}: Classes} + +\rSec2[ub.class.dtor]{Destructors} + +\pnum +\ubxref{class.dtor.no.longer.exists} +Once a destructor is invoked for an object, +the object's lifetime has ended; +the behavior is undefined if the +destructor is invoked for an object whose lifetime has ended. + +\pnum +\begin{example} +\begin{codeblock} +struct A { + ~A() {} +}; + +int main() { + A a; + a.~A(); +} // undefined behavior, lifetime of \tcode{a} already ended before implicit destructor +\end{codeblock} +\end{example} + + +\rSec2[ub.class.abstract]{Abstract classes} + +\pnum +\ubxref{class.abstract.pure.virtual} +Calling a pure virtual function from a constructor or destructor in an abstract class is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct B { + virtual void f() = 0; + B() { + f(); // undefined behavior, \tcode{f} is pure virtual and we are calling from the constructor + } +}; + +struct D : B { + void f() override; +}; +\end{codeblock} +\end{example} + + +\rSec2[ub.class.base.init]{Initializing bases and members} + +\pnum +\ubxref{class.base.init.mem.fun} +It is undefined behavior to call a member function before all the \grammarterm{mem-initializer}s for base classes have completed. + +\pnum +\begin{example} +\begin{codeblock} +class A { +public: + A(int); +}; + +class B : public A { + int j; + +public: + int f(); + B() + : A(f()), // undefined: calls member function but base A not yet initialized + j(f()) {} // well-defined: bases are all initialized +}; + +class C { +public: + C(int); +}; + +class D : public B, C { + int i; + +public: + D() + : C(f()), // undefined: calls member function but base \tcode{C} not yet initialized + i(f()) {} // well-defined: bases are all initialized +}; +\end{codeblock} +\end{example} + + +\rSec2[ub.class.cdtor]{Construction and destruction} + +\pnum +\ubxref{class.cdtor.before.ctor} +For an object with a non-trivial constructor, referring to any non-static member or base class of the object +before the constructor begins execution results in undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct X { + int i; +}; +struct Y : X { + Y(); +}; // non-trivial +struct A { + int a; +}; +struct B : public A { + int j; + Y y; +}; // non-trivial + +extern B bobj; +B *pb = &bobj; // OK +int *p1 = &bobj.a; // undefined, refers to base class member +int *p2 = &bobj.y.i; // undefined, refers to member's member + +A *pa = &bobj; // undefined, upcast to a base class type +B bobj; // definition of \tcode{bobj} + +extern X xobj; +int *p3 = &xobj.i; // OK, \tcode{X} is a trivial class +X xobj; + +struct W { + int j; +}; +struct X : public virtual W {}; +struct Y { + int *p; + X x; + Y() : p(&x.j) { // undefined, \tcode{x} is not yet constructed + } +}; +\end{codeblock} +\end{example} + +%TODO: CM: Can this example be shortened? + + +\pnum +\ubxref{class.cdtor.after.dtor} +For an object with a non-trivial destructor, +referring to any non-static member or base class of the object +after the destructor finishes execution +has undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct X { + int i; + ~X(); // non-trivial +}; +X& g() +{ + static X x; + return x; +} +void f() +{ + X* px = &g(); + px->~X(); + int j = px->i; // undefined behavior +} +\end{codeblock} +\end{example} + +\pnum +\ubxref{class.cdtor.convert.pointer} +When converting a pointer to a base class of an object, +construction must have started and destruction must not have finished otherwise +this is undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct A { }; +struct B : virtual A { }; +struct C : B { }; +struct D : virtual A { D(A*); }; +struct X { X(A*); }; + +struct E : C, D, X { + E() : D(this), // undefined behavior: upcast from \tcode{E*} to \tcode{A*} might use path \tcode{E*} $\rightarrow$ \tcode{D*} $\rightarrow$ \tcode{A*} + // but \tcode{D} is not constructed + + // ``\tcode{D((C*)this)}\!'' would be defined: \tcode{E*} $\rightarrow$ \tcode{C*} is defined because \tcode{E()} has started, + // and \tcode{C*} $\rightarrow$ \tcode{A*} is defined because \tcode{C} is fully constructed + + X(this) {} // defined: upon construction of \tcode{X}, \tcode{C/B/D/A} sublattice is fully constructed +}; +\end{codeblock} +\end{example} + +\pnum +\ubxref{class.cdtor.form.pointer} +When forming a pointer to +a direct non-static member of a class, +construction must have started +and destruction must not have finished +otherwise the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct A { + int i = 0; +}; +struct B { + int *p; + A a; + B() : p(&a.i) {} // undefined behavior +}; +\end{codeblock} +\end{example} + +\pnum +\ubxref{class.cdtor.virtual.not.x} +When a virtual function is called directly or indirectly from a constructor or from a destructor, +including during the construction or destruction of the class's non-static data members, and the object to +which the call applies is the object (call it \tcode{x}) under construction or destruction, the function called is the +final overrider in the constructor's or destructor's class and not one overriding it in a more-derived class. +If the virtual function call uses an explicit class member access\iref{expr.ref} and the object expression refers +to the complete object of \tcode{x} or one of that object's base class subobjects but not \tcode{x} or one of its base class +subobjects, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct V { + virtual void f(); + virtual void g(); +}; + +struct A : virtual V { + virtual void f(); +}; + +struct B : virtual V { + virtual void g(); + B(V *, A *); +}; + +struct D : A, B { + virtual void f(); + virtual void g(); + D() : B((A *)this, this) {} +}; + +B::B(V *v, A *a) { + f(); // calls \tcode{V::f}, not \tcode{A::f} + g(); // calls \tcode{B::g}, not \tcode{D::g} + v->g(); // \tcode{v} is base of \tcode{B}, the call is well-defined, calls \tcode{B::g} + a->f(); // undefined behavior, \tcode{a}'s type not a base of \tcode{B} +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{class.cdtor.typeid} +If the operand of \tcode{typeid} refers to +the object under construction or destruction and the static type of the operand is neither the constructor or +destructor's class nor one of its bases, the behavior is undefined. + +\pnum +\begin{example} +\begin{codeblock} +struct V { + virtual void f(); +}; + +struct A : virtual V {}; +struct B : virtual V { + B(V *, A *); +}; + +struct D : A, B { + D() : B((A *)this, this) {} +}; + +B::B(V *v, A *a) { + typeid(*this); // \tcode{std::type_info} for \tcode{B} + typeid(*v); // well-defined: \tcode{*v} has type \tcode{V}, a base of \tcode{B} yields \tcode{std::type_info} for \tcode{B} + typeid(*a); // undefined behavior: type \tcode{A} not a base of \tcode{B} +} +\end{codeblock} +\end{example} + + +\pnum +\ubxref{class.cdtor.dynamic.cast} +If the operand of the +\tcode{dynamic_cast} refers to the object under construction or destruction and the static type of the operand is +not a pointer to or object of the constructor or destructor's own class or one of its bases, the \tcode{dynamic_cast} +results in undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +struct V { + virtual void f(); +}; + +struct A : virtual V {}; +struct B : virtual V { + B(V *, A *); +}; + +struct D : A, B { + D() : B((A *)this, this) {} +}; + +B::B(V *v, A *a) { + dynamic_cast(v); // well-defined: \tcode{v} of type \tcode{V*}, \tcode{V} base of \tcode{B} results in \tcode{B*} + dynamic_cast(a); // undefined behavior: \tcode{a} has type \tcode{A*}, \tcode{A} not a base of \tcode{B} +} +\end{codeblock} +\end{example} + + +\rSec1[ub.temp]{\ref{temp}: Templates} +\rSec2[ub.temp.inst]{Implicit instantiation} + +\pnum +\ubxref{temp.inst.inf.recursion} +The result of an infinite recursion in template instantiation is undefined. + +\pnum +\begin{example} +\begin{codeblock} +template +class X { + X *p; // OK + X a; // implicit instantiation of \tcode{X} requires + // the implicit instantiation of \tcode{X} which requires + // the implicit instantiation of \tcode{X} which \ldots +}; + +int main() { + X x; // undefined behavior, instantiation will kick off infinite recursion +} +\end{codeblock} +\end{example} + + +\rSec1[ub.except]{\ref{except}: Exception handling} + +\rSec2[ub.except.handle]{Handling an exception} + +\pnum +\ubxref{except.handle.handler.ctor.dtor} +Referring to any non-static member or base class of an object in the handler for a \grammarterm{function-try-block} of a +constructor or destructor for that object results in undefined behavior. + +\pnum +\begin{example} +\begin{codeblock} +#include + +struct A { + A() try : x(0 ? 1 : throw 1) { + } catch (int) { + std::cout << "y: " << y << std::endl; // undefined behavior, referring to non-static member y in + // the handler of function-try-block + } + int x; + int y = 42; +}; +\end{codeblock} +\end{example} diff --git a/source/utilities.tex b/source/utilities.tex index d714c1f2ef..9cedb5cf2f 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -97,6 +97,22 @@ [[noreturn]] void unreachable(); void observable_checkpoint() noexcept; + // \ref{const.wrap.class}, class template \tcode{constant_wrapper} + template + struct @\exposidnc{cw-fixed-value}@; // \expos + + template<@\exposidnc{cw-fixed-value}@ X, class = typename decltype(X)::@\exposid{type}@> + struct constant_wrapper; + + template + concept @\defexposconceptnc{constexpr-param}@ = // \expos + requires { typename constant_wrapper; }; + + struct @\exposidnc{cw-operators}@; // \expos + + template<@\exposid{cw-fixed-value}@ X> + constexpr auto @\libglobal{cw}@ = constant_wrapper{}; + // \ref{intseq}, compile-time integer sequences% \indexlibraryglobal{index_sequence}% \indexlibraryglobal{make_index_sequence}% @@ -225,15 +241,6 @@ }; template constexpr in_place_index_t in_place_index{}; - // \tcode{constant_arg} argument tag% -\indexlibraryglobal{constant_arg_t}% -\indexlibraryglobal{constant_arg} - template - struct constant_arg_t { - explicit constant_arg_t() = default; - }; - template constexpr constant_arg_t constant_arg{}; - // \ref{variant.monostate}, class \tcode{monostate}% \indexlibraryglobal{monostate} struct monostate; @@ -376,19 +383,19 @@ }; void g() { - shared_ptr sp1 = factory(2, 1.414); // error: 2 will not bind to \tcode{int\&} + shared_ptr sp1 = factory(2, 1.414); // error: \tcode{2} will not bind to \tcode{int\&} int i = 2; shared_ptr sp2 = factory(i, 1.414); // OK } \end{codeblock} In the first call to \tcode{factory}, -\tcode{A1} is deduced as \tcode{int}, so 2 is forwarded +\tcode{A1} is deduced as \tcode{int}, so \tcode{2} is forwarded to \tcode{A}'s constructor as an rvalue. In the second call to \tcode{factory}, \tcode{A1} is deduced as \tcode{int\&}, so \tcode{i} is forwarded to \tcode{A}'s constructor as an lvalue. In both cases, \tcode{A2} is deduced as \tcode{double}, so -1.414 is forwarded to \tcode{A}'s constructor as an rvalue. +\tcode{1.414} is forwarded to \tcode{A}'s constructor as an rvalue. \end{example} \end{itemdescr} @@ -660,7 +667,7 @@ \begin{itemdescr} \pnum \mandates -Each of \tcode{T} and \tcode{U} is +Each of \tcode{T} and \tcode{R} is a signed or unsigned integer type\iref{basic.fundamental}. \pnum @@ -743,6 +750,302 @@ Establishes an observable checkpoint\iref{intro.abstract}. \end{itemdescr} +\rSec2[const.wrap.class]{Class template \tcode{constant_wrapper}} + +\begin{codeblock} +namespace std { + template + struct @\exposidnc{cw-fixed-value}@ { // \expos + using @\exposidnc{type}@ = T; // \expos + constexpr @\exposidnc{cw-fixed-value}@(@\exposidnc{type}@ v) noexcept : @\exposidnc{data}@(v) {} + T @\exposidnc{data}@; // \expos + }; + + template + struct @\exposidnc{cw-fixed-value}@ { // \expos + using @\exposidnc{type}@ = T[Extent]; // \expos + constexpr @\exposidnc{cw-fixed-value}@(T (&arr)[Extent]) noexcept; + T @\exposidnc{data}@[Extent]; // \expos + }; + + template + @\exposidnc{cw-fixed-value}@(T (&)[Extent]) -> @\exposidnc{cw-fixed-value}@; // \expos + + struct @\exposidnc{cw-operators}@ { // \expos + // unary operators + template<@\exposconcept{constexpr-param}@ T> + friend constexpr auto operator+(T) noexcept -> constant_wrapper<(+T::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ T> + friend constexpr auto operator-(T) noexcept -> constant_wrapper<(-T::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ T> + friend constexpr auto operator~(T) noexcept -> constant_wrapper<(~T::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ T> + friend constexpr auto operator!(T) noexcept -> constant_wrapper<(!T::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ T> + friend constexpr auto operator&(T) noexcept -> constant_wrapper<(&T::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ T> + friend constexpr auto operator*(T) noexcept -> constant_wrapper<(*T::value)> + { return {}; } + + // binary operators + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator+(L, R) noexcept -> constant_wrapper<(L::value + R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator-(L, R) noexcept -> constant_wrapper<(L::value - R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator*(L, R) noexcept -> constant_wrapper<(L::value * R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator/(L, R) noexcept -> constant_wrapper<(L::value / R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator%(L, R) noexcept -> constant_wrapper<(L::value % R::value)> + { return {}; } + + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator<<(L, R) noexcept -> constant_wrapper<(L::value << R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator>>(L, R) noexcept -> constant_wrapper<(L::value >> R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator&(L, R) noexcept -> constant_wrapper<(L::value & R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator|(L, R) noexcept -> constant_wrapper<(L::value | R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator^(L, R) noexcept -> constant_wrapper<(L::value ^ R::value)> + { return {}; } + + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + requires (!is_constructible_v || + !is_constructible_v) + friend constexpr auto operator&&(L, R) noexcept + -> constant_wrapper<(L::value && R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + requires (!is_constructible_v || + !is_constructible_v) + friend constexpr auto operator||(L, R) noexcept + -> constant_wrapper<(L::value || R::value)> + { return {}; } + + // comparisons + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator<=>(L, R) noexcept + -> constant_wrapper<(L::value <=> R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator<(L, R) noexcept -> constant_wrapper<(L::value < R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator<=(L, R) noexcept -> constant_wrapper<(L::value <= R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator==(L, R) noexcept -> constant_wrapper<(L::value == R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator!=(L, R) noexcept -> constant_wrapper<(L::value != R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator>(L, R) noexcept -> constant_wrapper<(L::value > R::value)> + { return {}; } + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator>=(L, R) noexcept -> constant_wrapper<(L::value >= R::value)> + { return {}; } + + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator,(L, R) noexcept = delete; + template<@\exposconcept{constexpr-param}@ L, @\exposconcept{constexpr-param}@ R> + friend constexpr auto operator->*(L, R) noexcept -> constant_wrapper*(R::value)> + { return {}; } + + // pseudo-mutators + template<@\exposconcept{constexpr-param}@ T> + constexpr auto operator++(this T) noexcept + -> constant_wrapper<(++T::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T> + constexpr auto operator++(this T, int) noexcept + -> constant_wrapper<(T::value++)> { return {}; } + template<@\exposconcept{constexpr-param}@ T> + constexpr auto operator--(this T) noexcept + -> constant_wrapper<(--T::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T> + constexpr auto operator--(this T, int) noexcept + -> constant_wrapper<(T::value--)> { return {}; } + + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator+=(this T, R) noexcept + -> constant_wrapper<(T::value += R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator-=(this T, R) noexcept + -> constant_wrapper<(T::value -= R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator*=(this T, R) noexcept + -> constant_wrapper<(T::value *= R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator/=(this T, R) noexcept + -> constant_wrapper<(T::value /= R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator%=(this T, R) noexcept + -> constant_wrapper<(T::value %= R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator&=(this T, R) noexcept + -> constant_wrapper<(T::value &= R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator|=(this T, R) noexcept + -> constant_wrapper<(T::value |= R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator^=(this T, R) noexcept + -> constant_wrapper<(T::value ^= R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator<<=(this T, R) noexcept + -> constant_wrapper<(T::value <<= R::value)> { return {}; } + template<@\exposconcept{constexpr-param}@ T, @\exposconcept{constexpr-param}@ R> + constexpr auto operator>>=(this T, R) noexcept + -> constant_wrapper<(T::value >>= R::value)> { return {}; } + }; + + template<@\exposid{cw-fixed-value}@ X, class> + struct @\libglobal{constant_wrapper}@ : @\exposid{cw-operators}@ { + static constexpr const auto & value = X.@\exposid{data}@; + using type = constant_wrapper; + using value_type = decltype(X)::@\exposid{type}@; + + template<@\exposconcept{constexpr-param}@ R> + constexpr auto operator=(R) const noexcept + -> constant_wrapper<(value = R::value)> { return {}; } + + constexpr operator decltype(value)() const noexcept { return value; } + + template + static constexpr decltype(auto) operator()(Args&&... args) noexcept(@\seebelow@); + template + static constexpr decltype(auto) operator[](Args&&... args) noexcept(@\seebelow@); + }; +} +\end{codeblock} + +\pnum +The class template \tcode{constant_wrapper} aids in metaprogramming by ensuring +that the evaluation of expressions comprised entirely of \tcode{constant_wrapper} +are core constant expressions\iref{expr.const.core}, +regardless of the context in which they appear. +In particular, this enables use of \tcode{constant_wrapper} values +that are passed as arguments to constexpr functions to be used in constant expressions. + +\pnum +\begin{note} +The unnamed second template parameter to \tcode{constant_wrapper} is present +to aid argument-dependent lookup\iref{basic.lookup.argdep} +in finding overloads for which \tcode{constant_wrapper}'s wrapped value is a suitable argument, +but for which the \tcode{constant_wrapper} itself is not. +\end{note} + +\pnum +\begin{example} +\begin{codeblock} + constexpr auto initial_phase(auto quantity_1, auto quantity_2) { + return quantity_1 + quantity_2; + } + + constexpr auto middle_phase(auto tbd) { + return tbd; + } + + void final_phase(auto gathered, auto available) { + if constexpr (gathered == available) + std::cout << "Profit!\n"; + } + + void impeccable_underground_planning() { + auto gathered_quantity = middle_phase(initial_phase(std::cw<42>, std::cw<13>)); + static_assert(gathered_quantity == 55); + auto all_available = std::cw<55>; + final_phase(gathered_quantity, all_available); + } + + void deeply_flawed_underground_planning() { + constexpr auto gathered_quantity = middle_phase(initial_phase(42, 13)); + constexpr auto all_available = 55; + final_phase(gathered_quantity, all_available); // error: \tcode{gathered == available} + // is not a constant expression + } +\end{codeblock} +\end{example} + +\begin{itemdecl} +constexpr @\exposid{cw-fixed-value}@(T (&arr)[Extent]) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initialize elements of \exposid{data} with corresponding elements of \tcode{arr}. +\end{itemdescr} + +\indexlibrarymember{operator()}{constant_wrapper}% +\begin{itemdecl} +template + static constexpr decltype(auto) operator()(Args&&... args) noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{\placeholder{call-expr}} be +\tcode{constant_wrapper<\placeholder{INVOKE}(value, remove_cvref_t::value...)>\{\}} +if all types in \tcode{remove_cvref_t...} satisfy \exposconcept{constexpr-param} and +\tcode{constant_wrapper<\placeholder{INVOKE}(val\-ue, remove_cvref_t::value...)>} is a valid type, +otherwise let \tcode{\placeholder{call-expr}} be \tcode{\placeholder{INVOKE}(value, std::forward(args)...)}. + +\pnum +\constraints +\tcode{\placeholder{call-expr}} is a valid expression. + +\pnum +\effects +Equivalent to: \tcode{return \placeholder{call-expr};} + +\pnum +\remarks +The exception specification is equivalent to \tcode{noexcept(\placeholder{call-expr})}. +\end{itemdescr} + +\indexlibrarymember{operator[]}{constant_wrapper}% +\begin{itemdecl} +template + static constexpr decltype(auto) operator[](Args&&... args) noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{\placeholder{subscr-expr}} be +\tcode{constant_wrapper::value...]>\{\}} +if all types in \tcode{remove_cvref_t...} satisfy \exposconcept{constexpr-param} and +\tcode{constant_wrapper::value...]>} is a valid type, +otherwise let \tcode{\placeholder{subscr-expr}} be \tcode{value[std::forward(args)...]}. + +\pnum +\constraints +\tcode{\placeholder{subscr-expr}} is a valid expression. + +\pnum +\effects +Equivalent to: \tcode{return \placeholder{subscr-expr};} + +\pnum +\remarks +The exception specification is equivalent to \tcode{noexcept(\placeholder{subscr-expr})}. +\end{itemdescr} + \rSec1[pairs]{Pairs} \rSec2[pairs.general]{General} @@ -1524,8 +1827,8 @@ the class template \tcode{tuple} that can be instantiated with any number of arguments. Each template argument specifies the type of an element in the \tcode{tuple}. Consequently, tuples are -heterogeneous, fixed-size collections of values. An instantiation of \tcode{tuple} with -two arguments is similar to an instantiation of \tcode{pair} with the same two arguments. +heterogeneous, fixed-size collections of values. A specialization of \tcode{tuple} with +two arguments behaves similarly to a specialization of \tcode{pair} with the same two arguments. See~\ref{pairs}. \pnum @@ -3966,7 +4269,7 @@ \begin{itemdescr} \pnum -\mandates +\constraints \tcode{is_constructible_v} is \tcode{true}. \pnum @@ -5071,7 +5374,11 @@ this indicates that an optional object not containing a value shall be constructed. \pnum -Type \tcode{nullopt_t} shall not have a default constructor or an initializer-list constructor, and shall not be an aggregate. +Type \tcode{nullopt_t} does not have +a default constructor or an initializer-list constructor, and +is not an aggregate. +\tcode{nullopt_t} models \libconcept{copyable} and +\tcode{\libconcept{three_way_comparable}}. \rSec2[optional.bad.access]{Class \tcode{bad_optional_access}} @@ -5925,7 +6232,8 @@ \pnum \throws -Any exception thrown by direct-initializing any $\tcode{T}_i$ for all $i$. +Any exception thrown by +the initialization of the contained value. \pnum \remarks @@ -5956,7 +6264,8 @@ \pnum \throws -Any exception thrown by move-constructing any $\tcode{T}_i$ for all $i$. +Any exception thrown by +the initialization of the contained value. \pnum \remarks @@ -6024,7 +6333,8 @@ \pnum \throws -Any exception thrown by the initialization of the selected alternative $\tcode{T}_j$. +Any exception thrown by +the initialization of the contained value. \pnum \remarks @@ -6058,7 +6368,8 @@ \pnum \throws -Any exception thrown by calling the selected constructor of \tcode{T}. +Any exception thrown by +the initialization of the contained value. \pnum \remarks @@ -6091,7 +6402,8 @@ \pnum \throws -Any exception thrown by calling the selected constructor of \tcode{T}. +Any exception thrown by +the initialization of the contained value. \pnum \remarks @@ -6125,7 +6437,8 @@ \pnum \throws -Any exception thrown by calling the selected constructor of $\tcode{T}_I$. +Any exception thrown by +the initialization of the contained value. \pnum \remarks @@ -6158,6 +6471,11 @@ \ensures \tcode{index()} is \tcode{I}. +\pnum +\throws +Any exception thrown by +the initialization of the contained value. + \pnum \remarks If $\tcode{T}_I$'s selected constructor is a constexpr constructor, this @@ -8247,10 +8565,10 @@ friend constexpr bool operator==(const expected&, const unexpected&); private: - bool @\exposid{has_val}@; // \expos + bool @\exposid{has_val}@; // \expos union { - T @\exposid{val}@; // \expos - E @\exposid{unex}@; // \expos + remove_cv_t @\exposid{val}@; // \expos + E @\exposid{unex}@; // \expos }; }; } @@ -8725,6 +9043,17 @@ \tcode{is_nothrow_move_constructible_v || is_nothrow_move_constructible_v} is \tcode{true}. \end{itemize} + +\pnum +This operator is trivial if: +\begin{itemize} +\item \tcode{is_trivially_copy_constructible_v} is \tcode{true}, and +\item \tcode{is_trivially_copy_assignable_v} is \tcode{true}, and +\item \tcode{is_trivially_destructible_v} is \tcode{true}, and +\item \tcode{is_trivially_copy_constructible_v} is \tcode{true}, and +\item \tcode{is_trivially_copy_assignable_v} is \tcode{true}, and +\item \tcode{is_trivially_destructible_v} is \tcode{true}. +\end{itemize} \end{itemdescr} \indexlibrarymember{operator=}{expected}% @@ -8782,6 +9111,17 @@ is_nothrow_move_assignable_v && is_nothrow_move_constructible_v && is_nothrow_move_assignable_v && is_nothrow_move_constructible_v \end{codeblock} + +\pnum +This operator is trivial if: +\begin{itemize} +\item \tcode{is_trivially_move_constructible_v} is \tcode{true}, and +\item \tcode{is_trivially_move_assignable_v} is \tcode{true}, and +\item \tcode{is_trivially_destructible_v} is \tcode{true}, and +\item \tcode{is_trivially_move_constructible_v} is \tcode{true}, and +\item \tcode{is_trivially_move_assignable_v} is \tcode{true}, and +\item \tcode{is_trivially_destructible_v} is \tcode{true}. +\end{itemize} \end{itemdescr} \indexlibrarymember{operator=}{expected}% @@ -8976,7 +9316,7 @@ throw; } } else { - T tmp(std::move(@\exposid{val}@)); + remove_cv_t tmp(std::move(@\exposid{val}@)); destroy_at(addressof(@\exposid{val}@)); try { construct_at(addressof(@\exposid{unex}@), std::move(rhs.@\exposid{unex}@)); @@ -9545,7 +9885,7 @@ \pnum \returns -If \tcode{x.has_value()} is \tcode{true}, +If \tcode{!x.has_value()} is \tcode{true}, \tcode{x.error() == e.error()}; otherwise \tcode{false}. \end{itemdescr} @@ -9929,6 +10269,13 @@ This operator is defined as deleted unless \tcode{is_copy_assignable_v} is \tcode{true} and \tcode{is_copy_constructible_v} is \tcode{true}. + +\pnum +This operator is trivial if +\tcode{is_trivially_copy_constructible_v}, +\tcode{is_trivially_copy_assigna\-ble_v}, and +\tcode{is_trivially_destructible_v} +are all \tcode{true}. \end{itemdescr} \indexlibrarymember{operator=}{expected}% @@ -9968,6 +10315,13 @@ \remarks The exception specification is equivalent to \tcode{is_nothrow_move_constructible_v \&\& is_nothrow_move_assignable_v}. + +\pnum +This operator is trivial if +\tcode{is_trivially_move_constructible_v}, +\tcode{is_trivially_move_assigna\-ble_v}, and +\tcode{is_trivially_destructible_v} +are all \tcode{true}. \end{itemdescr} \indexlibrarymember{operator=}{expected}% @@ -10542,7 +10896,7 @@ constexpr reference& operator=(const reference& x) noexcept; // for \tcode{b[i] = b[j];} constexpr const reference& operator=(bool x) const noexcept; constexpr operator bool() const noexcept; // for \tcode{x = b[i];} - constexpr bool operator~() const noexcept; // flips the bit + constexpr bool operator~() const noexcept; constexpr reference& flip() noexcept; // for \tcode{b[i].flip();} friend constexpr void swap(reference x, reference y) noexcept; @@ -10687,6 +11041,29 @@ \tcode{*this}. \end{itemdescr} +\indexlibrarymember{operator bool}{bitset::reference}% +\begin{itemdecl} +constexpr reference::operator bool() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if the value of the bit referred to by \tcode{*this} is one, +\tcode{false} otherwise. +\end{itemdescr} + +\indexlibrarymember{operator~}{bitset::reference}% +\begin{itemdecl} +constexpr bool reference::operator~() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{!bool(*this)}. +\end{itemdescr} + \indexlibrarymember{swap}{bitset::reference}% \begin{itemdecl} constexpr void swap(reference x, reference y) noexcept; @@ -11714,19 +12091,20 @@ A \defnadj{callable}{object} is an object of a callable type. \pnum -A \defnx{call wrapper type}{call wrapper!type} is a type that holds a callable object -and supports a call operation that forwards to that object. +A \defnx{call wrapper type}{call wrapper!type} is a type that holds +a \defnadj{target}{object}, +which is either +a callable object or +an object representing a callable object, +and supports a call operation that forwards to that callable object. \pnum A \defn{call wrapper} is an object of a call wrapper type. -\pnum -A \defn{target object} is the callable object held by a call wrapper. - \pnum A call wrapper type may additionally hold a sequence of objects and references -that may be passed as arguments to the target object. +that may be passed as arguments to the callable object. These entities are collectively referred to as \defnx{bound argument entities}{bound argument entity}. @@ -13424,9 +13802,9 @@ \pnum \returns -A perfect forwarding call wrapper\iref{func.require} \tcode{g} that -does not have state entities, and -has the call pattern \tcode{!invoke(f, call_args...)}. +A perfect forwarding call wrapper\iref{func.require} \tcode{g} +whose target object is a copy of \tcode{cw}, and +whose call pattern is \tcode{!invoke(f, call_args...)}. \end{itemdescr} \rSec2[func.bind.partial]{Function templates \tcode{bind_front} and \tcode{bind_back}} @@ -13546,8 +13924,9 @@ \pnum \returns -A perfect forwarding call wrapper\iref{func.require} \tcode{g} that -does not have a target object, and has the call pattern: +A perfect forwarding call wrapper\iref{func.require} \tcode{g} +whose target object is a copy of \tcode{cw}, and +whose call pattern is: \begin{itemize} \item \tcode{invoke(f, bound_args..., call_args...)} @@ -13835,10 +14214,12 @@ \pnum Let \tcode{t} be an object of a type that is a specialization of -\tcode{function}, \tcode{copyable_function}, or \tcode{move_only_function}, +\tcode{function}, \tcode{copyable_function}, \tcode{move_only_function}, +or \tcode{function_ref}, such that the target object \tcode{x} of \tcode{t} has a type that is a specialization of -\tcode{function}, \tcode{copyable_function}, or \tcode{move_only_function}. +\tcode{function}, \tcode{copyable_function}, \tcode{move_only_function}, +or \tcode{function_ref}. Each argument of the invocation of \tcode{x} evaluated as part of the invocation of \tcode{t} may alias an argument in the same position in the invocation of \tcode{t} that @@ -15178,9 +15559,11 @@ // \ref{func.wrap.ref.ctor}, constructors and assignment operators template function_ref(F*) noexcept; template constexpr function_ref(F&&) noexcept; - template constexpr function_ref(constant_arg_t) noexcept; - template constexpr function_ref(constant_arg_t, U&&) noexcept; - template constexpr function_ref(constant_arg_t, @\cv{}@ T*) noexcept; + template constexpr function_ref(constant_wrapper) noexcept; + template + constexpr function_ref(constant_wrapper, U&&) noexcept; + template + constexpr function_ref(constant_wrapper, @\cv{}@ T*) noexcept; constexpr function_ref(const function_ref&) noexcept = default; constexpr function_ref& operator=(const function_ref&) noexcept = default; @@ -15200,10 +15583,10 @@ // \ref{func.wrap.ref.deduct}, deduction guides template function_ref(F*) -> function_ref; - template - function_ref(constant_arg_t) -> function_ref<@\seebelow@>; - template - function_ref(constant_arg_t, T&&) -> function_ref<@\seebelow@>; + template + function_ref(constant_wrapper) -> function_ref<@\seebelow@>; + template + function_ref(constant_wrapper, T&&) -> function_ref<@\seebelow@>; } \end{codeblock} @@ -15253,6 +15636,25 @@ \end{codeblock} \end{itemdescr} +\indextext{function_ref::is-convertible-from-specialization@\tcode{function_ref::\exposid{is-convertible-from-\brk{}specialization}}}% +\begin{itemdecl} +template + static constexpr bool @\exposid{is-convertible-from-specialization}@ = @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +If \tcode{F} denotes a specialization +\tcode{function_ref} +for some placeholders \cvqual{cv2} and \placeholder{noex2}, +\tcode{\exposid{is-convertible-from-specialization}} is equal to: +\begin{codeblock} +is_convertible_v && +is_convertible_v. +\end{codeblock} +Otherwise, \tcode{\exposid{is-convertible-from-specialization}} is \tcode{false}. +\end{itemdescr} + \indexlibraryctor{function_ref}% \begin{itemdecl} template function_ref(F* f) noexcept; @@ -15300,32 +15702,62 @@ \pnum \effects -Initializes -\exposid{bound-entity} with \tcode{addressof(f)}, and +If \tcode{\exposid{is-convertible-from-specialization}>} +is \tcode{false}, +initializes +\exposid{bound-en\-tity} with \tcode{addressof(f)}, and \exposid{thunk-ptr} with the address of a function \tcode{\placeholder{thunk}} such that -\tcode{\placeholder{thunk}(\exposid{bound-entity}, \placeholder{call-args}...)} +\tcode{\placeholder{thunk}(\exposid{bound-\brk{}entity}, \placeholder{call-args}...)} is expression-equivalent\iref{defns.expression.equivalent} to \tcode{invoke_r(static_cast<\cv{} T\&>(f), \placeholder{call-args}...)}. +Otherwise, initializes \exposid{bound-entity} +with the value of \tcode{f.\exposid{bound-entity}} and +\exposid{thunk-\brk{}ptr} with the value of \tcode{f.\exposid{thunk-ptr}}. + +\pnum +\remarks +If \tcode{remove_cvref_t} is a specialization of \tcode{function_ref}, +an implementation may initialize \exposid{bound-entity} +with the value of \tcode{f.\exposid{bound-entity}} and \exposid{thunk-ptr} +with the value of \tcode{f.\exposid{thunk-ptr}}. +\begin{example} +\begin{codeblock} +void f1(std::string); +void f2(std::string); + +function_ref r1(&f1); +function_ref r2(r1); +r2(""); // \tcode{f1} is invoked +r1 = &f2; +r2(""); // it is unspecified if \tcode{f1} or \tcode{f2} is invoked +\end{codeblock} +\end{example} \end{itemdescr} \indexlibraryctor{function_ref}% \begin{itemdecl} -template constexpr function_ref(constant_arg_t) noexcept; +template constexpr function_ref(constant_wrapper f) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -Let \tcode{F} be \tcode{decltype(f)}. - \pnum \constraints \tcode{\exposid{is-invocable-using}} is \tcode{true}. \pnum \mandates +\begin{itemize} +\item If \tcode{is_pointer_v || is_member_pointer_v} is \tcode{true}, -then \tcode{f != nullptr} is \tcode{true}. +then \tcode{f.value != nullptr} is \tcode{true}, and +\item +if \tcode{ArgTypes} is not an empty pack and +all types in \tcode{remove_cvref_t...} +satisfy \exposconcept{constexpr-param} then +\tcode{constant_wrapper<\placeholdernc{INVOKE}(f.value, remove_cvref_t::\newline value...)>} +is not a valid type. +\end{itemize} \pnum \effects @@ -15336,19 +15768,18 @@ such that \tcode{\placeholder{thunk}(\exposid{bound-entity}, \placeholder{call-args}...)} is expression-equivalent\iref{defns.expression.equivalent} to -\tcode{invoke_r(f, \placeholder{call-args}...)}. +\tcode{invoke_r(f.value, \placeholder{call-args}...)}. \end{itemdescr} \indexlibraryctor{function_ref}% \begin{itemdecl} -template - constexpr function_ref(constant_arg_t, U&& obj) noexcept; +template + constexpr function_ref(constant_wrapper f, U&& obj) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -Let \tcode{T} be \tcode{remove_reference_t} and -\tcode{F} be \tcode{decltype(f)}. +Let \tcode{T} be \tcode{remove_reference_t}. \pnum \constraints @@ -15360,7 +15791,7 @@ \pnum \mandates If \tcode{is_pointer_v || is_member_pointer_v} is \tcode{true}, -then \tcode{f != nullptr} is \tcode{true}. +then \tcode{f.value != nullptr} is \tcode{true}. \pnum \effects @@ -15370,19 +15801,16 @@ such that \tcode{\placeholder{thunk}(\exposid{bound-entity}, \placeholder{call-args}...)} is expression-equivalent\iref{defns.expression.equivalent} to -\tcode{invoke_r(f, static_cast<\cv{} T\&>(obj), \placeholder{call-args}...)}. +\tcode{invoke_r(f.value, static_cast<\cv{} T\&>(obj), \placeholder{call-args}...)}. \end{itemdescr} \indexlibraryctor{function_ref}% \begin{itemdecl} -template - constexpr function_ref(constant_arg_t, @\cv{}@ T* obj) noexcept; +template + constexpr function_ref(constant_wrapper f, @\cv{}@ T* obj) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -Let \tcode{F} be \tcode{decltype(f)}. - \pnum \constraints \tcode{\exposid{is-invocable-using}} is \tcode{true}. @@ -15390,7 +15818,7 @@ \pnum \mandates If \tcode{is_pointer_v || is_member_pointer_v} is \tcode{true}, -then \tcode{f != nullptr} is \tcode{true}. +then \tcode{f.value != nullptr} is \tcode{true}. \pnum \expects @@ -15405,7 +15833,7 @@ such that \tcode{\placeholder{thunk}(\exposid{bound-entity}, \placeholder{call-args}...)} is expression-equivalent\iref{defns.expression.equivalent} to -\tcode{invoke_r(f, obj, \placeholder{call-args}...)}. +\tcode{invoke_r(f.value, obj, \placeholder{call-args}...)}. \end{itemdescr} \indexlibrarymember{operator=}{function_ref}% @@ -15417,9 +15845,9 @@ \pnum \constraints \begin{itemize} -\item \tcode{T} is not the same type as \tcode{function_ref}, +\item \tcode{\exposid{is-convertible-from-specialization}} is \tcode{false}, \item \tcode{is_pointer_v} is \tcode{false}, and -\item \tcode{T} is not a specialization of \tcode{constant_arg_t}. +\item \tcode{T} is not a specialization of \tcode{constant_wrapper}. \end{itemize} \end{itemdescr} @@ -15451,13 +15879,13 @@ \end{itemdescr} \begin{itemdecl} -template - function_ref(constant_arg_t) -> function_ref<@\seebelow@>; +template + function_ref(constant_wrapper) -> function_ref<@\seebelow@>; \end{itemdecl} \begin{itemdescr} \pnum -Let \tcode{F} be \tcode{remove_pointer_t}. +Let \tcode{F} be \tcode{remove_pointer_t}. \pnum \constraints @@ -15469,14 +15897,11 @@ \end{itemdescr} \begin{itemdecl} -template - function_ref(constant_arg_t, T&&) -> function_ref<@\seebelow@>; +template + function_ref(constant_wrapper, T&&) -> function_ref<@\seebelow@>; \end{itemdecl} \begin{itemdescr} -\pnum -Let \tcode{F} be \tcode{decltype(f)}. - \pnum \constraints %FIXME: R and E should be defined outside of these constraints. @@ -15943,15 +16368,8 @@ \pnum \constantwhen -\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} +Neither \tcode{To} nor \tcode{From} +has constexpr-unknown representation\iref{expr.const.core}. \pnum \returns @@ -16067,7 +16485,7 @@ \remarks A function call expression that violates the precondition in the \expects element -is not a core constant expression\iref{expr.const}. +is not a core constant expression\iref{expr.const.core}. \end{itemdescr} \indexlibraryglobal{bit_floor}% diff --git a/tools/check-output.sh b/tools/check-output.sh index a28d236e0c..280fc1d423 100755 --- a/tools/check-output.sh +++ b/tools/check-output.sh @@ -36,34 +36,34 @@ rm -f tmp.txt # Find bad labels grep newlabel `ls *.aux | grep -v std.aux` | awk -F '{' '{ print $2 }' | - sed 's/}//g' | sed 's/^tab://;s/fig://;s/eq://;s/idx.*\..//' | + sed 's/}//g' | sed 's/^tab://;s/fig://;s/eq://;s/ub://;s/ubx://;s/ifndr://;s/ifndrx://;s/idx.*\..//' | grep -v '^[a-z.0-9]*$' | sed 's/^\(.*\)$/bad label \1/' | fail || failed=1 # Find grammar index entries missing a definition cat std-grammarindex.ind | - awk 'BEGIN { def=1 } /^ .item/ { if (def==0) { gsub("[{},]", "", item); print item } item=$NF; def=0; next } /hyperindexformat/ { def=1 }' | + awk 'BEGIN { def=1 } /^ .item/ { if (def==0) { gsub("[{},]", "", item); print item } item=$NF; def=0; next } /hyper(x{0,1})indexformat/ { def=1 }' | grep -v -- '-keyword$' | # xxx-keyword is special sed 's/^\(.*\)$/grammar non-terminal \1 has no definition/' | fail || failed=1 # Find header index entries missing a definition cat std-headerindex.ind | - awk 'BEGIN { def=1 } /^ .item/ { if (def==0) { gsub("[{},]", "", item); print item } i=NF; while (i > 0 && $i !~ "<[a-z_.]*>") { --i; } item=$i; def=0; next } /hyperindexformat/ { def=1 }' | + awk 'BEGIN { def=1 } /^ .item/ { if (def==0) { gsub("[{},]", "", item); print item } i=NF; while (i > 0 && $i !~ "<[a-z_.]*>") { --i; } item=$i; def=0; next } /hyper(x{0,1})indexformat/ { def=1 }' | sed 's/^\(.*\)$/header \1 has no definition/' | fail || failed=1 # Find concept index entries missing a definition cat std-conceptindex.ind | - sed 's/.hyperindexformat/\nhyperindexformat/;s/.hyperpage/\nhyperpage/g' | + sed 's/.hyper\(x\{0,1\}\)indexformat/\nhyperindexformat/;s/.hyperpage/\nhyperpage/g' | awk 'BEGIN { def=1 } /^ .item/ { if (def==0) { gsub("[{},]", "", item); print item } item=$NF; def=0; next } /hyperindexformat/ { def=1 }' | sed 's/^\(.*\)$/concept \1 has no definition/' | fail || failed=1 # Find undecorated concept names in code blocks patt="`cat std-conceptindex.ind | - sed 's/.hyperindexformat/\nhyperindexformat/;s/.hyperpage/\nhyperpage/' | + sed 's/.hyper\(x\{0,1\}\)indexformat/\nhyperindexformat/;s/.hyperpage/\nhyperpage/' | sed -n 's/^ .item.*{\([-a-z_]*\)}.*$/\1/p;s/^ .item.*frenchspacing \([a-z_]*\)}.*$/\1/p'`" patt="`echo $patt | sed 's/ /\\\\|/g'`" diff --git a/tools/check-source.sh b/tools/check-source.sh index ffd7c94d47..b473511598 100755 --- a/tools/check-source.sh +++ b/tools/check-source.sh @@ -242,7 +242,7 @@ done | fail 'hanging paragraph' || failed=1 # Subclauses without siblings -for f in $texfiles; do +for f in `ls $texfiles | grep -v ub.tex | grep -v ifndr.tex`; do sed -n '/^\\rSec/{=;p;}' $f | # prefix output with filename and line sed '/^[0-9]\+$/{N;s/\n/:/;}' | sed "s/.*/$f:&/" |