std::adjacent_difference
Определён в заголовочном файле <numeric> | ||
|---|---|---|
template< class InputIt, class OutputIt >
OutputIt adjacent_difference( InputIt first, InputIt last,
OutputIt d_first );
| (1) | (constexpr начиная с C++20) |
template< class ExecutionPolicy,
class ForwardIt1, class ForwardIt2 >
ForwardIt2 adjacent_difference( ExecutionPolicy&& policy,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 d_first );
| (2) | (начиная с C++17) |
template< class InputIt, class OutputIt, class BinaryOp >
OutputIt adjacent_difference( InputIt first, InputIt last,
OutputIt d_first, BinaryOp op );
| (3) | (constexpr начиная с C++20) |
template< class ExecutionPolicy,
class ForwardIt1, class ForwardIt2, class BinaryOp >
ForwardIt2 adjacent_difference( ExecutionPolicy&& policy,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 d_first, BinaryOp op );
| (4) | (начиная с C++17) |
Пусть T — это тип значения decltype(first).
[first, last) пуст, ничего не делает.- Создаёт аккумулятор
accтипаTи инициализирует его значением*first. - Присваивает
accзначение*d_first. - Для каждого итератора
iterв[++first,last)по порядку выполняет следующие действия по порядку:
val типа T и инициализирует его значением *iter.val - acc(до C++20)val - std::move(acc)(начиная с C++20).*++d_first.val в acc.[first, last) пуст, ничего не делает.- Присваивает
*firstзначение*d_first. - Для каждого целого числа
iв[1,std::distance(first, last))по порядку выполняет следующие действия по порядку:
curr - prev, где curr — следующий iй итератор first, а prev — следующий i - 1й итератор first.*dest, где dest — следующий iй итератор d_first.op(val, acc)(до C++20)op(val, std::move(acc))(начиная с C++20).op(curr, prev).Пусть binary_op — фактически используемая бинарная операция:
- Если выполняется любое из следующих условий, программа некорректна:
- Для перегрузок (1,3):
-
Tне может быть сконструирован из*first. -
accнельзя записать вd_first. - Результат
binary_op(val, acc)(до C++20)binary_op(val, std::move(acc))(начиная с C++20) нельзя записать вd_first. - Для перегрузок (2,4):
-
*firstнельзя записать вd_first. - Результат
binary_op(*first, *first)нельзя записать вd_first. - Пусть
d_last— итератор, который будет возвращён. Если выполняется любое из следующих условий, поведение не определено:
| (начиная с C++20) |
- Для перегрузок (2,4)
[first,last)и[d_first,d_last)пересекаются. -
binary_opизменяет любой элемент[first,last)или[d_first,d_last). -
binary_opделает недействительным любой итератор или поддиапазон в[first,last]или[d_first,d_last].
Параметры
| first, last | - | пара итераторов, задающая диапазон элементов |
| d_first | - | начало диапазона назначения |
| policy | - | используемая политика выполнения |
| op | - | объект-функция бинарной операции, которая будет применяться. Сигнатура функции должна быть эквивалентна следующей: Retfun(constType1&a,constType2&b); Сигнатура не обязана содержать |
| Требования к типам | ||
-InputIt должен удовлетворять требованиям LegacyInputIterator. |
||
-OutputIt должен удовлетворять требованиям LegacyOutputIterator. |
||
-ForwardIt1, ForwardIt2 должен удовлетворять требованиям LegacyForwardIterator. |
||
Возвращаемое значение
Итератор на элемент после последнего записанного элемента или d_first, если [first, last) пуст.
Сложность
Пусть \(\scriptsize N\)N — это std::distance(first, last):
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++20
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++20
acc = std::move(val);
}
return ++d_first;
}
|
Примечания
acc был введён в результате принятия решения по вопросу LWG 539. Причина использования acc вместо непосредственного вычисления разностей заключается в том, что семантика последнего становится неоднозначной, если не совпадают следующие типы:
- тип значения
InputIt - тип или типы, доступные для записи, у
OutputIt - типы параметров operator- или
op - возвращаемый тип operator- или
op
acc служит промежуточным объектом для сохранения значений обрабатываемых элементов:
- его тип — тип значения
InputIt - ему присваивается значение, записанное в
d_first(то есть возвращаемое значение operator- илиop) - его значение передаётся в operator- или
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>
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);
}
Вывод:
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 3058 | C++17 | для перегрузок (2,4) результат каждого вызова operator- или op присваивался временномуобъекту, а затем этот объект присваивался выходному диапазону | присваивать результаты непосредственно выходному диапазону |
См. также
| вычисляет частичную сумму диапазона элементов (шаблон функции) |
|
| вычисляет сумму или свёртку диапазона элементов (шаблон функции) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/algorithm/adjacent_difference