std::variant<Types...>::operator=
De cppreference.com
constexpr variant& operator=( const variant& rhs );
|
(1) | (desde C++17) |
constexpr variant& operator=( variant&& rhs ) noexcept(/* véase más abajo */);
|
(2) | (desde C++17) |
template< class T >
variant& operator=( T&& t ) noexcept(/* véase más abajo */);
|
(3) | (desde C++17) |
Asigna un valor nuevo a un objeto variant existente.
1) Asignación de copia:
- Si tanto
*thiscomorhsestán sin valor por excepción, no hace nada. - De lo contrario, si
rhsestá sin valor, pero*thisno, destruye el valor contenido en*thisy lo hace sin valor. - De lo contrario, si
rhsmantiene la misma alternativa que*this, asigna el valor contenido enrhsal valor contenido en*this. Si se lanza una excepción,*thisno se vuelve sin valor: el valor depende de la garantía de seguridad de excepción de la asignación de copia de la alternativa. - De lo contrario, si la alternativa mantenida por
rhses o bien construible por copia que no lanza o no construible por movimiento que no lanza (determinado por std::is_nothrow_copy_constructible y std::is_nothrow_move_constructible, respectivamente), es equivalente athis->emplace<rhs.index()>(get<rhs.index()>(rhs)). - De lo contrario, es equivalente a
this->operator=(variant(rhs)). Observa que*thispuede conventirse en valueless_by_exception como se describe en (2).
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 ambas true para toda 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 todas true para toda T_i en Types....2) Asignación de movimiento:
- Si tanto
*thiscomorhsestán sin valor por excepción, no hace nada. - De lo contrario, si
rhsestá sin valor, pero*thisno, destruye el valor contenido en*thisy lo hace sin valor. - De lo contrario, si
rhsmantiene la misma alternativa que*this, asignastd::get<j>(std::move(rhs))al valor contenido en*this, conjsiendoindex(). Si se lanza una excepción,*thisno se vuelve sin valor: el valor depende de la garantía de seguridad de excepción de la asignación de movimiento de la alternativa. - De lo contrario (si
rhsy*thismantienen distintas alternativas), es equivalente athis->emplace<rhs.index()>(get<rhs.index()>(std::move(rhs))). Si se lanza una excepción por el constructor de movimiento deT_i,*thisse vuelve valueless_by_exception.
Esta sobrecarga solo participa en la resolución de sobrecargas si
std::is_move_constructible_v<T_i> y std::is_move_assignable_v<T_i> son ambas true para toda 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 todas true para toda T_i en Types....3) Asignación de conversión.
- Determina el tipo alternaativo
T_jque se seleccionaría por la resolución de sobrecarga para la expresiónF(std::forward<T>(t))si hubiera una sobrecarga de la función imaginariaF(T_i)para todaT_ideTypes...en ámbito al mismo tiempo, excepto que:
- Una sobrecarga
F(T_i)solamente se considera si la declaraciónT_i x[] = { std::forward<T>(t) };es válida para alguna variable inventadax; - Si
T_ies (posiblemente calificada-cv)bool,F(T_i)solamente se considera sistd:remove_cvref_t<T>también esbool.
- Una sobrecarga
- Si
*thisya mantiene unaT_j, asignastd::forward<T>(t)al valor contenido en*this. Si se lanza una excepción,*thisno se vuelve sin valor: el valor depende de la garantía de seguridad de excepción de la asignación llamada. - De lo contrario, si
std::is_nothrow_constructible_v<T_j, T> || !std::is_nothrow_move_constructible_v<T_j>estrue, es equivalente athis->emplace<j>(std::forward<T>(t)); - De lo contrario, es equivalente a
this->operator=(variant(std::forward<T>(t))).
std::decay_t<T> (hasta C++20)std::remove_cvref_t<T> (desde C++20) no es el 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)) (con F siendo el conjunto de funciones imaginarias mencionadas previamente) está bien formada.std::variant<string> v1;
v1 = "abc"; // de acuerdo
std::variant<std::string, std::string> v2;
v2 = "abc"; // ERROR
std::variant <std::string, bool> v3;
v3 = "abc"; // de acuerdo, escoge string; bool no es un candidato
std::variant<float, long, double> v4; // mantiene float
v4 = 0; // de acuerdo, mantiene long; float y double no son candidatos
Parámetros
| rhs | - | Otro variante.
|
| t | - | Un valor convertible a una de las alternativas del variante. |
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)
Especificación noexcept: (desde C++11)
noexcept(((std::is_nothrow_move_constructible_v<Types> && std::is_nothrow_move_assignable_v<Types>) && ...))
|
||
3)
Especificación noexcept: (desde C++11)
noexcept(std::is_nothrow_assignable_v<T_j&, T> && std::is_nothrow_constructible_v<T_j, T>)
|
||
Ejemplo
Ejecuta este código
#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 ), donde T es int\n";
a = 2019;
std::cout << "a" << a << '\n';
std::cout << "(3) operator=( T&& t ), donde T es 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';
}
Posible salida:
a: { 2017 };
b: { "CppCon" };
(1) operator=( const variant& rhs )
a: { "CppCon" };
b: { "CppCon" };
(2) operator=( variant&& rhs )
a: { "CppCon" };
b: { "" };
(3) operator=( T&& t ), donde T es int
a: { 2019 };
(3) operator=( T&& t ), donde T es std::string
s: "CppNow"
a: { "CppNow" };
s: ""
Informes de defectos
Los siguientes informes de defectos de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.
| ID | Aplicado a | Comportamiento según lo publicado | Comportamiento correcto |
|---|---|---|---|
| LWG 3024 | C++17 | El operador de asignación de copia no participa en la resolución de sobrecarga si cualquier tipo miembro no es copiable. | En su lugar, se definió como eliminado. |
| P0602R4 | C++17 | La asignación de copia/movimiento puede no ser trivial incluso si las operaciones subyacentes son triviales. | Se requirió que se propagase la trivialidad. |
| P0608R3 | C++17 | La asignación de conversión ciegamente recopila el conjunto de sobrecargas, lo que conduce a conversiones no deseadas. | No se consideran las conversiones de estrechamiento ni Booleanas. |
Véase también
| Construye un valor en el variante, en el sitio. (función miembro pública) |