命名空间
变体
操作

std::adjacent_difference

来自 cppreference.com
< cpp‎ | algorithm
 
 
算法库
约束算法和范围上的算法 (C++20)
约束算法,例如 ranges::copy, ranges::sort, ...
执行策略 (C++17)
排序和相关操作
分区操作
排序操作
二分搜索操作
(在已分区范围上)
集合操作(在已排序范围上)
合并操作(在已排序范围上)
堆操作
最小/最大操作
(C++11)
(C++17)
字典序比较操作
排列操作
C 库
数值操作
(C++11)
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 开始)

Tdecltype(first) 的值类型。

1) 如果 [firstlast) 为空,则不执行任何操作。
否则,按顺序执行以下操作
  1. 创建一个类型为 T 的累加器 acc,并用 *first 初始化它。
  2. acc 赋值给 *d_first
  3. 对于 [++firstlast) 中的每个迭代器 iter,按顺序执行以下操作
a) 创建一个类型为 T 的对象 val,并用 *iter 初始化它。
b) 计算 val - acc(直到 C++20)val - std::move(acc)(从 C++20 开始).
c) 将结果赋值给 *++d_first
d) 复制(直到 C++20)移动(从 C++20 开始)val 赋值给 acc
2) 如果 [firstlast) 为空,则不执行任何操作。
否则,按顺序执行以下操作
  1. *first 赋值给 *d_first
  2. 对于 [1std::distance(first, last)) 中的每个整数 i,按顺序执行以下操作
a) 计算 curr - prev,其中 currfirst 的下一个 i
th
迭代器,prevfirst 的下一个 i - 1
th
迭代器。
b) 将结果赋值给 *dest,其中 destd_first 的下一个 i
th
迭代器。
3)(1) 相同,但计算 op(val, acc)(直到 C++20)op(val, std::move(acc))(自 C++20 起)
4)(2) 相同,但计算 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)[firstlast)[d_firstd_last) 重叠。
  • binary_op 修改 [firstlast)[d_firstd_last) 中的任何元素。
  • binary_op 使 [firstlast][d_firstd_last] 中的任何迭代器或子范围失效。

内容

[edit] 参数

first, last - 元素范围
d_first - 目标范围的开始
policy - 要使用的执行策略。有关详细信息,请参见 执行策略
op - 要应用的二元运算函数对象。

函数的签名应等效于以下内容

 Ret fun(const Type1 &a, const Type2 &b);

签名不需要具有 const &
类型  Type1 Type2 必须是,使得类型 iterator_traits<InputIt>::value_type 的对象可以隐式转换为它们两者。类型 Ret 必须是,使得类型 OutputIt 可以解引用并赋值为类型 Ret 的值。​

类型要求
-
InputIt 必须满足 LegacyInputIterator 的要求。
-
OutputIt 必须满足 LegacyOutputIterator 的要求。
-
ForwardIt1, ForwardIt2 必须满足 LegacyForwardIterator 的要求。

[edit] 返回值

指向写入的最后一个元素之后的元素的迭代器,如果 [firstlast) 为空,则返回 d_first

[edit] 复杂度

给定 N 作为 std::distance(first, last)

1,2) 恰好 N-1 次应用 operator-
3,4) 恰好 N-1 次应用二元函数 op

[edit] 异常

具有名为 ExecutionPolicy 的模板参数的重载报告错误如下

  • 如果作为算法的一部分调用的函数的执行抛出异常,并且 ExecutionPolicy标准策略 之一,则调用 std::terminate。对于任何其他 ExecutionPolicy,行为是实现定义的。
  • 如果算法无法分配内存,则抛出 std::bad_alloc

[edit] 可能的实现

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;
}

[edit] 注意

引入 acc 是因为解决了 LWG 问题 539。使用 acc 而不是直接计算差值的原因是,如果以下类型不匹配,则后者的语义会让人困惑

  • InputIt 的值类型
  • OutputIt 的可写类型(s)
  • 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>{});

[edit] 示例

#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

[edit] 缺陷报告

以下行为更改缺陷报告已追溯应用于以前发布的 C++ 标准。

DR 应用于 发布的行为 正确行为
LWG 242 C++98 op 不能有副作用 它不能修改
所涉及的范围
LWG 539 C++98 结果所需的类型要求丢失
评估和赋值的有效性验证丢失
添加
LWG 3058 C++17 对于重载 (2,4),每次调用
operator-op 的结果被赋值给一个临时
对象,该对象被赋值给输出范围
将结果
直接分配给输出
范围

[编辑] 另请参阅

计算一系列元素的偏和
(函数模板) [编辑]
对一系列元素进行求和或折叠
(函数模板) [编辑]