Namespaces
Variants

std::adjacent_difference

Von de.cppreference.net
 
 
Algorithmenbibliothek
Eingeschränkte Algorithmen und Algorithmen auf Bereichen (C++20)
Eingeschränkte Algorithmen, z. B. ranges::copy, ranges::sort, ...
Nicht modifizierende Sequenzoperationen    
Stapeloperationen
(C++17)
Suchoperationen
Modifizierende Sequenzoperationen
Kopieroperationen
(C++11)
(C++11)
Tauschoperationen
Transformationsoperationen
Erzeugungsoperationen
Entfernungsoperationen
Reihenfolgeändernde Operationen
(bis C++17)(C++11)
(C++20)(C++20)
Stichprobenoperationen
(C++17)

Sortier- und verwandte Operationen
Partitionierungsoperationen
(C++11)    

Sortieroperationen
Binäre Suchoperationen
(auf partitionierten Bereichen)
Mengenoperationen (auf sortierten Bereichen)
Mischoperationen (auf sortierten Bereichen)
Heap-Operationen
Minimum/Maximum-Operationen
(C++11)
(C++17)
Lexikografische Vergleichsoperationen
Permutationsoperationen


 
 
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).

1) Wenn [first, last) leer ist, tut es nichts.
Andernfalls führt es der Reihe nach die folgenden Operationen aus:
  1. Erzeugt einen Akkumulator acc vom Typ T und initialisiert ihn mit *first.
  2. Weist acc an *d_first zu.
  3. Für jeden Iterator iter in [++first, last) der Reihe nach führt es die folgenden Operationen aus:
a) Erzeugt ein Objekt val vom Typ T und initialisiert es mit *iter.
b) Berechnet val - acc(bis C++20)val - std::move(acc)(seit C++20).
c) Weist das Ergebnis an *++d_first zu.
d) Kopiert(bis C++20)Verschiebt(seit C++20) von val nach acc zu.
2) Wenn [first, last) leer ist, tut es nichts.
Andernfalls führt es der Reihe nach die folgenden Operationen aus:
  1. Weist *first an *d_first zu.
  2. Für jede ganze Zahl i in [1, std::distance(first, last)) führt es der Reihe nach die folgenden Operationen aus:
a) Berechnet curr - prev, wobei curr der nächste ite Iterator von first ist und prev der nächste i - 1te Iterator von first ist.
b) Weist das Ergebnis an *dest zu, wobei dest der nächste ite Iterator von d_first ist.
3) Gleich wie (1), berechnet aber op(val, acc)(bis C++20)op(val, std::move(acc))(seit C++20) stattdessen.
4) Gleich wie (2), berechnet aber 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):
  • T ist nicht aus *first konstruierbar.
  • acc ist nicht beschreibbar nach d_first.
  • Das Ergebnis von binary_op(val, acc)(bis C++20)binary_op(val, std::move(acc))(seit C++20) ist nicht beschreibbar nach d_first.
  • Für Überladungen (2,4):
  • *first ist nicht beschreibbar nach d_first.
  • Das Ergebnis von binary_op(*first, *first) ist nicht beschreibbar nach d_first.
  • Gegeben d_last als 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_op verändert jedes Element von [first, last) oder [d_first, d_last).
  • binary_op macht jeden Iterator oder Teilbereich in [first, last] oder [d_first, d_last] ungültig.

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:

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

Die Signatur muss kein const & enthalten.
Die Typen Type1 und Type2 müssen so sein, dass ein Objekt vom Typ iterator_traits<InputIt>::value_type implizit in beide konvertiert werden kann. Der Typ Ret muss so sein, dass ein Objekt vom Typ OutputIt dereferenziert und ihm ein Wert vom Typ Ret zugewiesen werden kann. ​

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):

1,2) Genau N-1 Anwendungen von operator-.
3,4) Genau N-1 Anwendungen der binären Funktion 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 ExecutionPolicy eine der Standardstrategien ist, wird std::terminate aufgerufen. Für jedes andere ExecutionPolicy ist 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- oder op
  • der Rückgabetyp von operator- oder op

acc dient als Zwischenobjekt zum Zwischenspeichern von Werten der iterierten Elemente:

  • sein Typ ist der Werttyp von InputIt
  • der in d_first geschriebene Wert (der Rückgabewert von operator- oder op) wird ihm zugewiesen
  • sein Wert wird an operator- oder 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>{});

ü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 Aufrufsoperator-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)