std::adjacent_difference(3)
๐ std::adjacent_difference ๐
okay so bestie, this is the std::adjacent_difference(3) page from the C++ Standard Libary manual, and we are literally about to make adjacent differences make sense. โจ
๐ธ NAME ๐ธ
std::adjacent_difference โ std::adjacent_difference. yes, the name is the name, iykyk ๐
โจ Synopsis โจ
Defined in header <numeric>.
- (1)
constexpr since C++20:
template< class InputIt, class OutputIt >
OutputIt adjacent_difference( InputIt first, InputIt last,
OutputIt d_first );
- (2)
since C++17:
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >
ForwardIt2 adjacent_difference( ExecutionPolicy&& policy,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 d_first );
- (3)
constexpr since C++20:
template< class InputIt, class OutputIt, class BinaryOp >
OutputIt adjacent_difference( InputIt first, InputIt last,
OutputIt d_first, BinaryOp op );
- (4)
since C++17:
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class BinaryOp >
ForwardIt2 adjacent_difference( ExecutionPolicy&& policy,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 d_first, BinaryOp op );
๐ฆ What the overloads actually do ๐ฆ
(1) If [first, last) is empty, does nothing. Otherwise, performs the following operations in order:
- Creates an accumulator
accof typeT, and initializes it with*first. - Assigns
accto*d_first. - For each iterator
iterin[++first, last)in order, performs the following operations in order:- a) Creates an object
valof typeT, and initializes it with*iter. - b) Computes
val - acc(until C++11) orval - std::move(acc)(since C++11). - c) Assigns the result to
*++d_first. - d) Copy assigns from
valtoacc(until C++11) or move assigns fromvaltoacc(since C++11).
- a) Creates an object
(2) If [first, last) is empty, does nothing. Otherwise, performs the following operations in order:
- Assigns
*firstto*d_first. - For each integer
iin[1, std::distance(first, last)), performs the following operations in order:- a) Computes
curr - prev, wherecurris the nextith iterator offirst, andprevis the nexti - 1th iterator offirst. - b) Assigns the result to
*dest, wheredestis the nextith iterator ofd_first.
- a) Computes
(3) Same as (1), but computes op(val, acc) (until C++11) or op(val, std::move(acc)) (since C++11) instead.
(4) Same as (2), but computes op(curr, prev) instead.
Given binary_op as the actual binary operation:
- If any of the following conditions is satisfied, the program is ill-formed:
- For overloads (1,3):
Tis not constructible from*first.accis not writable tod_first.- The result of
binary_op(val, acc)(until C++11) orbinary_op(val, std::move(acc))(since C++11) is not writable tod_first.
- For overloads (2,4):
*firstis not writable tod_first.- The result of
binary_op(*first, *first)is not writable tod_first.
- For overloads (1,3):
- Given
d_lastas the iterator to be returned, if any of the following conditions is satisfied, the behavior is undefined:- For overloads (1,3),
Tis not MoveAssignable. (since C++11) - For overloads (2,4),
[first, last)and[d_first, d_last)overlaps. binary_opmodifies any element of[first, last)or[d_first, d_last).binary_opinvalidates any iterator or subrange in[first, last]or[d_first, d_last].
- For overloads (1,3),
๐ฆ Parameters ๐ฆ
first,lastโ the range of elements.d_firstโ the beginning of the destination range.policyโ the execution policy to use. See execution policy for details.opโ binary operation function object that will be applied.
The signature of the function should be equivalent to the following:
Ret fun(const Type1 &a, const Type2 &b);
The signature does not need to have const &. The types Type1 and Type2 must be such that an object of type iterator_traits<InputIt>::value_type can be implicitly converted to both of them. The type Ret must be such that an object of type OutputIt can be dereferenced and assigned a value of type Ret.
๐ Type requirements ๐
InputItmust meet the requirements ofLegacyInputIterator.OutputItmust meet the requirements ofLegacyOutputIterator.ForwardIt1,ForwardIt2must meet the requirements ofLegacyForwardIterator.
๐ Return value ๐
Iterator to the element past the last element written, or d_first if [first, last) is empty.
๐ฅ Complexity ๐ฅ
Given N as std::distance(first, last):
- 1,2: Exactly
N-1applications ofoperator-. - 3,4: Exactly
N-1applications of the binary functionop.
๐ญ Exceptions ๐ญ
The overloads with a template parameter named ExecutionPolicy report errors as follows:
- If execution of a function invoked as part of the algorithm throws an exception and
ExecutionPolicyis one of the standard policies,std::terminateis called. For any otherExecutionPolicy, the behavior is implementation-defined. - If the algorithm fails to allocate memory,
std::bad_allocis thrown.
๐ Possible implementation ๐
adjacent_difference (1)
template<class InputIt, class OutputIt>
constexpr // since C++20
OutputIt adjacent_difference(InputIt first, InputIt last, OutputIt d_first)
{
if (first == last)
return d_first;
typedef typename std::iterator_traits<InputIt>::value_type value_t;
value_t acc = *first;
*d_first = acc;
while (++first != last)
{
value_t val = *first;
*++d_first = val - std::move(acc); // std::move since C++11
acc = std::move(val);
}
return ++d_first;
}
adjacent_difference (3)
template<class InputIt, class OutputIt, class BinaryOp>
constexpr // since C++20
OutputIt adjacent_difference(InputIt first, InputIt last,
OutputIt d_first, BinaryOp op)
{
if (first == last)
return d_first;
typedef typename std::iterator_traits<InputIt>::value_type value_t;
value_t acc = *first;
*d_first = acc;
while (++first != last)
{
value_t val = *first;
*++d_first = op(val, std::move(acc)); // std::move since C++11
acc = std::move(val);
}
return ++d_first;
}
๐ง Notes ๐ง
acc was introduced because of the resolution of LWG issue 539. The reason for using acc rather than directly calculating the differences is because the semantic of the latter is confusing if the following types mismatch:
- the value type of
InputIt - the writable type(s) of
OutputIt - the types of the parameters of
operator-orop - the return type of
operator-orop
acc serves as the intermediate object to cache values of the iterated elements:
- its type is the value type of
InputIt - the value written to
d_first(which is the return value ofoperator-orop) is assigned to it - its value is passed to
operator-orop
char i_array[4] = {100, 100, 100, 100};
int o_array[4];
// OK: performs conversions when needed
// 1. creates โaccโ of type char (the value type)
// 2. โaccโ is assigned to the first element of โo_arrayโ
// 3. the char arguments are used for long multiplication (char -> long)
// 4. the long product is assigned to the output range (long -> int)
// 5. the next value of โi_arrayโ is assigned to โaccโ
// 6. go back to step 3 to process the remaining elements in the input range
std::adjacent_difference(i_array, i_array + 4, o_array, std::multiplies<long>{});
๐ Example ๐
#include <array>
#include <functional>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
void println(auto comment, const auto& sequence)
{
std::cout << comment;
for (const auto& n : sequence)
std::cout << n << ' ';
std::cout << '\n';
};
int main()
{
// Default implementation - the difference between two adjacent items
std::vector v{4, 6, 9, 13, 18, 19, 19, 15, 10};
println("Initially, v = ", v);
std::adjacent_difference(v.begin(), v.end(), v.begin());
println("Modified v = ", v);
// Fibonacci
std::array<int, 10> a {1};
std::adjacent_difference(std::begin(a), std::prev(std::end(a)),
std::next(std::begin(a)), std::plus<>{});
println("Fibonacci, a = ", a);
}
๐ธ Output ๐ธ
Initially, v = 4 6 9 13 18 19 19 15 10
Modified v = 4 2 3 4 5 1 0 -4 -5
Fibonacci, a = 1 1 2 3 5 8 13 21 34 55
๐ง Defect reports ๐ง
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
LWG 242โ Applied to:C++98. Behavior as published:opcould not have side effects. Correct behavior: it cannot modify the ranges involved.LWG 539โ Applied to:C++98. Behavior as published: the type requirements needed for the result evaluations and assignments to be valid were missing. Correct behavior: added.LWG 2055(P0616R0) โ Applied to:C++11. Behavior as published:accwas not moved while being accumulated. Correct behavior: it is moved.LWG 3058โ Applied to:C++17. Behavior as published: for overloads (2,4), the result of each invocation ofoperator-oropwas assigned to a temporary object, and that object is assigned to the output range. Correct behavior: assign the results to the output range directly.
โจ See also โจ
okay bestie, if adjacent_difference was your gateway drug, here's the rest of the friend group ๐
partial_sumโ computes the partial sum of a range of elements (function template). it's giving "running total main character energy" ๐งฎโจaccumulateโ sums up or folds a range of elements (function template). like, it just takes everything in and folds it into one gorgeous value ๐ซถ
ngl, these two are the ones you'll keep reaching for when adjacent_difference has done its little transformation moment. same header, same family, same slay ๐
and that's a wrap on this page, bestie!! ๐ you made it to the end and honestly? obsessed with your commitment. go forth and difference some adjacents ๐
source: http://cppreference.com ยท version/date: 2024.06.10 ยท the page footer, but make it cute ๐ฆ
๐ฆ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 ยท MIT
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms