Namespaces
Variants

std:: adjacent_difference

From cppreference.net
Algorithm library
Constrained algorithms and algorithms on ranges (C++20)
Constrained algorithms, e.g. ranges::copy , ranges::sort , ...
Execution policies (C++17)
Non-modifying sequence operations
Batch operations
(C++17)
Search operations
Modifying sequence operations
Copy operations
(C++11)
(C++11)
Swap operations
Transformation operations
Generation operations
Removing operations
Order-changing operations
(until C++17) (C++11)
(C++20) (C++20)
Sampling operations
(C++17)

Sorting and related operations
Partitioning operations
Sorting operations
Binary search operations
(on partitioned ranges)
Set operations (on sorted ranges)
Merge operations (on sorted ranges)
Heap operations
Minimum/maximum operations
Lexicographical comparison operations
Permutation operations
C library
Numeric operations
(C++11)
adjacent_difference
Operations on uninitialized memory
定义于头文件 <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 ) 的值类型。

1) [ first , last ) 为空范围,则不执行任何操作。
否则,按顺序执行以下操作:
  1. 创建类型为 T 的累加器 acc ,并用 * first 初始化。
  2. acc 赋值给 * d_first
  3. 对于按顺序位于 [ ++ first , last ) 范围内的每个迭代器 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) [ first , last ) 为空区间,则不执行任何操作。
否则,按顺序执行以下操作:
  1. * first 赋值给 * d_first
  2. 对于区间 [ 1 , std:: distance ( first, last ) ) 内的每个整数 i ,按顺序执行以下操作:
a) 计算 curr - prev ,其中 curr first 的第 i 迭代器, prev first 的第 i - 1 迭代器。
b) 将结果赋值给 * dest ,其中 dest d_first 的第 i 迭代器。
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 作为待 返回 的迭代器,若满足以下任一条件,则行为未定义:
(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 ] 中的任何迭代器或子区间失效。

目录

参数

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 的要求。

返回值

指向最后被写入元素之后位置的迭代器,若 [ first , last ) 为空范围则返回 d_first

复杂度

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

1,2) 恰好需要 N-1 operator - 运算符的应用。
3,4) 恰好执行 N-1 次二元函数 op 的调用。

异常

带有名为 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 的结果被赋值给临时
对象,再将该对象赋值给输出区间
直接将结果
赋值给输出
区间

参见

计算范围内元素的部分和
(函数模板)
对范围内元素进行求和或折叠操作
(函数模板)