Namespaces
Variants

std:: exchange

From cppreference.net
Utilities library
Défini dans l'en-tête <utility>
template < class T, class U = T >
T exchange ( T & obj, U && new_value ) ;
(depuis C++14)
(constexpr depuis C++20)
(conditionnellement noexcept depuis C++23)

Remplace la valeur de obj par new_value et retourne l'ancienne valeur de obj .

Table des matières

Paramètres

obj - objet dont la valeur doit être remplacée
new_value - la valeur à assigner à obj
Exigences de type
-
T doit satisfaire aux exigences de MoveConstructible . De plus, il doit être possible d'assigner par déplacement des objets de type U vers des objets de type T .

Valeur de retour

L'ancienne valeur de obj .

Exceptions

(aucun)

(jusqu'à C++23)
(depuis C++23)

Implémentation possible

template<class T, class U = T>
constexpr // Depuis C++20
T exchange(T& obj, U&& new_value)
    noexcept( // Depuis C++23
        std::is_nothrow_move_constructible<T>::value &&
        std::is_nothrow_assignable<T&, U>::value
    )
{
    T old_value = std::move(obj);
    obj = std::forward<U>(new_value);
    return old_value;
}

Notes

std::exchange peut être utilisé lors de l'implémentation des constructeurs de déplacement et, pour les membres qui ne nécessitent pas de nettoyage spécial , des opérateurs d'affectation par déplacement :

struct S
{
    int n;
    S(S&& other) noexcept : n{std::exchange(other.n, 0)} {}
    S& operator=(S&& other) noexcept
    {
        n = std::exchange(other.n, 0); // Déplace n, tout en laissant zéro dans other.n
        // Note : en cas d'auto-affectation par déplacement, n reste inchangé
        // Note également : si n est un descripteur de ressource opaque nécessitant
        //                 un nettoyage spécial, la ressource est perdue.
        return *this;
    }
};
Macro de test de fonctionnalité Valeur Std Fonctionnalité
__cpp_lib_exchange_function 201304L (C++14) std::exchange

Exemple

#include <iostream>
#include <iterator>
#include <utility>
#include <vector>
class stream
{
public:
    using flags_type = int;
public:
    flags_type flags() const { return flags_; }
    // Remplace flags_ par newf, et retourne l'ancienne valeur.
    flags_type flags(flags_type newf) { return std::exchange(flags_, newf); }
private:
    flags_type flags_ = 0;
};
void f() { std::cout << "f()"; }
int main()
{
    stream s;
    std::cout << s.flags() << '\n';
    std::cout << s.flags(12) << '\n';
    std::cout << s.flags() << "\n\n";
    std::vector<int> v;
    // Puisque le second paramètre template a une valeur par défaut, il est possible
    // d'utiliser une liste d'initialisation entre accolades comme second argument. L'expression ci-dessous
    // est équivalente à std::exchange(v, std::vector<int>{1, 2, 3, 4});
    std::exchange(v, {1, 2, 3, 4});
    std::copy(begin(v), end(v), std::ostream_iterator<int>(std::cout, ", "));
    std::cout << "\n\n";
    void (*fun)();
    // La valeur par défaut du paramètre template permet également d'utiliser une
    // fonction normale comme second argument. L'expression ci-dessous est équivalente à
    // std::exchange(fun, static_cast<void(*)()>(f))
    std::exchange(fun, f);
    fun();
    std::cout << "\n\nSuite de Fibonacci : ";
    for (int a{0}, b{1}; a < 100; a = std::exchange(b, a + b))
        std::cout << a << ", ";
    std::cout << "...\n";
}

Sortie :

0
0
12
1, 2, 3, 4,
f()
Suite de Fibonacci : 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

Voir aussi

échange les valeurs de deux objets
(modèle de fonction)
remplace atomiquement la valeur de l'objet atomique par l'argument non atomique et retourne l'ancienne valeur de l'atome
(modèle de fonction)