Namespaces
Variants

std::adjacent_difference

ja.cppreference.net より
 
 
アルゴリズムライブラリ
制約付きアルゴリズムとレンジのアルゴリズム (C++20)
制約付きアルゴリズム、例: ranges::copy、 ranges::sort、...
ソートおよび関連操作
分割操作
(C++11)    

ソート操作
二分探索操作
(分割されたレンジに対する)
集合操作 (ソート済みレンジに対する)
マージ操作 (ソート済みレンジに対する)
ヒープ操作
最小値/最大値操作
(C++11)
(C++17)
辞書順比較操作
順列操作


 
 
ヘッダ <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. 型 acc のアキュムレータ T を作成し、 *first で初期化する。
  2. acc を *d_first に代入する。
  3. iter 内の各イテレータ [++first, last) に対して順に、以下の操作を順に実行する:
a) 型 val のオブジェクト T を作成し、 *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. i 内の各整数 [1, std::distance(first, last)) に対して順に、以下の操作を順に実行する:
a) curr - prev を計算する。ここで curr は i 番目 の次の first のイテレータ、 prev は i - 1 番目 の次の first のイテレータである。
b) 結果を *dest に代入する。ここで dest は i 番目 の次の d_first のイテレータである。
3) (1) と同じだが、代わりに op(val, acc)(C++20 まで)op(val, std::move(acc))(C++20 から) を計算する。
4) (2) と同じだが、代わりに op(curr, prev) を計算する。

実際の二項演算を binary_op としたとき:

  • 以下の条件のいずれかが満たされる場合、プログラムは ill-formed である:
  • オーバーロード (1,3) について:
  • T*first から構築可能ではない。
  • accwritable が d_first に対して false である。
  • binary_op(val, acc)(C++20 まで)binary_op(val, std::move(acc))(C++20 から) の結果が d_first に対して writable ではない。
  • オーバーロード (2,4) について:
  • *firstd_first に対して writable ではない。
  • binary_op(*first, *first) の結果が d_first に対して writable ではない。
  • d_last を 返されるイテレータとしたとき、以下の条件のいずれかが満たされる場合、動作は未定義である:
  • オーバーロード (1,3) について、 T は MoveAssignable ではない。
(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 の要件を満たさなければならない。

戻り値

書き込まれた最後の要素の次の要素を指すイテレータ。 d_first が空の場合は [first, last)。

計算量

N を std::distance(first, last) として:

1,2) 正確に N-1 回の operator- の適用。
3,4) 正確に N-1 回の二項関数 op の適用。

例外

テンプレートパラメータ 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_firstoperator- または 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 opC++98
は副作用を持ってはならない
関与するレンジを変更できない LWG 539 C++98
結果の評価と代入が有効であるために必要な型要件が欠落していた
追加された
LWG 3058 C++17 オーバーロード (2,4) において、各呼び出し
の operator- または op の結果が一時
オブジェクトに代入され、そのオブジェクトが出力レンジに代入されていた
結果を直接
出力レンジに
代入する

関連項目

要素の範囲の部分和を計算する
(関数テンプレート)
要素の範囲を合計または畳み込む
(関数テンプレート)