Namespaces
Variants

std:: exchange

From cppreference.net
Utilities library
Definido en el encabezado <utility>
template < class T, class U = T >
T exchange ( T & obj, U && new_value ) ;
(desde C++14)
(constexpr desde C++20)
(condicionalmente noexcept desde C++23)

Reemplaza el valor de obj con new_value y devuelve el valor anterior de obj .

Contenidos

Parámetros

obj - objeto cuyo valor reemplazar
new_value - el valor a asignar a obj
Requisitos de tipo
-
T debe cumplir con los requisitos de MoveConstructible . Además, debe ser posible asignar por movimiento objetos de tipo U a objetos de tipo T .

Valor de retorno

El valor antiguo de obj .

Excepciones

(ninguno)

(hasta C++23)
(desde C++23)

Implementación posible

template<class T, class U = T>
constexpr // Desde C++20
T exchange(T& obj, U&& new_value)
    noexcept( // Desde 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;
}

Notas

std::exchange puede utilizarse al implementar move constructors y, para los miembros que no requieren special cleanup , move assignment operators :

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); // Mover n, dejando cero en other.n
        // Nota: en caso de auto-asignación de movimiento, n permanece sin cambios
        // También nota: si n es un identificador de recurso opaco que requiere
        //            limpieza especial, el recurso tiene una fuga.
        return *this;
    }
};
Macro de prueba de características Valor Std Característica
__cpp_lib_exchange_function 201304L (C++14) std::exchange

Ejemplo

#include <iostream>
#include <iterator>
#include <utility>
#include <vector>
class stream
{
public:
    using flags_type = int;
public:
    flags_type flags() const { return flags_; }
    // Reemplaza flags_ por newf, y devuelve el valor anterior.
    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;
    // Dado que el segundo parámetro de plantilla tiene un valor por defecto, es posible
    // usar una lista de inicialización entre llaves como segundo argumento. La expresión a continuación
    // es equivalente a 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)();
    // El valor por defecto del parámetro de plantilla también hace posible usar una
    // función normal como segundo argumento. La expresión a continuación es equivalente a
    // std::exchange(fun, static_cast<void(*)()>(f))
    std::exchange(fun, f);
    fun();
    std::cout << "\n\nSecuencia de Fibonacci: ";
    for (int a{0}, b{1}; a < 100; a = std::exchange(b, a + b))
        std::cout << a << ", ";
    std::cout << "...\n";
}

Salida:

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

Véase también

intercambia los valores de dos objetos
(plantilla de función)
reemplaza atómicamente el valor del objeto atómico con argumento no atómico y devuelve el valor anterior del atómico
(plantilla de función)