std::adjacent_difference
| Definiert in Header <numeric>
|
||
template< class InputIt, class OutputIt >
OutputIt adjacent_difference( InputIt first, InputIt last,
OutputIt d_first );
|
(1) | (constexpr seit C++20) |
template< class ExecutionPolicy,
class ForwardIt1, class ForwardIt2 >
ForwardIt2 adjacent_difference( ExecutionPolicy&& policy,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 d_first );
|
(2) | (seit C++17) |
template< class InputIt, class OutputIt, class BinaryOp >
OutputIt adjacent_difference( InputIt first, InputIt last,
OutputIt d_first, BinaryOp op );
|
(3) | (constexpr seit C++20) |
template< class ExecutionPolicy,
class ForwardIt1, class ForwardIt2, class BinaryOp >
ForwardIt2 adjacent_difference( ExecutionPolicy&& policy,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 d_first, BinaryOp op );
|
(4) | (seit C++17) |
Sei T der Werttyp von decltype(first).
[first, last) leer ist, tut es nichts.- Erzeugt einen Akkumulator
accvom TypTund initialisiert ihn mit*first. - Weist
accan*d_firstzu. - Für jeden Iterator
iterin[++first,last)der Reihe nach führt es die folgenden Operationen aus:
val vom Typ T und initialisiert es mit *iter.val - acc(bis C++20)val - std::move(acc)(seit C++20).*++d_first zu.val nach acc zu.[first, last) leer ist, tut es nichts.- Weist
*firstan*d_firstzu. - Für jede ganze Zahl
iin[1,std::distance(first, last))führt es der Reihe nach die folgenden Operationen aus:
curr - prev, wobei curr der nächste ite Iterator von first ist und prev der nächste i - 1te Iterator von first ist.*dest zu, wobei dest der nächste ite Iterator von d_first ist.op(val, acc)(bis C++20)op(val, std::move(acc))(seit C++20) stattdessen.op(curr, prev) stattdessen.Gegeben binary_op als die tatsächliche binäre Operation:
- Wenn eine der folgenden Bedingungen erfüllt ist, ist das Programm fehlerhaft:
- Für Überladungen (1,3):
Tist nicht aus*firstkonstruierbar.accist nicht beschreibbar nachd_first.- Das Ergebnis von
binary_op(val, acc)(bis C++20)binary_op(val, std::move(acc))(seit C++20) ist nicht beschreibbar nachd_first.
- Für Überladungen (2,4):
*firstist nicht beschreibbar nachd_first.- Das Ergebnis von
binary_op(*first, *first)ist nicht beschreibbar nachd_first.
- Gegeben
d_lastals der zurückzugebende Iterator, ist das Verhalten undefiniert, wenn eine der folgenden Bedingungen erfüllt ist:
|
(seit C++20) |
- Für Überladungen (2,4) überschneiden sich
[first,last)und[d_first,d_last). binary_opverändert jedes Element von[first,last)oder[d_first,d_last).binary_opmacht jeden Iterator oder Teilbereich in[first,last]oder[d_first,d_last]ungültig.
- Für Überladungen (2,4) überschneiden sich
Parameter
| first, last | - | das Paar von Iteratoren, das den Bereich der zu bearbeitenden Elemente definiert |
| d_first | - | der Anfang des Zielbereichs |
| policy | - | die Ausführungsstrategie, die verwendet werden soll |
| op | - | binäres Operationsfunktionsobjekt, das angewendet wird. Die Signatur der Funktion sollte wie folgt lauten:
Die Signatur muss kein |
| Typanforderungen | ||
-InputIt muss die Anforderungen von LegacyInputIterator erfüllen.
| ||
-OutputIt muss die Anforderungen von LegacyOutputIterator erfüllen.
| ||
-ForwardIt1, ForwardIt2 muss die Anforderungen von LegacyForwardIterator erfüllen.
| ||
Rückgabewert
Iterator auf das Element hinter dem letzten geschriebenen Element, oder d_first, wenn [first, last) leer ist.
Komplexität
Gegeben N als std::distance(first, last):
operator-.op.Ausnahmen
Die Überladungen mit einem Vorlagenparameter namens ExecutionPolicy melden Fehler wie folgt:
- Wenn die Ausführung einer im Rahmen des Algorithmus aufgerufenen Funktion eine Ausnahme auslöst und
ExecutionPolicyeine der Standardstrategien ist, wird std::terminate aufgerufen. Für jedes andereExecutionPolicyist das Verhalten implementationsdefiniert. - Wenn der Algorithmus keinen Speicher zuweisen kann, wird std::bad_alloc ausgelöst.
Mögliche Implementierung
| 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;
}
|
Anmerkungen
acc wurde aufgrund der Auflösung von LWG-Issue 539 eingeführt. Der Grund für die Verwendung von acc anstatt der direkten Berechnung der Differenzen ist, dass die Semantik der letzteren verwirrend ist, wenn die folgenden Typen nicht übereinstimmen:
- der Werttyp von
InputIt - die beschreibbaren Typen von
OutputIt - die Typen der Parameter von
operator-oderop - der Rückgabetyp von
operator-oderop
acc dient als Zwischenobjekt zum Zwischenspeichern von Werten der iterierten Elemente:
- sein Typ ist der Werttyp von
InputIt - der in
d_firstgeschriebene Wert (der Rückgabewert vonoperator-oderop) wird ihm zugewiesen - sein Wert wird an
operator-oderop
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>{});
übergeben
#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);
}
Dieses Programm ausführen
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
Ausgabe:
Fehlerberichte
| Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet. | DR | Angewendet auf | Verhalten wie veröffentlicht |
|---|---|---|---|
| Richtiges Verhalten | LWG 242 | opC++98
|
konnte keine Nebenwirkungen haben
es kann keine |
| der beteiligten Bereiche ändern | LWG 539 | C++98
die für das Ergebnis benötigten Typanforderungen |
Auswertungen und Zuweisungen gültig zu sein, fehlten |
| hinzugefügt | LWG 3058 | C++17
für Überladungen (2,4) wurde das Ergebnis jedes Aufrufs operator-von op oder einem temporären |
Objekt zugewiesen, und dieses Objekt wird dem Ausgabebereich zugewiesen
die Ergebnisse direkt dem Ausgabebereich zuweisen |
Siehe auch
| berechnet die Partialsumme eines Bereichs von Elementen (Funktionstemplate) | |
| summiert oder faltet einen Bereich von Elementen (Funktionstemplate) |