std::variant<Types...>:: operator=
|
constexpr
variant
&
operator
=
(
const
variant
&
rhs
)
;
|
(1) | (depuis C++17) |
|
constexpr
variant
&
operator
=
(
variant
&&
rhs
)
noexcept
(
/* voir ci-dessous */
)
;
|
(2) | (depuis C++17) |
|
template
<
class
T
>
variant & operator = ( T && t ) noexcept ( /* voir ci-dessous */ ) ; |
(3) |
(depuis C++17)
(constexpr depuis C++20) |
Attribue une nouvelle valeur à un objet
variant
existant.
- Si les deux * this et rhs sont sans valeur par exception, ne fait rien.
- Sinon, si rhs est sans valeur, mais * this ne l'est pas, détruit la valeur contenue dans * this et le rend sans valeur.
- Sinon, si rhs contient la même alternative que * this , affecte la valeur contenue dans rhs à la valeur contenue dans * this . Si une exception est levée, * this ne devient pas sans valeur : la valeur dépend de la garantie de sécurité face aux exceptions de l'affectation par copie de l'alternative.
-
Sinon, si l'alternative détenue par
rhs
est soit non levante en construction par copie, soit
non
non levante en construction par déplacement (tel que déterminé par
std::is_nothrow_copy_constructible
et
std::is_nothrow_move_constructible
, respectivement), équivalent à
this
-
>
emplace
<
rhs.
index
(
)
>
(
*
std::
get_if
<
rhs.
index
(
)
>
(
std::
addressof
(
rhs
)
)
)
.
*
this
peut devenir
valueless_by_exceptionsi une exception est levée lors de la construction par copie dansemplace. - Sinon, équivalent à this - > operator = ( variant ( rhs ) ) .
T_i
dans
Types...
. Cette surcharge est triviale si
std::
is_trivially_copy_constructible_v
<
T_i
>
,
std::
is_trivially_copy_assignable_v
<
T_i
>
et
std::
is_trivially_destructible_v
<
T_i
>
sont tous
true
pour tous les
T_i
dans
Types...
.
- Si les deux * this et rhs sont sans valeur par exception, ne fait rien.
- Sinon, si rhs est sans valeur, mais * this ne l'est pas, détruit la valeur contenue dans * this et le rend sans valeur.
-
Sinon, si
rhs
contient la même alternative que
*
this
, affecte
std
::
move
(
*
std::
get_if
<
j
>
(
std::
addressof
(
rhs
)
)
)
à la valeur contenue dans
*
this
, avec
jétantindex(). Si une exception est levée, * this ne devient pas sans valeur : la valeur dépend de la garantie de sécurité face aux exceptions de l'affectation par déplacement de l'alternative. -
Sinon (si
rhs
et
*
this
contiennent des alternatives différentes), équivalent à
this
-
>
emplace
<
rhs.
index
(
)
>
(
std
::
move
(
*
std::
get_if
<
rhs.
index
(
)
>
(
std::
addressof
(
rhs
)
)
)
)
. Si une exception est levée par le constructeur par déplacement de
T_i, * this devientvalueless_by_exception.
T_i
dans
Types...
. Cette surcharge est triviale si
std::
is_trivially_move_constructible_v
<
T_i
>
,
std::
is_trivially_move_assignable_v
<
T_i
>
, et
std::
is_trivially_destructible_v
<
T_i
>
sont tous
true
pour tous les
T_i
dans
Types...
.
-
Détermine le type alternatif
T_jqui serait sélectionné par la résolution de surcharge pour l'expression F ( std:: forward < T > ( t ) ) s'il existait une surcharge de la fonction imaginaire F ( T_i ) pour chaqueT_ideTypes...dans la portée simultanément, sauf que :
-
-
Une surcharge
F
(
T_i
)
n'est considérée que si la déclaration
T_i x
[
]
=
{
std::
forward
<
T
>
(
t
)
}
;
est valide pour une variable inventée
x;
-
Une surcharge
F
(
T_i
)
n'est considérée que si la déclaration
T_i x
[
]
=
{
std::
forward
<
T
>
(
t
)
}
;
est valide pour une variable inventée
-
Si
*
this
contient déjà un
T_j, assigne std:: forward < T > ( t ) à la valeur contenue dans * this . Si une exception est levée, * this ne devient pas sans valeur : la valeur dépend de la garantie de sûreté des exceptions de l'assignation appelée. -
Sinon, si
std::
is_nothrow_constructible_v
<
T_j, T
>
||
!
std::
is_nothrow_move_constructible_v
<
T_j
>
est
true
, équivaut à
this
-
>
emplace
<
j
>
(
std::
forward
<
T
>
(
t
)
)
.
*
this
peut devenir
valueless_by_exceptionsi une exception est levée lors de l'initialisation dansemplace. - Sinon, équivaut à this - > emplace < j > ( T_j ( std:: forward < T > ( t ) ) ) .
Cette surcharge participe à la résolution de surcharge seulement si
std::
decay_t
<
T
>
(jusqu'en C++20)
std::
remove_cvref_t
<
T
>
(depuis C++20)
n'est pas du même type que
variant
et
std::
is_assignable_v
<
T_j
&
, T
>
est
true
et
std::
is_constructible_v
<
T_j, T
>
est
true
et l'expression
F
(
std::
forward
<
T
>
(
t
)
)
(avec F étant l'ensemble de fonctions imaginaires mentionné ci-dessus) est bien formée.
std::variant<std::string> v1; v1 = "abc"; // OK std::variant<std::string, std::string> v2; v2 = "abc"; // Erreur std::variant <std::string, bool> v3; v3 = "abc"; // OK, choisit string; bool n'est pas un candidat std::variant<float, long, double> v4; // contient float v4 = 0; // OK, contient long; float et double ne sont pas candidats
Table des matières |
Paramètres
| rhs | - |
another
variant
|
| t | - | une valeur convertible en l'une des alternatives du variant |
Valeur de retour
* this
Exceptions
std:: is_nothrow_move_assignable_v < Types > ) && ... ) )
std:: is_nothrow_constructible_v < T_j, T > )
Notes
| Macro de test de fonctionnalité | Valeur | Std | Fonctionnalité |
|---|---|---|---|
__cpp_lib_variant
|
202106L
|
(C++20)
(DR) |
std::variant
entièrement
constexpr
(
3
)
|
Exemple
#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'; }
Sortie possible :
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: ""
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Appliqué à | Comportement publié | Comportement corrigé |
|---|---|---|---|
| LWG 3024 | C++17 |
l'opérateur d'affectation par copie ne participe pas à la résolution de surcharge
si un type membre n'est pas copiable |
défini comme supprimé à la place |
| LWG 3585 | C++17 |
l'affectation de conversion était parfois inattendument mal formée
car il n'y avait pas d'affectation de déplacement disponible |
rendue bien formée |
| P0602R4 | C++17 |
l'affectation par copie/déplacement peut ne pas être triviale
même si les opérations sous-jacentes sont triviales |
requis de propager la trivialité |
| P0608R3 | C++17 |
l'affectation de conversion assemble aveuglément un ensemble de surcharge,
conduisant à des conversions non intentionnelles |
les conversions de rétrécissement et booléennes
ne sont pas considérées |
| P2231R1 | C++20 |
l'affectation de conversion
(
3
)
n'était pas
constexpr
alors que les opérations requises peuvent être constexpr en C++20 |
rendue constexpr |
Voir aussi
construit une valeur dans le
variant
, en place
(fonction membre publique) |