std::adjacent_difference
定义于头文件 <numeric> |
||
template< class InputIt, class OutputIt > OutputIt adjacent_difference( InputIt first, InputIt last, |
(1) | (constexpr since C++20) |
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 > |
(2) | (since C++17) |
template< class InputIt, class OutputIt, class BinaryOp > OutputIt adjacent_difference( InputIt first, InputIt last, |
(3) | (constexpr since C++20) |
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class BinaryOp > |
(4) | (since C++17) |
设 T
为 decltype(first) 的值类型。
[
first,
last)
为空,则不执行任何操作。- 创建一个类型为
T
的累加器 acc,并用 *first 初始化它。 - 将 acc 赋值给 *d_first。
- 对于
[
++first,
last)
中按顺序的每个迭代器 iter,按顺序执行以下操作
T
的对象 val,并用 *iter 初始化它。[
first,
last)
为空,则不执行任何操作。- 将 *first 赋值给 *d_first。
- 对于
[
1,
std::distance(first, last))
中的每个整数 i,按顺序执行以下操作
给定 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]
中的任何迭代器或子范围无效。
- 对于重载 (2,4),
目录 |
[编辑] 参数
first, last | - | 定义要操作的元素范围的迭代器对 |
d_first | - | 目标范围的起始迭代器 |
policy | - | 要使用的执行策略 |
op | - | 将被应用的二元运算函数对象。 函数的签名应等效于以下形式 Ret fun(const Type1 &a, const Type2 &b); 签名不需要具有 const &。 |
类型要求 | ||
-InputIt 必须满足 LegacyInputIterator 的要求。 | ||
-OutputIt 必须满足 LegacyOutputIterator 的要求。 | ||
-ForwardIt1, ForwardIt2 必须满足 LegacyForwardIterator 的要求。 |
[编辑] 返回值
指向写入的最后一个元素之后的位置的迭代器,如果 [
first,
last)
为空,则返回 d_first。
[编辑] 复杂度
给定 N 为 std::distance(first, last)
[编辑] 异常
带有名为 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 issue 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 被赋值给一个临时 对象,该对象被赋值给输出范围 |
直接赋值结果 到输出 范围 |
[编辑] 参见
计算元素范围的部分和 (函数模板) | |
对元素范围求和或折叠 (函数模板) |