std::variant<Types...>:: operator=
|
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.
- 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_exceptionsi se lanza una excepción durante la construcción por copia dentro deemplace. - En caso contrario, equivalente a this - > operator = ( variant ( rhs ) ) .
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...
.
- 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
jigual aindex(). 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_ilanza una excepción, * this se convierte envalueless_by_exception.
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...
.
-
Determina el tipo alternativo
T_jque 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 cadaT_ideTypes...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;
-
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
-
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 vuelve sin valor: el valor depende de la garantía de seguridad de excepciones 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
, equivalente a
this
-
>
emplace
<
j
>
(
std::
forward
<
T
>
(
t
)
)
.
*
this
puede volverse
valueless_by_exceptionsi se lanza una excepción durante la inicialización dentro deemplace. - De lo contrario, equivalente a this - > emplace < j > ( T_j ( std:: forward < T > ( t ) ) ) .
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
std:: is_nothrow_move_assignable_v < Types > ) && ... ) )
std:: is_nothrow_constructible_v < T_j, T > )
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) |