Namespaces
Variants

std::variant<Types...>::operator=

De es.cppreference.net
 
 
Biblioteca de utilidades
Soporte de lenguaje
Soporte de tipos (tipos básicos, RTTI)
Macros de prueba de características de biblioteca (C++20)
Utilidades de programa
Funciones variádicas
Soporte de corrutinas (C++20)
Soporte de contratos (C++26)
Comparación a tres vías
(C++20)
(C++20)(C++20)(C++20)    
(C++20)(C++20)(C++20)

Utilidades generales
Operadores relacionales (obsoleto en C++20)
 
 
constexpr variant& operator=( const variant& rhs );
(1) (desde C++17)
constexpr variant& operator=( variant&& rhs ) noexcept(/* see below */);
(2) (desde C++17)
template< class T >
variant& operator=( T&& t ) noexcept(/* see below */);
(3) (desde C++17)
(constexpr desde C++20)

Asigna un nuevo valor a un objeto variant existente.

1) Copia-asignación:
  • Si tanto *this como rhs no tienen valor por excepción, no hace nada.
  • En caso contrario, si rhs no tiene valor, pero *this sí, destruye el valor contenido en *this y lo deja sin valor.
  • En caso contrario, si rhs tiene la misma alternativa que *this, asigna el valor contenido en rhs al valor contenido en *this. Si se lanza una excepción, *this no se queda sin valor: el valor depende de la garantía de seguridad ante excepciones de la copia-asignación de la alternativa.
  • En caso contrario, si la alternativa contenida por rhs no es construible por copia sin lanzar excepciones o no es construible por movimiento sin lanzar excepciones (según lo determina std::is_nothrow_copy_constructible y std::is_nothrow_move_constructible, respectivamente), equivale a this->emplace<rhs.index()>(*std::get_if<rhs.index()>(std::addressof(rhs))). *this puede quedar valueless_by_exception sin valor si se lanza una excepción durante la construcción por copia dentro de emplace.
  • En caso contrario, equivale a this->operator=(variant(rhs)).
Esta sobrecarga se define como eliminada a menos que std::is_copy_constructible_v<T_i> y std::is_copy_assignable_v<T_i> sean ambos true para todo T_i en Types.... Esta sobrecarga es trivial si std::is_trivially_copy_constructible_v<T_i>,std::is_trivially_copy_assignable_v<T_i> y std::is_trivially_destructible_v<T_i> son todos true para todo T_i en Types....
2) Movimiento-asignación:
  • Si tanto *this como rhs no tienen valor por excepción, no hace nada.
  • En caso contrario, si rhs no tiene valor, pero *this sí, destruye el valor contenido en *this y lo deja sin valor.
  • En caso contrario, si rhs tiene la misma alternativa que *this, asigna std::move(*std::get_if<j>(std::addressof(rhs))) al valor contenido en *this, siendo j index(). Si se lanza una excepción, *this no se queda sin valor: el valor depende de la garantía de seguridad ante excepciones de la movimiento-asignación de la alternativa.
  • En caso contrario (si rhs y *this tienen alternativas diferentes), equivale a this->emplace<rhs.index()>(std::move(*std::get_if<rhs.index()>(std::addressof(rhs)))). Si el constructor de movimiento de T_i lanza una excepción, *this se convierte en valueless_by_exception.
Esta sobrecarga participa en la resolución de sobrecargas solo si std::is_move_constructible_v<T_i> y std::is_move_assignable_v<T_i> son ambos true para todo T_i en Types.... Esta sobrecarga es trivial si std::is_trivially_move_constructible_v<T_i>, std::is_trivially_move_assignable_v<T_i> y std::is_trivially_destructible_v<T_i> son todos true para todo T_i en Types....
3) Asignación de conversión.
  • Determina el tipo de alternativa T_j que sería seleccionado por resolución de sobrecarga para la expresión F(std::forward<T>(t)) si hubiera una sobrecarga de la función imaginaria F(T_i) para cada T_i de Types... en el ámbito al mismo tiempo, excepto que:
  • Una sobrecarga F(T_i) solo se considera si la declaración T_i x[] = { std::forward<T>(t) }; es válida para alguna variable inventada x;
  • Si *this ya contiene un T_j, asigna std::forward<T>(t) al valor contenido en *this. Si se lanza una excepción, *this no se queda sin valor: el valor depende de la garantía de seguridad ante excepciones de la asignación llamada.
  • En caso contrario, si std::is_nothrow_constructible_v<T_j, T> || !std::is_nothrow_move_constructible_v<T_j> es true, equivale a this->emplace<j>(std::forward<T>(t)). *this puede quedar valueless_by_exception sin valor si se lanza una excepción durante la inicialización dentro de emplace.
  • En caso contrario, equivale a this->emplace<j>(T_j(std::forward<T>(t))).

