std::adjacent_difference
ja.cppreference.net より
| ヘッダ <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) が空なら、何もしない。 そうでなければ、以下の操作を順に実行する。
- 型
accのアキュムレータTを作成し、*firstで初期化する。 accを*d_firstに代入する。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) が空なら、何もしない。 そうでなければ、以下の操作を順に実行する。
*firstを*d_firstに代入する。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を 返されるイテレータとしたとき、以下の条件のいずれかが満たされる場合、動作は未定義である:
|
(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 | - | 適用される二項演算関数オブジェクト。 関数のシグネチャは以下と同等であるべき:
シグネチャに |
| 型要件 | ||
-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 の結果が一時オブジェクトに代入され、そのオブジェクトが出力レンジに代入されていた |
結果を直接 出力レンジに 代入する |
関連項目
| 要素の範囲の部分和を計算する (関数テンプレート) | |
| 要素の範囲を合計または畳み込む (関数テンプレート) |