Namespaces
Variants

std::adjacent_difference

De fr.cppreference.net
 
 
Bibliothèque d'algorithmes
Algorithmes contraints et algorithmes sur plages (C++20)
Algorithmes contraints, p. ex. ranges::copy, ranges::sort, ...
Opérations de séquence non modifiantes    
Opérations par lots
(C++17)
Opérations de recherche
Opérations de séquence modifiantes
Opérations de copie
(C++11)
(C++11)
Opérations d'échange
Opérations de transformation
Opérations de génération
Opérations de suppression
Opérations de changement d'ordre
(jusqu'à C++17)(C++11)
(C++20)(C++20)
Opérations d'échantillonnage
(C++17)

Opérations de tri et connexes
Opérations de partitionnement
(C++11)    

Opérations de tri
Opérations de recherche binaire
(sur plages partitionnées)
Opérations d'ensemble (sur plages triées)
Opérations de fusion (sur plages triées)
Opérations de tas
Opérations de minimum/maximum
(C++11)
(C++17)
Opérations de comparaison lexicographique
Opérations de permutation


 
 
Défini dans l'en-tête <numeric>
template< class InputIt, class OutputIt >
OutputIt adjacent_difference( InputIt first, InputIt last,
                              OutputIt d_first );
(1) (constexpr depuis C++20)
template< class ExecutionPolicy,
          class ForwardIt1, class ForwardIt2 >
ForwardIt2 adjacent_difference( ExecutionPolicy&& policy,
                                ForwardIt1 first, ForwardIt1 last,
                                ForwardIt2 d_first );
(2) (depuis C++17)
template< class InputIt, class OutputIt, class BinaryOp >
OutputIt adjacent_difference( InputIt first, InputIt last, 
                              OutputIt d_first, BinaryOp op );
(3) (constexpr depuis 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) (depuis C++17)

Soit T le type valeur de decltype(first).

1) Si [firstlast) est vide, ne fait rien.
Sinon, effectue les opérations suivantes dans l'ordre :
  1. Crée un accumulateur acc de type T, et l'initialise avec *first.
  2. Affecte acc à *d_first.
  3. Pour chaque itérateur iter dans [++firstlast) dans l'ordre, effectue les opérations suivantes dans l'ordre :
a) Crée un objet val de type T, et l'initialise avec *iter.
b) Calcule val - acc(jusqu'à C++20)val - std::move(acc)(depuis C++20).
c) Affecte le résultat à *++d_first.
d) Affecte par copie(jusqu'à C++20)Affecte par déplacement(depuis C++20) de val à acc.
2) Si [firstlast) est vide, ne fait rien.
Sinon, effectue les opérations suivantes dans l'ordre :
  1. Affecte *first à *d_first.
  2. Pour chaque entier i dans [1std::distance(first, last)), effectue les opérations suivantes dans l'ordre :
a) Calcule curr - prev, où curr est le ii-ème itérateur suivant de first, et prev est le i - 1i-ème itérateur suivant de first.
b) Affecte le résultat à *dest, où dest est le ii-ème itérateur suivant de d_first.
3) Identique à (1), mais calcule op(val, acc)(jusqu'à C++20)op(val, std::move(acc))(depuis C++20) à la place.
4) Identique à (2), mais calcule op(curr, prev) à la place.

Soit binary_op l'opération binaire réelle :

  • Si l'une des conditions suivantes est satisfaite, le programme est mal formé :
  • Pour les surcharges (1,3) :
  • T n'est pas constructible à partir de *first.
  • acc n'est pas inscriptible dans d_first.
  • Le résultat de binary_op(val, acc)(jusqu'à C++20)binary_op(val, std::move(acc))(depuis C++20) n'est pas inscriptible dans d_first.
  • Pour les surcharges (2,4) :
  • *first n'est pas inscriptible dans d_first.
  • Le résultat de binary_op(*first, *first) n'est pas inscriptible dans d_first.
  • Soit d_last l'itérateur à retourner, si l'une des conditions suivantes est satisfaite, le comportement est indéfini :
(depuis C++20)
  • Pour les surcharges (2,4), [firstlast) et [d_firstd_last) se chevauchent.
  • binary_op modifie tout élément de [firstlast) ou [d_firstd_last).
  • binary_op invalide tout itérateur ou sous-plage dans [firstlast] ou [d_firstd_last].

Paramètres

first, last - la paire d'itérateurs définissant la plage d'éléments à
d_first - le début de la plage de destination
policy - la politique d'exécution à utiliser
op - objet fonction d'opération binaire qui sera appliqué.

La signature de la fonction doit être équivalente à la suivante :

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

La signature n'a pas besoin d'avoir const &.
Les types Type1 et Type2 doivent être tels qu'un objet de type iterator_traits<InputIt>::value_type puisse être converti implicitement en les deux. Le type Ret doit être tel qu'un objet de type OutputIt puisse être déréférencé et qu'une valeur de type Ret puisse lui être affectée. ​

Exigences de type
-
InputIt doit satisfaire les exigences de LegacyInputIterator.
-
OutputIt doit satisfaire les exigences de LegacyOutputIterator.
-
ForwardIt1, ForwardIt2 doit satisfaire les exigences de LegacyForwardIterator.

Valeur de retour

Itérateur pointant sur l'élément après le dernier élément écrit, ou d_first si [firstlast) est vide.

Complexité

Soit N comme std::distance(first, last) :

1,2) Exactement N-1 applications de operator-.
3,4) Exactement N-1 applications de la fonction binaire op.

Exceptions

Les surcharges avec un paramètre template nommé ExecutionPolicy signalent les erreurs comme suit :

  • Si l'exécution d'une fonction invoquée dans le cadre de l'algorithme lève une exception et que ExecutionPolicy est l'une des politiques standard, std::terminate est appelé. Pour tout autre ExecutionPolicy, le comportement est défini par l'implémentation.
  • Si l'algorithme échoue à allouer de la mémoire, std::bad_alloc est levée.

Implémentation possible

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;
}

Notes

acc a été introduit suite à la résolution de LWG issue 539. La raison d'utiliser acc plutôt que de calculer directement les différences est que la sémantique de ce dernier est confuse si les types suivants ne correspondent pas :

  • le type valeur de InputIt
  • le(s) type(s) inscriptible(s) de OutputIt
  • les types des paramètres de operator- ou op
  • le type de retour de operator- ou op

acc sert d'objet intermédiaire pour mettre en cache les valeurs des éléments itérés :

  • son type est le type valeur de InputIt
  • la valeur écrite dans d_first (qui est la valeur de retour de operator- ou op) lui est affectée
  • sa valeur est passée à operator- ou 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>{});

Exemple

#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);
}

Sortie :

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

Rapports de défauts

Les rapports de défauts suivants, modifiant le comportement, ont été appliqués rétroactivement aux normes C++ publiées précédemment.

DR Appliqué à Comportement publié Comportement correct
LWG 242 C++98 op ne pouvait pas avoir d'effets de bord il ne peut pas modifier
les plages impliquées
LWG 539 C++98 les exigences de type nécessaires pour que les évaluations
et les affectations du résultat soient valides manquaient
ajoutées
LWG 3058 C++17 pour les surcharges (2,4), le résultat de chaque invocation
de operator- ou op était affecté à un objet
temporaire, et cet objet était affecté à la plage de sortie
affecter les résultats
directement à la
plage de sortie

Voir aussi

calcule la somme partielle d'une plage d'éléments
(modèle de fonction)
additionne ou réduit une plage d'éléments
(modèle de fonction)