| Document #: | P3923R0 |
| Date: | 2025-11-07 |
| Project: | Programming Language C++ |
| Audience: |
LWG |
| Reply-to: |
Tim Song <t.canens.cpp@gmail.com> |
This paper provides wording to resolve the following national body comments on the C++26 CD:
This wording is relative to [N5014] except where noted.
Edit 22.4.7 [tuple.helper] as indicated:
4 […]
5 […]
6 In addition to being available via inclusion of the
<tuple>header, the template is available when any of the headers<array>,<complex>,<ranges>, or<utility>are included.
7 […]
8 In addition to being available via inclusion of the
<tuple>header, the template is available when any of the headers<array>,<complex>,<ranges>, or<utility>are included.
[ Drafting note: We add a cross-reference and a note to 23.3.9.1 [hive.overview] to clarify that “insertion” doesn’t include construction or assignment. ]
1 A
hiveis a type of sequence container that provides constant-time insertion and erasure operations. Storage is automatically managed in multiple memory blocks, referred to as element blocks. Insertion (23.3.9.4 [hive.modifiers]) position is determined by the container, and insertion may re-use the memory locations of erased elements. [ Note ?: Construction and assignment are not considered to involve insertion operations. — end note ]
template<container-compatible-range<T> R> hive(from_range_t, R&& rg, const Allocator& = Allocator()); template<container-compatible-range<T> R> hive(from_range_t, R&& rg, hive_limits block_limits, const Allocator& = Allocator());13 Effects: Constructs a
hiveobject equal towith the elements of the rangerg, using the specified allocator. If the second overload is called, also initializescurrent-limitswithblock_limits.14 Complexity: Linear in
ranges::distance(rg).15 Preconditions:
Tis Cpp17CopyInsertable intohive.16 Effects: Constructs a hive object equal towith the elements of
x. If the second overload is called, usesalloc. Initializescurrent-limitswithx.current-limits.17 Complexity: Linear in
x.size().18 Preconditions: For the second overload, when
allocator_traits<alloc>::is_always_equal::valueisfalse,Tmeets the Cpp17MoveInsertable requirements.19 Effects: When the first overload is called, or the second overload is called and
alloc == x.get_allocator()istrue,current-limitsis set tox.current-limitsand each element block is moved fromxinto*this. Pointers and references to the elements ofxnow refer to those same elements but as members of*this. Iterators referring to the elements ofxwill continue to refer to their elements, but they now behave as iterators into*this. If the second overload is called andalloc == x.get_allocator()is false, each element inxis moved into*this. References, pointers and iterators referring to the elements ofx, as well as the past-the-end iterator ofx, are invalidated.20 Postconditions:
x.empty()istrue. The relative order of the elements of*thisis the same as that of the elements ofxprior to this call.21 Complexity: If the second overload is called and
alloc == x.get_allocator()isfalse, linear inx.size(). Otherwise constant.hive(initializer_list<T> il, const Allocator& = Allocator()); hive(initializer_list<T> il, hive_limits block_limits, const Allocator& = Allocator());22 Preconditions:
Tis Cpp17CopyInsertable intohive.13 Effects: Constructs a
hiveobject equal towith the elements ofil, using the specified allocator. If the second overload is called, also initializescurrent-limitswithblock_limits.14 Complexity: Linear in
il.size().15 Preconditions:
Tis Cpp17CopyInsertable intohiveand Cpp17CopyAssignable.16 Effects: All elements in
*thisare either copy-assigned to, or destroyed. All elements inxare copied into*this, maintaining their relative order.[ Note 1:
current-limitsis unchanged. — end note ]17 Complexity: Linear in
size() + x.size().hive& operator=(hive&& x) noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value || allocator_traits<Allocator>::is_always_equal::value);18 Preconditions: When
is
false,Tis Cpp17MoveInsertable intohiveand Cpp17MoveAssignable.19 Effects: Each element in
*thisis either move-assigned to, or destroyed. Whenis
true,current-limitsis set tox.current-limitsand each element block is moved fromxinto*this. Pointers and references to the elements ofxnow refer to those same elements but as members of*this. Iterators referring to the elements ofxwill continue to refer to their elements, but they now behave as iterators into*this, not intox. Whenis
false, each element inxis moved into*this. References, pointers and iterators referring to the elements ofx, as well as the past-the-end iterator ofx, are invalidated.20 Postconditions:
x.empty()istrue. The relative order of the elements of*thisis the same as that of the elements ofxprior to this call.21 Complexity: Linear in
size(). Ifis
false, also linear inx.size().
[ Drafting note: LWG concluded that the wording is already clear that the order does not change because nothing in the wording gives permission for it to change. However, it was pointed out that the first sentence of the Remarks: paragraph is similarly a “nothing happens” sentence and LWG decided to strike it to avoid the erroneous implication that “everything not explictly described as not changing can change”. ]
Edit 23.3.9.3 [hive.capacity] as indicated:
3 Effects: […]
4 Postconditions: […]
5 Throws: […]
6 Complexity: […]
7 Remarks: The size of the sequence is not changed. All references, pointers, and iterators referring to elements in
*this, as well as the past-the-end iterator, remain valid.
Edit 23.3.9.3 [hive.capacity] as indicated:
12 Effects: For the first overload, all reserved blocks are deallocated, and
capacity()is reduced accordingly. For the second overload, ifn >= capacity()istrue, there are no effects; otherwise,capacity()is reduced to no less thann.13 Complexity: Linear in the number of reserved blocks deallocated.
14 Remarks: All references, pointers, and iterators referring to elements in
*this, as well as the past-the-end iterator, remain valid.
[ Drafting note: LWG determined that there is no good reason to check the block limits during or after the splice and therefore we can offer the strong exception guarantee. ]
Edit 23.3.9.5 [hive.operations] as indicated:
2 Preconditions:
get_allocator() == x.get_allocator()istrue.3 Effects: If
addressof(x) == thisistrue, the behavior is erroneous and there are no effects. If an exception is thrown, there are no effects. Otherwise, inserts the contents ofxinto*thisandxbecomes empty. Pointers and references to the moved elements ofxnow refer to those same elements but as members of*this. Iterators referring to the moved elements continue to refer to their elements, but they now behave as iterators into*this, not intox.4 Throws:
length_errorif any ofx’s active blocks are not within the bounds ofcurrent-limits.5 Complexity: Linear in the sum of all element blocks in
xplus all element blocks in*this.6 Remarks: Reserved blocks in
xare not transferred into*this. Ifaddressof(x) == thisisfalse, invalidates the past-the-end iterator for bothxand*this.
template<class InputIterator1, class InputIterator2, class OutputIterator> constexpr OutputIterator set_union(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result); template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2, class ForwardIterator> ForwardIterator set_union(ExecutionPolicy&& exec, ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result); template<class InputIterator1, class InputIterator2, class OutputIterator, class Compare> constexpr OutputIterator set_union(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp); template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2, class ForwardIterator, class Compare> ForwardIterator set_union(ExecutionPolicy&& exec, ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result, Compare comp); template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2, weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires mergeable<I1, I2, O, Comp, Proj1, Proj2> constexpr ranges::set_union_result<I1, I2, O> ranges::set_union(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); template<input_range R1, input_range R2, weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2> constexpr ranges::set_union_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O> ranges::set_union(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); template<execution-policy Ep, random_access_iterator I1, sized_sentinel_for<I1> S1, random_access_iterator I2, sized_sentinel_for<I2> S2, random_access_iterator O, sized_sentinel_for<O> OutS, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires mergeable<I1, I2, O, Comp, Proj1, Proj2> ranges::set_union_result<I1, I2, O> ranges::set_union(Ep&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result, OutS result_last, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); template<execution-policy Ep, sized-random-access-range R1, sized-random-access-range R2, sized-random-access-range OutR, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires mergeable<iterator_t<R1>, iterator_t<R2>, iterator_t<OutR>, Comp, Proj1, Proj2> ranges::set_union_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, borrowed_iterator_t<OutR>> ranges::set_union(Ep&& exec, R1&& r1, R2&& r2, OutR&& result_r, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});1 Let:
- (1.1)
compbeless{}, andproj1andproj2beidentity{}for the overloads with no parameters by those names;- (1.2) M be the number of elements in the sorted union (see below)
last1 - first1plus the number of elements in[first2, last2)that are not present in[first1, last1);- (1.3)
result_lastberesult +M for the overloads with no parameterresult_lastorresult_r;- (1.4) N be min(M,
result_last - result).2 Preconditions: The ranges
[first1, last1)and[first2, last2)are sorted with respect tocompandproj1orproj2, respectively. The resulting range does not overlap with either of the original ranges.3 Effects: Constructs a sorted union of theN elements from the two ranges; that is, the set of elements that are present in one or both of the ranges. If
[first1, last1)contains m elements that are equivalent to each other and[first2, last2)contains n elements that are equivalent to them, then all m elements from the first range are included in the union, in order, and then the final max(n − m, 0) elements from the second range are included in the union, in order. If, of those elements, k elements from the first range are copied to the output range, then the first min(k, n) elements from the second range are considered skipped. Copies the first N elements of the sorted union to the range[result, result +N).4 Returns:
- (4.1)
result_lastfor the overloads in namespacestd.- (4.2)
{last1, last2, result +N}for the overloads in namespaceranges, if N is equal to M.- (4.3) Otherwise,
{j1, j2, result_last}{first1 +A, first2 +B, result_last}for the overloads in namespaceranges, where the iteratorsj1andj2point to positions past the lastA and B are the numbers of copied or skipped elements in[first1, last1)and[first2, last2), respectively.5 Complexity: At most
2 * ((last1 - first1) + (last2 - first2)) - 1comparisons and applications of each projection.6 Remarks: Stable (16.4.6.8 [algorithm.stable]). If
[first1, last1)contains m elements that are equivalent to each other and[first2, last2)contains n elements that are equivalent to them, then all m elements from the first range are copied to the output range, in order, and then the final max(n − m, 0) elements from the second range are copied to the output range, in order.
template<class InputIterator1, class InputIterator2, class OutputIterator> constexpr OutputIterator set_intersection(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result); template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2, class ForwardIterator> ForwardIterator set_intersection(ExecutionPolicy&& exec, ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result); template<class InputIterator1, class InputIterator2, class OutputIterator, class Compare> constexpr OutputIterator set_intersection(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp); template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2, class ForwardIterator, class Compare> ForwardIterator set_intersection(ExecutionPolicy&& exec, ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result, Compare comp); template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2, weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires mergeable<I1, I2, O, Comp, Proj1, Proj2> constexpr ranges::set_intersection_result<I1, I2, O> ranges::set_intersection(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); template<input_range R1, input_range R2, weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2> constexpr ranges::set_intersection_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O> ranges::set_intersection(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); template<execution-policy Ep, random_access_iterator I1, sized_sentinel_for<I1> S1, random_access_iterator I2, sized_sentinel_for<I2> S2, random_access_iterator O, sized_sentinel_for<O> OutS, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires mergeable<I1, I2, O, Comp, Proj1, Proj2> ranges::set_intersection_result<I1, I2, O> ranges::set_intersection(Ep&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result, OutS result_last, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); template<execution-policy Ep, sized-random-access-range R1, sized-random-access-range R2, sized-random-access-range OutR, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires mergeable<iterator_t<R1>, iterator_t<R2>, iterator_t<OutR>, Comp, Proj1, Proj2> ranges::set_intersection_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, borrowed_iterator_t<OutR>> ranges::set_intersection(Ep&& exec, R1&& r1, R2&& r2, OutR&& result_r, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});1 Let:
- (1.1)
compbeless{}, andproj1andproj2beidentity{}for the overloads with no parameters by those names;- (1.2) M be the number of elements in the sorted intersection (see below)
[first1, last1)that are present in[first2, last2);- (1.3)
result_lastberesult +M for the overloads with no parameterresult_lastorresult_r;- (1.4) N be min(M,
result_last - result).2 Preconditions: The ranges
[first1, last1)and[first2, last2)are sorted with respect tocompandproj1orproj2, respectively. The resulting range does not overlap with either of the original ranges.3 Effects: Constructs a sorted intersection of theN elements from the two ranges; that is, the set of elements that are present in both of the ranges. If
[first1, last1)contains m elements that are equivalent to each other and[first2, last2)contains n elements that are equivalent to them, the first min(m, n) elements from the first range are included in the sorted intersection. 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 skipped. If N < M, a non-copied element is also considered skipped if it compares less than the (N + 1)th element of the sorted intersection. Copies the first N elements of the sorted intersection to the range[result, result +N).4 Returns:
- (4.1)
result_lastfor the overloads in namespacestd.- (4.2)
{last1, last2, result +N}for the overloads in namespaceranges, if N is equal to M.- (4.3) Otherwise,
{j1, j2, result_last}{first1 +A, first2 +B, result_last}for the overloads in namespaceranges, where the iteratorsj1andj2point to positions past the lastA and B are the numbers of copied or skipped elements in[first1, last1)and[first2, last2), respectively.5 Complexity: At most
2 * ((last1 - first1) + (last2 - first2)) - 1comparisons and applications of each projection.6 Remarks: Stable (16.4.6.8 [algorithm.stable]). If
[first1, last1)contains m elements that are equivalent to each other and[first2, last2)contains n elements that are equivalent to them, the first min(m, n) elements are copied from the first range to the output range, in order.
template<class InputIterator1, class InputIterator2, class OutputIterator> constexpr OutputIterator set_difference(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result); template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2, class ForwardIterator> ForwardIterator set_difference(ExecutionPolicy&& exec, ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result); template<class InputIterator1, class InputIterator2, class OutputIterator, class Compare> constexpr OutputIterator set_difference(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp); template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2, class ForwardIterator, class Compare> ForwardIterator set_difference(ExecutionPolicy&& exec, ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result, Compare comp); template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2, weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires mergeable<I1, I2, O, Comp, Proj1, Proj2> constexpr ranges::set_difference_result<I1, O> ranges::set_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); template<input_range R1, input_range R2, weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2> constexpr ranges::set_difference_result<borrowed_iterator_t<R1>, O> ranges::set_difference(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); template<execution-policy Ep, random_access_iterator I1, sized_sentinel_for<I1> S1, random_access_iterator I2, sized_sentinel_for<I2> S2, random_access_iterator O, sized_sentinel_for<O> OutS, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires mergeable<I1, I2, O, Comp, Proj1, Proj2> ranges::set_difference_result<I1, O> ranges::set_difference(Ep&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result, OutS result_last, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); template<execution-policy Ep, sized-random-access-range R1, sized-random-access-range R2, sized-random-access-range OutR, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires mergeable<iterator_t<R1>, iterator_t<R2>, iterator_t<OutR>, Comp, Proj1, Proj2> ranges::set_difference_result<borrowed_iterator_t<R1>, borrowed_iterator_t<OutR>> ranges::set_difference(Ep&& exec, R1&& r1, R2&& r2, OutR&& result_r, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});1 Let:
- (1.1)
compbeless{}, andproj1andproj2beidentity{}for the overloads with no parameters by those names;- (1.2) M be the number of elements in the sorted difference (see below)
[first1, last1)that are not present in[first2, last2);- (1.3)
result_lastberesult +M for the overloads with no parameterresult_lastorresult_r;- (1.4) N be min(M,
result_last - result).2 Preconditions: The ranges
[first1, last1)and[first2, last2)are sorted with respect tocompandproj1orproj2, respectively. The resulting range does not overlap with either of the original ranges.3 Effects: Copies N elements of the range
[first1, last1)which are not present in the range[first2, last2)to the range[result, result +N). The elements in the constructed range are sorted.3 Effects: Constructs a sorted difference between the elements from the two ranges; that is, the set of elements that are present in the range
[first1, last1)but not[first2, last2). If[first1, last1)contains m elements that are equivalent to each other and[first2, last2)contains n elements that are equivalent to them, the last max(m − n, 0) elements from[first1, last1)are included in the sorted difference, in order. Copies the first N elements of the sorted difference to the range[result, result +N).4 Returns:
- (4.1)
result_lastfor the overloads in namespacestd.- (4.2)
{last1, result +N}for the overloads in namespaceranges, if N is equal to M.- (4.3) Otherwise,
{j1, result_last}for the overloads in namespaceranges, where the iteratorj1points to the position of thepast the last copied or skipped element in[first1, last1)corresponding to the (N + 1)th element of the sorted difference.5 Complexity: At most
2 * ((last1 - first1) + (last2 - first2)) - 1comparisons and applications of each projection.6 Remarks: Stable (16.4.6.8 [algorithm.stable]). If
[first1, last1)contains m elements that are equivalent to each other and[first2, last2)contains n elements that are equivalent to them, the last max(m − n, 0) elements are copied from[first1, last1)to the output range, in order.
template<class InputIterator1, class InputIterator2, class OutputIterator> constexpr OutputIterator set_symmetric_difference(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result); template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2, class ForwardIterator> ForwardIterator set_symmetric_difference(ExecutionPolicy&& exec, ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result); template<class InputIterator1, class InputIterator2, class OutputIterator, class Compare> constexpr OutputIterator set_symmetric_difference(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp); template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2, class ForwardIterator, class Compare> ForwardIterator set_symmetric_difference(ExecutionPolicy&& exec, ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result, Compare comp); template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2, weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires mergeable<I1, I2, O, Comp, Proj1, Proj2> constexpr ranges::set_symmetric_difference_result<I1, I2, O> ranges::set_symmetric_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); template<input_range R1, input_range R2, weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2> constexpr ranges::set_symmetric_difference_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O> ranges::set_symmetric_difference(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); template<execution-policy Ep, random_access_iterator I1, sized_sentinel_for<I1> S1, random_access_iterator I2, sized_sentinel_for<I2> S2, random_access_iterator O, sized_sentinel_for<O> OutS, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires mergeable<I1, I2, O, Comp, Proj1, Proj2> ranges::set_symmetric_difference_result<I1, I2, O> ranges::set_symmetric_difference(Ep&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result, OutS result_last, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); template<execution-policy Ep, sized-random-access-range R1, sized-random-access-range R2, sized-random-access-range OutR, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires mergeable<iterator_t<R1>, iterator_t<R2>, iterator_t<OutR>, Comp, Proj1, Proj2> ranges::set_symmetric_difference_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, borrowed_iterator_t<OutR>> ranges::set_symmetric_difference(Ep&& exec, R1&& r1, R2&& r2, OutR&& result_r, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});1 Let:
- (1.1)
compbeless{}, andproj1andproj2beidentity{}for the overloads with no parameters by those names;
- (1.2) K be the number of elements in
[first1, last1)that are not present in[first2, last2);
- (1.3) M be the number of elements in the sorted symmetric difference (see below)
[first2, last2)that are not present in[first1, last1);- (1.4)
result_lastberesult +M + K for the overloads with no parameterresult_lastorresult_r;- (1.5) N be min(K + M,
result_last - result).2 Preconditions: The ranges
[first1, last1)and[first2, last2)are sorted with respect tocompandproj1orproj2, respectively. The resulting range does not overlap with either of the original ranges.3 Effects: Copies the elements of the range
[first1, last1)that are not present in the range[first2, last2), and the elements of the range[first2, last2)that are not present in the range[first1, last1)to the range[result, result +N). The elements in the constructed range are sorted.3 Effects: Constructs a sorted symmetric difference of the elements from the two ranges; that is, the set of elements that are present in exactly one of
[first1, last1)and[first2, last2). If[first1, last1)contains m elements that are equivalent to each other and[first2, last2)contains n elements that are equivalent to them, then |m − n| of those elements are included in the symmetric difference: the last m − n of these elements from[first1, last1), in order, if m > n, and the last n − m of these elements from[first2, last2), in order, if m < n. If N < M, a non-copied element is considered skipped if it compares less than or equivalent to the (N + 1)th element of the sorted symmetric difference, unless it is from the same range as that element and does not precede it. Copies the first N elements of the sorted symmetric difference to the range[result, result +N).4 Returns:
- (4.1)
result_lastfor the overloads in namespacestd.- (4.2)
{last1, last2, result +N}for the overloads in namespaceranges, if N is equal to M + K.- (4.3) Otherwise,
{j1, j2, result_last}{first1 +A, first2 +B, result_last}for the overloads in namespaceranges, where the iteratorsj1andj2point to positions past the lastA and B are the numbers of copied or skipped elements in[first1, last1)and[first2, last2), respectively.5 Complexity: At most
2 * ((last1 - first1) + (last2 - first2)) - 1comparisons and applications of each projection.6 Remarks: Stable (16.4.6.8 [algorithm.stable]). If
[first1, last1)contains m elements that are equivalent to each other and[first2, last2)contains n elements that are equivalent to them, then |m − n| of those elements shall be copied to the output range: the last m − n of these elements from[first1, last1)if m > n, and the last n − m of these elements from[first2, last2)if m < n. In either case, the elements are copied in order.
Edit 21.4.16 [meta.reflection.define.aggregate] as indicated:
template<reflection_range R = initializer_list<info>>
consteval info define_aggregate(info class_type, R&& mdescrs);7 Let C be the class represented by
class_typeand rK be the Kth reflection value inmdescrs. For every rK inmdescrs, let (TK, NK, AK, WK, NUAK) be the corresponding data member description represented by rK.8 Constant When:
- (8.1) C is incomplete from every point in the evaluation context; [ Note 4: C can be a class template specialization for which there is a reachable definition of the class template. In this case, the injected declaration is an explicit specialization. — end note ]
- (8.2) […]
- (8.3) […]
- (8.4) […]
9 Effects: Produces an injected declaration D (7.7 [expr.const]) that defines C and has properties as follows:
- (9.1) […]
- (9.2) […]
- (9.3) […]
- (9.4) If C is a specialization of a templated class T, and C is not a local class, then D is an explicit specialization of T.
- (9.5) […]
- (9.6) […]
10 Returns:
class_type.
? Remarks: If C is a specialization of a templated class and it has not been instantiated, C is treated as an explicit specialization.
7 Let
spawn-future-statebe the exposition-only class template:namespace std::execution { template<class Alloc, scope_token Token, sender Sender, class Env> struct spawn-future-state // exposition only : spawn-future-state-base<completion_signatures_of_t<future-spawned-sender<Sender, Env>>> { using sigs-t = // exposition only completion_signatures_of_t<future-spawned-sender<Sender, Env>>; using receiver-t = // exposition only spawn-future-receiver<sigs-t>; using op-t = // exposition only connect_result_t<future-spawned-sender<Sender, Env>, receiver-t>; spawn-future-state(Alloc alloc, Sender&& sndr, Token token, Env env) // exposition only : alloc(std::move(alloc)), op(connect( write_env(stop-when(std::forward<Sender>(sndr), ssource.get_token()), std::move(env)), receiver-t(this))), token(std::move(token)), associated(token.try_associate()) { if (associated) start(op); else set_stopped(receiver-t(this)); } void complete() noexcept override; // exposition only void consume(receiver auto& rcvr) noexcept; // exposition only void abandon() noexcept; // exposition only private:using alloc-t = // exposition onlyallocator_traits<Alloc>::template rebind_alloc<spawn-future-state>;Allocalloc-talloc; // exposition only ssource-t ssource; // exposition only op-t op; // exposition only Token token; // exposition only bool associated; // exposition only void destroy() noexcept; // exposition only };template<class Alloc, scope_token Token, sender Sender, class Env>spawn-future-state(Alloc alloc, Sender&& sndr, Token token, Env env) -> spawn-future-state<Alloc, Token, Sender, Env>; }[…]
12 Effects: Equivalent to:
auto token = std::move(this->token); bool associated = this->associated; { - auto alloc = std::move(this->alloc); - - allocator_traits<alloc-t>::destroy(alloc, this); - allocator_traits<alloc-t>::deallocate(alloc, this, 1); + using traits = allocator_traits<Alloc>::template rebind_traits<spawn-future-state>; + typename traits::allocator_type alloc(std::move(this->alloc)); + traits::destroy(alloc, this); + traits::deallocate(alloc, this, 1); } if (associated) token.disassociate();[…]
16 The expression
spawn_future(sndr, token, env)has the following effects:
- (16.1) Uses
allocto allocate and construct an objectsof a type that is a specialization ofspawn-future-statetypedecltype(spawn-future-state(alloc, token.wrap(sndr), token, senv))fromalloc,token.wrap(sndr),token, andsenv. If an exception is thrown then any constructed objects are destroyed and any allocated memory is deallocated.- (16.2) Constructs an object
uof a type that is a specialization ofunique_ptrsuch that:- (16.3) Returns
make-sender(spawn_future, std::move(u)).
5 Let
spawn-statebe the exposition-only class template:namespace std::execution { template<class Alloc, scope_token Token, sender Sender> struct spawn-state : spawn-state-base { // exposition only using op-t = connect_result_t<Sender, spawn-receiver>; // exposition only spawn-state(Alloc alloc, Sender&& sndr, Token token); // exposition only void complete() noexcept override; // exposition only void run(); // exposition only private:using alloc-t = // exposition onlyallocator_traits<Alloc>::template rebind_alloc<spawn-state>;Allocalloc-talloc; // exposition only op-t op; // exposition only Token token; // exposition only void destroy() noexcept; // exposition only }; }[…]
9 Effects: Equivalent to:
- auto alloc = std::move(this->alloc); - - allocator_traits<alloc-t>::destroy(alloc, this); - allocator_traits<alloc-t>::deallocate(alloc, this, 1); + using traits = allocator_traits<Alloc>::template rebind_traits<spawn-state>; + typename traits::allocator_type alloc(std::move(this->alloc)); + traits::destroy(alloc, this); + traits::deallocate(alloc, this, 1);11 The expression
spawn(sndr, token, env)is of typevoidand has the following effects:
- (11.1) Uses
allocto allocate and construct an objectoof type that is a specialization ofspawn-statedecltype(spawn-state(alloc, write_env(token.wrap(sndr), senv), token)fromalloc,write_env(token.wrap(sndr), senv), andtokenand then invokeso.run(). If an exception is thrown then any constructed objects are destroyed and any allocated memory is deallocated.
[ Editor's note: This wording is relative to the working draft after the application of the resolution of US 209-232. ]
Edit 33.9.12.11 [exec.bulk] as indicated:
5 The exposition-only class template impls-for (33.9.2 [exec.snd.expos]) is specialized for bulk_chunked_t as follows:
namespace std::execution {
template<>
struct impls-for<bulk_chunked_t> : default-impls {
static constexpr auto complete = see below;
template<class Sndr, class... Env>
static consteval void check-types();
};
}The member impls-for<bulk_chunked_t>::complete is initialized with a callable object equivalent to the following lambda:
[…]
? Effects: Equivalent to:
auto cs = get_completion_signatures<child-type<Sndr>, FWD-ENV-T(Env)...>(); auto fn = []<class... Ts>(set_value_t(*)(Ts...)) { using data_type = data-type<Sndr>; if constexpr (!invocable<remove_cvref_t<child-type<data_type>&, remove_cvref_t<data-type<data_type>>, Ts&...>) throw unspecified-exception(); }; cs.for-each(overload-set(fn, [](auto){}));
6 The exposition-only class template impls-for (33.9.2 [exec.snd.expos]) is specialized for bulk_unchunked_t as follows:
namespace std::execution {
template<>
struct impls-for<bulk_unchunked_t> : default-impls {
static constexpr auto complete = see below;
template<class Sndr, class... Env>
static consteval void check-types();
};
}The member impls-for<bulk_unchunked_t>::complete is initialized with a callable object equivalent to the following lambda:
[…]
7 Effects: Equivalent to:
auto cs = get_completion_signatures<child-type<Sndr>, FWD-ENV-T(Env)...>(); auto fn = []<class... Ts>(set_value_t(*)(Ts...)) {using data_type = data-type<Sndr>;if constexpr (!invocable<remove_cvref_t<child-type<data_type>>&,remove_cvref_t<data-type<data_typeSndr>>, Ts&...>) throw unspecified-exception(); }; cs.for-each(overload-set(fn, [](auto){}));
namespace std { template<class... Types> class tuple { public: // [tuple.cnstr], tuple construction constexpr explicit(see below) tuple(); constexpr explicit(see below) tuple(const Types&...)noexcept(see below); // only if sizeof...(Types) >= 1 template<class... UTypes> constexpr explicit(see below) tuple(UTypes&&...)noexcept(see below); // only if sizeof...(Types) >= 1 tuple(const tuple&) = default; tuple(tuple&&) = default; template<class... UTypes> constexpr explicit(see below) tuple(tuple<UTypes...>&); template<class... UTypes> constexpr explicit(see below) tuple(const tuple<UTypes...>&); template<class... UTypes> constexpr explicit(see below) tuple(tuple<UTypes...>&&); template<class... UTypes> constexpr explicit(see below) tuple(const tuple<UTypes...>&&); template<class U1, class U2> constexpr explicit(see below) tuple(pair<U1, U2>&); // only if sizeof...(Types) == 2 template<class U1, class U2> constexpr explicit(see below) tuple(const pair<U1, U2>&); // only if sizeof...(Types) == 2 template<class U1, class U2> constexpr explicit(see below) tuple(pair<U1, U2>&&); // only if sizeof...(Types) == 2 template<class U1, class U2> constexpr explicit(see below) tuple(const pair<U1, U2>&&); // only if sizeof...(Types) == 2 template<tuple-like UTuple> constexpr explicit(see below) tuple(UTuple&&); // allocator-extended constructors template<class Alloc> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a); template<class Alloc> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, const Types&...); template<class Alloc, class... UTypes> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, UTypes&&...); template<class Alloc> constexpr tuple(allocator_arg_t, const Alloc& a, const tuple&); template<class Alloc> constexpr tuple(allocator_arg_t, const Alloc& a, tuple&&); template<class Alloc, class... UTypes> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&); template<class Alloc, class... UTypes> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&); template<class Alloc, class... UTypes> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&&); template<class Alloc, class... UTypes> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&&); template<class Alloc, class U1, class U2> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&); template<class Alloc, class U1, class U2> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&); template<class Alloc, class U1, class U2> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&); template<class Alloc, class U1, class U2> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&&); template<class Alloc, tuple-like UTuple> constexpr explicit(see below) tuple(allocator_arg_t, const Alloc& a, UTuple&&); // [tuple.assign], tuple assignment constexpr tuple& operator=(const tuple&); constexpr const tuple& operator=(const tuple&) const; constexpr tuple& operator=(tuple&&) noexcept(see below); constexpr const tuple& operator=(tuple&&) const; template<class... UTypes> constexpr tuple& operator=(const tuple<UTypes...>&); template<class... UTypes> constexpr const tuple& operator=(const tuple<UTypes...>&) const; template<class... UTypes> constexpr tuple& operator=(tuple<UTypes...>&&); template<class... UTypes> constexpr const tuple& operator=(tuple<UTypes...>&&) const; template<class U1, class U2> constexpr tuple& operator=(const pair<U1, U2>&); // only if sizeof...(Types) == 2 template<class U1, class U2> constexpr const tuple& operator=(const pair<U1, U2>&) const; // only if sizeof...(Types) == 2 template<class U1, class U2> constexpr tuple& operator=(pair<U1, U2>&&); // only if sizeof...(Types) == 2 template<class U1, class U2> constexpr const tuple& operator=(pair<U1, U2>&&) const; // only if sizeof...(Types) == 2 template<tuple-like UTuple> constexpr tuple& operator=(UTuple&&); template<tuple-like UTuple> constexpr const tuple& operator=(UTuple&&) const; // [tuple.swap], tuple swap constexpr void swap(tuple&) noexcept(see below); constexpr void swap(const tuple&) const noexcept(see below); }; template<class... UTypes> tuple(UTypes...) -> tuple<UTypes...>; template<class T1, class T2> tuple(pair<T1, T2>) -> tuple<T1, T2>; template<class Alloc, class... UTypes> tuple(allocator_arg_t, Alloc, UTypes...) -> tuple<UTypes...>; template<class Alloc, class T1, class T2> tuple(allocator_arg_t, Alloc, pair<T1, T2>) -> tuple<T1, T2>; template<class Alloc, class... UTypes> tuple(allocator_arg_t, Alloc, tuple<UTypes...>) -> tuple<UTypes...>; }
constexpr explicit(see below) tuple(const Types&...)noexcept((is_nothrow_copy_constructible_v<Types> && ...));9 Constraints: […]
10 Effects: […]
11 Remarks: […]
template<class... UTypes> constexpr explicit(see below) tuple(UTypes&&... u)noexcept((is_nothrow_constructible_v<Types, UTypes> && ...));12 […]
13 Constraints: […]
14 Effects: […]
15 Remarks: […]
[N5014] Thomas Köppe. 2025-08-05. Working Draft, Standard for Programming Language C++.
https://wg21.link/n5014