Namespaces
Variants

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

From cppreference.net
Utilities library
constexpr variant & operator = ( const variant & rhs ) ;
(1) (desde C++17)
constexpr variant & operator = ( variant && rhs ) noexcept ( /* ver más abajo */ ) ;
(2) (desde C++17)
template < class T >
variant & operator = ( T && t ) noexcept ( /* ver más abajo */ ) ;
(3) (desde C++17)
(constexpr desde C++20)

Asigna un nuevo valor a un objeto variant existente.

1) Asignación por copia:
  • Si tanto * this como rhs están sin valor por excepción, no hace nada.
  • En caso contrario, si rhs está sin valor pero * this no lo está, destruye el valor contenido en * this y lo deja sin valor.
  • En caso contrario, si rhs contiene la misma alternativa que * this , asigna el valor contenido en rhs al valor contenido en * this . Si se lanza una excepción, * this no queda sin valor: el valor depende de la garantía de seguridad de excepciones de la asignación por copia de la alternativa.
  • En caso contrario, si la alternativa contenida en rhs es no-lanzante en construcción por copia o no es no-lanzante en construcción por movimiento (determinado por std::is_nothrow_copy_constructible y std::is_nothrow_move_constructible , respectivamente), equivalente a this - > emplace < rhs. index ( ) > ( * std:: get_if < rhs. index ( ) > ( std:: addressof ( rhs ) ) ) . * this puede quedar valueless_by_exception si se lanza una excepción durante la construcción por copia dentro de emplace .
  • En caso contrario, equivalente 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 todos los 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 todos los T_i en Types... .
2) Asignación por movimiento:
  • Si tanto * this como rhs están sin valor por excepción, no hace nada.
  • En caso contrario, si rhs está sin valor pero * this no lo está, destruye el valor contenido en * this y lo deja sin valor.
  • En caso contrario, si rhs contiene la misma alternativa que * this , asigna std :: move ( * std:: get_if < j > ( std:: addressof ( rhs ) ) ) al valor contenido en * this , siendo j igual a index() . Si se lanza una excepción, * this no queda sin valor: el valor depende de la garantía de seguridad de excepciones de la asignación por movimiento de la alternativa.
  • En caso contrario (si rhs y * this contienen alternativas diferentes), equivalente a this - > emplace < rhs. index ( ) > ( std :: move ( * std:: get_if < rhs. index ( ) > ( std:: addressof ( rhs ) ) ) ) . Si el constructor por movimiento de T_i lanza una excepción, * this se convierte en valueless_by_exception .
Esta sobrecarga participa en la resolución de sobrecarga 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) Converting assignment.
  • Determina el tipo alternativo T_j que sería seleccionado por la resolución de sobrecarga para la expresión F ( std:: forward < T > ( t ) ) si existiera una sobrecarga de la función imaginaria F ( T_i ) para cada T_i de Types... en á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 ;

Esta sobrecarga participa en la resolución de sobrecarga 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 mencionado anteriormente de funciones imaginarias) está bien formada.

std::variant<std::string> v1;
v1 = "abc"; // CORRECTO
std::variant<std::string, std::string> v2;
v2 = "abc"; // Error
std::variant <std::string, bool> v3;
v3 = "abc"; // CORRECTO, elige string; bool no es candidato
std::variant<float, long, double> v4; // contiene float
v4 = 0; // CORRECTO, contiene long; float y double no son candidatos

Contenidos

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)