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 acuerdostd::variant<std::string, std::string> v2; v2 ="abc";// ERRORstd::variant<std::string, bool> v3; v3 ="abc";// de acuerdo, escoge string; bool no es un candidatostd::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)>;ifconstexpr(std::is_same_v<T, int>) os << arg;elseifconstexpr(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) |