adjacent_difference
shouldn't require creating temporariesSection: 26.10.12 [adjacent.difference] Status: C++20 Submitter: Billy O'Neal III Opened: 2018-02-02 Last modified: 2021-02-25
Priority: 3
View all other issues in [adjacent.difference].
View all issues with C++20 status.
Discussion:
Parallel adjacent_difference
is presently specified to "create a temporary object whose
type is ForwardIterator1
's value type". Serial adjacent_difference
does that
because it needs to work with input iterators, and needs to work when the destination range
exactly overlaps the input range. The parallel version requires forward iterators and doesn't
allow overlap, so it can avoid making these temporaries.
[2018-02-13, Priority set to 3 after mailing list discussion]
[2018-3-14 Wednesday evening issues processing; remove 'const' before minus
and move to Ready.]
Previous resolution [SUPERSEDED]:
This wording is relative to N4713.
Modify 26.10.12 [adjacent.difference] as indicated:
template<class InputIterator, class OutputIterator> OutputIterator adjacent_difference(InputIterator first, InputIterator last, OutputIterator result); template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2> ForwardIterator2 adjacent_difference(ExecutionPolicy&& exec, ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result); template<class InputIterator, class OutputIterator, class BinaryOperation> OutputIterator adjacent_difference(InputIterator first, InputIterator last, OutputIterator result, BinaryOperation binary_op); template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2, class BinaryOperation> ForwardIterator2 adjacent_difference(ExecutionPolicy&& exec, ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, BinaryOperation binary_op);-?- Let
T
be the value type ofdecltype(first)
. For the overloads that do not take an argumentbinary_op
, letbinary_op
be an lvalue that denotes an object of typeconst minus<>
.-1- Requires:
-2- Effects: For the overloads with no
(1.1) — For the overloads with no
ExecutionPolicy
,InputIterator
’s value typeT
shall beMoveAssignable
(Table 25) and shall be constructible from the type of*first
.acc
(defined below) shall be writable (24.3.1 [iterator.requirements.general]) to theresult
output iterator. The result of the expressionval - std::move(acc)
orbinary_op(val, std::move(acc))
shall be writable to theresult
output iterator.(1.2) — For the overloads with an
ExecutionPolicy
, thevalue type ofresult of the expressionsForwardIterator1
shall beCopyConstructible
(Table 24), constructible from the expression*first - *first
orbinary_op(*first, *first)
, and assignable to the value type ofForwardIterator2
binary_op(*first, *first)
and*first
shall be writable toresult
.(1.3) — […]
ExecutionPolicy
and a non-empty range, the function creates an accumulatoracc
whose type isof typeInputIterator
’s value typeT
, initializes it with*first
, and assigns the result to*result
. For every iteratori
in[first + 1, last)
in order, creates an objectval
whose type isInputIterator
’s value typeT
, initializes it with*i
, computesval - std::move(acc)
orbinary_op(val, std::move(acc))
, assigns the result to*(result + (i - first))
, and move assigns fromval
toacc
. -3- For the overloads with anExecutionPolicy
and a non-empty range,first the function creates an object whose type isperformsForwardIterator1
's value type, initializes it with*first
, and assigns the result to*result
. Then for everyd
in[1, last - first - 1]
, creates an objectval
whose type isForwardIterator1
's value type, initializes it with*(first + d) - *(first + d - 1)
orbinary_op(*(first + d), *(first + d - 1))
, and assigns the result to*(result + d)
*result = *first
. Then, for everyd
in[1, last - first - 1]
, performs*(result + d) = binary_op(*(first + d), *(first + (d - 1)))
.
[2018-06 Rapperswil: Adopted]
Proposed resolution:
This wording is relative to N4713.
Modify 26.10.12 [adjacent.difference] as indicated:
template<class InputIterator, class OutputIterator> OutputIterator adjacent_difference(InputIterator first, InputIterator last, OutputIterator result); template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2> ForwardIterator2 adjacent_difference(ExecutionPolicy&& exec, ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result); template<class InputIterator, class OutputIterator, class BinaryOperation> OutputIterator adjacent_difference(InputIterator first, InputIterator last, OutputIterator result, BinaryOperation binary_op); template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2, class BinaryOperation> ForwardIterator2 adjacent_difference(ExecutionPolicy&& exec, ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, BinaryOperation binary_op);-?- Let
T
be the value type ofdecltype(first)
. For the overloads that do not take an argumentbinary_op
, letbinary_op
be an lvalue that denotes an object of typeminus<>
.-1- Requires:
-2- Effects: For the overloads with no
(1.1) — For the overloads with no
ExecutionPolicy
,InputIterator
’s value typeT
shall beMoveAssignable
(Table 25) and shall be constructible from the type of*first
.acc
(defined below) shall be writable (24.3.1 [iterator.requirements.general]) to theresult
output iterator. The result of the expressionval - std::move(acc)
orbinary_op(val, std::move(acc))
shall be writable to theresult
output iterator.(1.2) — For the overloads with an
ExecutionPolicy
, thevalue type ofresult of the expressionsForwardIterator1
shall beCopyConstructible
(Table 24), constructible from the expression*first - *first
orbinary_op(*first, *first)
, and assignable to the value type ofForwardIterator2
binary_op(*first, *first)
and*first
shall be writable toresult
.(1.3) — […]
ExecutionPolicy
and a non-empty range, the function creates an accumulatoracc
whose type isof typeInputIterator
’s value typeT
, initializes it with*first
, and assigns the result to*result
. For every iteratori
in[first + 1, last)
in order, creates an objectval
whose type isInputIterator
’s value typeT
, initializes it with*i
, computesval - std::move(acc)
orbinary_op(val, std::move(acc))
, assigns the result to*(result + (i - first))
, and move assigns fromval
toacc
. -3- For the overloads with anExecutionPolicy
and a non-empty range,first the function creates an object whose type isperformsForwardIterator1
's value type, initializes it with*first
, and assigns the result to*result
. Then for everyd
in[1, last - first - 1]
, creates an objectval
whose type isForwardIterator1
's value type, initializes it with*(first + d) - *(first + d - 1)
orbinary_op(*(first + d), *(first + d - 1))
, and assigns the result to*(result + d)
*result = *first
. Then, for everyd
in[1, last - first - 1]
, performs*(result + d) = binary_op(*(first + d), *(first + (d - 1)))
.