std::adjacent_difference
Определено в заголовке <numeric> | ||
|---|---|---|
| (1) | ||
template< class InputIt, class OutputIt > OutputIt adjacent_difference( InputIt first, InputIt last, OutputIt d_first ); | (до C++20) | |
template< class InputIt, class OutputIt >
constexpr OutputIt adjacent_difference( InputIt first, InputIt last,
OutputIt d_first );
| (с C++20) | |
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >
ForwardIt2 adjacent_difference( ExecutionPolicy&& policy,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 d_first );
| (2) | (с C++17) |
| (3) | ||
template< class InputIt, class OutputIt, class BinaryOperation >
OutputIt adjacent_difference( InputIt first, InputIt last,
OutputIt d_first, BinaryOperation op ); | (до C++20) | |
template< class InputIt, class OutputIt, class BinaryOperation >
constexpr OutputIt adjacent_difference( InputIt first, InputIt last,
OutputIt d_first,
BinaryOperation op );
| (с C++20) | |
template< class ExecutionPolicy,
class ForwardIt1, class ForwardIt2, class BinaryOperation >
ForwardIt2 adjacent_difference( ExecutionPolicy&& policy,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 d_first, BinaryOperation op );
| (4) | (с C++17) |
Если [first, last) не пусто, вычисляет разницу между вторым и первым элементом каждой смежной пары элементов и записывает разницу в диапазон, начинающийся в d_first + 1. Неизменная копия *first записывается в *d_first. Перегрузки (1,2) используют оператор- для вычисления разностей, перегрузки (3,4) используют заданную бинарную функцию op, применяя std::move к своим операндам справа(с C++11).
Эквивалентная операция для перегрузки (1), если [first, last) не пусто, использует накопитель acc для хранения значения, которое нужно вычесть:
std::iterator_traits<InputIt>::value_type acc = *first; *d_first = acc; std::iterator_traits<InputIt>::value_type val1 = *(first + 1); *(d_first + 1) = val1 - std::move(acc); // or *(d_first + 1) = op(val1, std::move(acc)); for overload (2) acc = std::move(val1); std::iterator_traits<InputIt>::value_type val2 = *(first + 2); *(d_first + 2) = val2 - std::move(acc); acc = std::move(val2); std::iterator_traits<InputIt>::value_type val3 = *(first + 3); *(d_first + 3) = val3 - std::move(acc); acc = std::move(val3); // ...
Эквивалентная операция для перегрузки (3), если [first, last) не пусто:
// performed first *d_first = *first; // performed after the initial assignment, might not be sequenced *(d_first + 1) = *(first + 1) - *(first); // or *(d_first + 1) = op(*(first + 1), *(first)); for overload (4) *(d_first + 2) = *(first + 2) - *(first + 1); *(d_first + 3) = *(first + 3) - *(first + 2); ...
Если op делает недействительными какие-либо итераторы (включая любые конечные итераторы) или изменяет любые элементы вовлечённых диапазонов, поведение не определено.
Для перегрузок (1,3), если std::iterator_traits<InputIt>::value_type не является копируемым(до C++11)перемещаемым(с C++11), поведение не определено.
Параметры
| first, last | - | диапазон элементов |
| d_first | - | начало целевого диапазона |
| policy | - | политика выполнения. См. политику выполнения для подробностей. |
| op | - | бинарный функциональный объект, который будет применяться. Подпись функции должна быть эквивалентна следующей:
Подпись не должна содержать |
| Требования к типу | ||
-InputIt должно соответствовать требованиям LegacyInputIterator. Для перегрузок (1,3) его тип значения должен быть создаваемым из *first. |
||
-OutputIt должно соответствовать требованиям LegacyOutputIterator. acc (определённый выше) и результат val - acc (для (1)) или op(val, acc) (для (3))(до C++11)val - std::move(acc) (для (1)) или op(val, std::move(acc)) (для (3))(с C++11) должны быть записываемыми в d_first. |
||
-ForwardIt1, ForwardIt2 должно соответствовать требованиям LegacyForwardIterator. Результат *first и результат *first - *first (для (2)) или op(*first, *first) (для (4)) должны быть записываемыми в d_first. |
||
Возвращаемое значение
Итератор на элемент после последнего записанного элемента, или d_first если [first, last) пусто.
Сложность
Учитывая N как std::distance(first, last) - 1:
N применений operator-
N применений бинарной функции op
Исключение
Перегрузки с шаблоным параметром с именем ExecutionPolicy сообщают об ошибках следующим образом:
- Если выполнение функции, вызванной как часть алгоритма, вызывает исключение и
ExecutionPolicyявляется одной из стандартных политик, вызываетсяstd::terminate. Для любой другойExecutionPolicy, поведение не определено. - Если алгоритм не может выделить память, выбрасывается
std::bad_alloc.
Возможная реализация
| 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 BinaryOperation>
constexpr // since C++20
OutputIt adjacent_difference(InputIt first, InputIt last,
OutputIt d_first, BinaryOperation 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;
} |
Примечания
acc была введена из-за разрешения LWG issue 539. Причина использования acc вместо непосредственного вычисления разностей заключается в том, что семантика последнего может быть неясной при несовпадении типов:
- тип значения
InputIt - тип(ы) записи
OutputIt - типы параметров оператора- или
op - тип возвращаемого значения оператора- или
op
acc служит промежуточным объектом для кэширования значений итерируемых элементов:
- его тип — тип значения
InputIt - значение, записанное в
d_first(которое является результатом оператора- илиop) присваивается ему - его значение передаётся в оператор- или
op
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>{});Пример
#include <array>
#include <functional>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
auto print = [](auto comment, auto const& sequence)
{
std::cout << comment;
for (const auto& n : sequence)
std::cout << n << ' ';
std::cout << '\n';
};
int main()
{
// Default implementation - the difference b/w two adjacent items
std::vector v {4, 6, 9, 13, 18, 19, 19, 15, 10};
print("Initially, v = ", v);
std::adjacent_difference(v.begin(), v.end(), v.begin());
print("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<>{});
print("Fibonacci, a = ", a);
}Вывод:
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
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применён к | Поведение, как опубликовано | Правильное поведение |
|---|---|---|---|
| LWG 242 | C++98 |
op не мог иметь побочных эффектов | он не может изменять вовлечённые диапазоны |
| LWG 539 | C++98 | требования к типу для результатов вычислений и присваиваний отсутствовали | добавлены |
|
LWG 2055 (P0616R0) | C++11 |
acc не перемещался во время накопления | он перемещается |
| LWG 3058 | C++17 | для перегрузок (2,4) результат каждого вызова оператора- или op присваивался временнойпеременной, а эта переменная присваивалась выходному диапазону | присваивать результаты непосредственно выходному диапазону |
См. также
| вычисляет частичную сумму диапазона элементов (шаблон функции) |
|
| суммирует или складывает по определённому правилу диапазон элементов (шаблон функции) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/algorithm/adjacent_difference