Esta sobrecarga participa en la resolución de sobrecargas solo si std::decay_t<T>(hasta C++20)std::remove_cvref_t<T>(desde C++20) no es del mismo tipo que variant y std::is_assignable_v<T_j&, T> es true y std::is_constructible_v<T_j, T> es true y la expresión F(std::forward<T>(t)) (siendo F el conjunto de funciones imaginarias mencionado anteriormente) está bien formada.

std::variant<std::string> v1;
v1 = "abc"; // OK
std::variant<std::string, std::string> v2;
v2 = "abc"; // Error
std::variant <std::string, bool> v3;
v3 = "abc"; // OK, chooses string; bool is not a candidate
std::variant<float, long, double> v4; // holds float
v4 = 0; // OK, holds long; float and double are not candidates

Parámetros

rhs - otro variant
t - un valor convertible a una de las alternativas del variant

Valor de retorno

* this

Excepciones

1) Puede lanzar cualquier excepción lanzada por la asignación y la inicialización de copia/movimiento de cualquier alternativa.
2)
noexcept especificación:
noexcept ( ( ( std:: is_nothrow_move_constructible_v < Types > &&
std:: is_nothrow_move_assignable_v < Types > ) && ... ) )
3)
noexcept especificación:

Notas

Macro de prueba de características Valor Std Característica
__cpp_lib_variant 202106L (C++20)
(DR)
Completamente constexpr std::variant ( 3 )

Ejemplo

#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
std::ostream& operator<<(std::ostream& os, std::variant<int, std::string> const& va)
{
    os << ": { ";
    std::visit([&](auto&& arg)
    {
        using T = std::decay_t<decltype(arg)>;
        if constexpr (std::is_same_v<T, int>)
            os << arg;
        else if constexpr (std::is_same_v<T, std::string>)
            os << std::quoted(arg);
    }, va);
    return os << " };\n";
}
int main()
{
    std::variant<int, std::string> a{2017}, b{"CppCon"};
    std::cout << "a" << a << "b" << b << '\n';
    std::cout << "(1) operator=( const variant& rhs )\n";
    a = b;
    std::cout << "a" << a << "b" << b << '\n';
    std::cout << "(2) operator=( variant&& rhs )\n";
    a = std::move(b);
    std::cout << "a" << a << "b" << b << '\n';
    std::cout << "(3) operator=( T&& t ), where T is int\n";
    a = 2019;
    std::cout << "a" << a << '\n';
    std::cout << "(3) operator=( T&& t ), where T is std::string\n";
    std::string s{"CppNow"};
    std::cout << "s: " << std::quoted(s) << '\n';
    a = std::move(s);
    std::cout << "a" << a << "s: " << std::quoted(s) << '\n';
}

Salida posible:

a: { 2017 };
b: { "CppCon" };
(1) operator=( const variant& rhs )
a: { "CppCon" };
b: { "CppCon" };
(2) operator=( variant&& rhs )
a: { "CppCon" };
b: { "" };
(3) operator=( T&& t ), where T is int
a: { 2019 };
(3) operator=( T&& t ), where T is std::string
s: "CppNow"
a: { "CppNow" };
s: ""

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.

DR Aplicado a Comportamiento publicado Comportamiento correcto
LWG 3024 C++17 el operador de asignación de copia no participa en la resolución de sobrecarga
si algún tipo miembro no es copiable
definido como eliminado en su lugar
LWG 3585 C++17 la asignación de conversión a veces era inesperadamente mal formada
porque no había asignación de movimiento disponible
hecho bien formado
P0602R4 C++17 la asignación de copia/movimiento puede no ser trivial
incluso si las operaciones subyacentes son triviales
requerido propagar trivialidad
P0608R3 C++17 la asignación de conversión ensambla ciegamente un conjunto de sobrecarga,
conduciendo a conversiones no intencionadas
conversiones de estrechamiento y booleanas
no consideradas
P2231R1 C++20 la asignación de conversión ( 3 ) no era constexpr
mientras que las operaciones requeridas pueden ser constexpr en C++20
hecho constexpr

Véase también

construye un valor en el variant , en el lugar
(función miembro pública)