std::adjacent_difference
| 定义于头文件 <numeric>
|
||
template< class InputIt, class OutputIt >
OutputIt adjacent_difference( InputIt first, InputIt last,
OutputIt d_first );
|
(1) | (C++20 起为 constexpr) |
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) | (C++20 起为 constexpr) |
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]中的任何迭代器或子范围失效。
- 对于重载 (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 。
可能的实现
| 相邻差分 (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; } |
| 相邻差分 (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]; // 正确:在需要时执行类型转换 // 1. 创建 char 类型的“acc”(值类型) // 2. 将“acc”赋值给“o_array”的第一个元素 // 3. char 参数用于 long 类型乘法运算(char → long) // 4. long 类型的乘积被赋值给输出范围(long → int) // 5. 将“i_array”的下一个值赋值给“acc” // 6. 返回步骤3处理输入范围内的剩余元素 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() { // 默认实现 - 计算相邻元素的差值 std::vector v{4, 6, 9, 13, 18, 19, 19, 15, 10}; println("初始状态, v = ", v); std::adjacent_difference(v.begin(), v.end(), v.begin()); println("修改后 v = ", v); // 斐波那契数列生成 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("斐波那契数列, a = ", a); }
输出:
初始状态, v = 4 6 9 13 18 19 19 15 10 修改后 v = 4 2 3 4 5 1 0 -4 -5 斐波那契数列, a = 1 1 2 3 5 8 13 21 34 55
缺陷报告
下列行为变更缺陷报告被追溯应用于先前发布的 C++ 标准。
| 缺陷报告 | 适用标准 | 发布行为 | 正确行为 |
|---|---|---|---|
| LWG 242 | C++98 | op 不允许有副作用 |
不能修改
所涉及的区间 |
| LWG 539 | C++98 |
缺少确保结果求值
和赋值有效的类型要求 |
已添加 |
| LWG 3058 | C++17 |
对于重载
(2,4)
,每次调用
operator - 或 op 的结果被赋值给临时 对象,再将该对象赋值给输出区间 |
直接将结果
赋值给输出 区间 |
参见
|
计算范围内元素的部分和
(函数模板) |
|
|
对范围内元素进行求和或折叠操作
(函数模板) |