std:: adjacent_difference
|
定义于头文件
<numeric>
|
||
|
template
<
class
InputIt,
class
OutputIt
>
OutputIt adjacent_difference
(
InputIt first, InputIt last,
|
(1) | (自 C++20 起为 constexpr) |
|
template
<
class
ExecutionPolicy,
class
ForwardIt1,
class
ForwardIt2
>
|
(2) | (自 C++17 起) |
|
template
<
class
InputIt,
class
OutputIt,
class
BinaryOp
>
OutputIt adjacent_difference
(
InputIt first, InputIt last,
|
(3) | (自 C++20 起为 constexpr) |
|
template
<
class
ExecutionPolicy,
class
ForwardIt1,
class
ForwardIt2,
class
BinaryOp
>
|
(4) | (自 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 作为待 返回 的迭代器,若满足以下任一条件,则行为未定义:
|
(since 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 的结果被赋值给临时 对象,再将该对象赋值给输出区间 |
直接将结果
赋值给输出 区间 |
参见
|
计算范围内元素的部分和
(函数模板) |
|
|
对范围内元素进行求和或折叠操作
(函数模板) |