Espacios de nombres
Variantes

std::exchange

De cppreference.com
 
 
Biblioteca de servicios
 
<tbody> </tbody> <tbody class="t-dcl-rev "> </tbody><tbody> </tbody>
Definido en el archivo de encabezado <utility>
template< class T, class U = T > T exchange( T& obj, U&& new_value );
(desde C++14)
(hasta C++20)
template< class T, class U = T > constexpr T exchange( T& obj, U&& new_value );
(desde C++20)
(hasta C++23)
template< class T, class U = T > constexpr T exchange( T& obj, U&& new_value ) noexcept(/* véase más abajo */);
(desde C++23)

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

Parámetros

obj - Objeto cuyo valor hay que reemplazar.
new_value - El valor a asignar a obj.
Requisitos de tipo
-
T debe satisfacer los requisitos de MoveConstructible. También debe ser posible asignar por movimiento objetos de tipo U a objetos de tipo T.

Valor de retorno

El valor antiguo de obj.

Excepciones

(Ninguna)

(hasta C++23)
Especificación noexcept:   (desde C++11)
<tbody> </tbody>
noexcept( std::is_nothrow_move_constructible_v<T> && std::is_nothrow_assignable_v<T&, U> )
(desde C++23)

Posible implementación

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

La función de intercambio std::exchange puede usarse al implementar los operadores de asignación de movimiento y los constructores de movimiento:

struct S
{
  int n;

  S(S&& other) noexcept : n{std::exchange(other.n, 0)}
  {}
  
  S& operator=(S&& other) noexcept 
  {
    if(this != &other)
        n = std::exchange(other.n, 0); // mover n, dejando cero en other.n
    return *this;
  }
};

Ejemplo

#include <iostream>
#include <utility>
#include <vector>
#include <iterator>

class stream
{
  public:

   using flags_type = int;

  public:

    flags_type flags() const
    { return flags_; }

    // Reemplaza flags_ por newf y devuelve el valor antiguo
    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;

   // Ya que el segundo parámetro de plantilla tiene un valor por defecto,
   // es posible usar una lista de inicializadores entre llaves como
   // el segundo argumento. La expresión siguiente 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 siguiente es equivalente a
   // std::exchange(fun, static_cast<void(*)()>(f))
   std::exchange(fun,f);
   fun();
}

Salida:

0
0
12

1, 2, 3, 4, 

f()

Véase también

Intercambia los valores de dos objetos
(plantilla de función) [editar]
Reemplaza atómicamente el valor del objeto atómico con el del argumento no atómico y devuelve el valor anterior del objeto atómico.
(plantilla de función) [editar]