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
*this
comorhs
están sin valor por excepción, no hace nada. - De lo contrario, si
rhs
está sin valor, pero*this
no, destruye el valor contenido en*this
y lo hace sin valor. - De lo contrario, si
rhs
mantiene la misma alternativa que*this
, asigna el valor contenido enrhs
al valor contenido en*this
. Si se lanza una excepción,*this
no 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
rhs
es 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 a this->emplace<rhs.index()>(get<rhs.index()>(rhs)). - De lo contrario, es equivalente a this->operator=(variant(rhs)). Observa que
*this
puede 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
*this
comorhs
están sin valor por excepción, no hace nada. - De lo contrario, si
rhs
está sin valor, pero*this
no, destruye el valor contenido en*this
y lo hace sin valor. - De lo contrario, si
rhs
mantiene la misma alternativa que*this
, asigna std::get<j>(std::move(rhs)) al valor contenido en*this
, conj
siendoindex()
. Si se lanza una excepción,*this
no 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
rhs
y*this
mantienen distintas alternativas), es equivalente a this->emplace<rhs.index()>(get<rhs.index()>(std::move(rhs))). Si se lanza una excepción por el constructor de movimiento deT_i
,*this
se 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_j
que se seleccionaría por la 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 todaT_i
deTypes...
en ámbito al mismo tiempo, excepto que:
- Una sobrecarga F(T_i) solamente se considera si la declaración T_i x[] = { std::forward<T>(t) }; es válida para alguna variable inventada
x
; - Si
T_i
es (posiblemente calificada-cv) bool, F(T_i) solamente se considera si std:remove_cvref_t<T> también es bool.
- Una sobrecarga F(T_i) solamente se considera si la declaración T_i x[] = { std::forward<T>(t) }; es válida para alguna variable inventada
- Si
*this
ya mantiene unaT_j
, asigna std::forward<T>(t) al valor contenido en*this
. Si se lanza una excepción,*this
no 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> es true, es equivalente a this->emplace<j>(std::forward<T>(t));
- De lo contrario, es equivalente a this->operator=(variant(std::forward<T>(t))).
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
Contenido |
[editar] Parámetros
rhs | - | Otro variant e.
|
t | - | Un valor convertible a una de las alternativas del variante. |
[editar] Valor de retorno
*this
[editar] 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>) |
||
[editar] 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: ""
[editar] 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. |
[editar] Véase también
Construye un valor en el variante, en el sitio. (función miembro pública) |