std::variant<Types...>::operator=
De fr.cppreference.net
constexpr variant& operator=( const variant& rhs );
|
(1) | (depuis C++17) |
constexpr variant& operator=( variant&& rhs ) noexcept(/* see below */);
|
(2) | (depuis C++17) |
template< class T >
variant& operator=( T&& t ) noexcept(/* see below */);
|
(3) | (depuis C++17) (constexpr depuis C++20) |
Assigne une nouvelle valeur à un objet variant existant.
1) Affectation par copie :
- Si
*thisetrhssont tous deux sans valeur par exception, ne fait rien. - Sinon, si
rhsest sans valeur, mais pas*this, détruit la valeur contenue dans*thiset le rend sans valeur. - Sinon, si
rhscontient la même alternative que*this, assigne la valeur contenue dansrhsà la valeur contenue dans*this. Si une exception est levée,*thisne devient pas sans valeur : la valeur dépend de la garantie de sécurité d'exception de l'affectation par copie de l'alternative. - Sinon, si l'alternative contenue par
rhsest constructible par copie sans exception ou n'est pas constructible par déplacement sans exception (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))).*thispeut devenirvalueless_by_exceptionsi une exception est levée lors de la construction par copie à l'intérieur deemplace. - Sinon, équivalent à
this->operator=(variant(rhs)).
Cette surcharge est définie comme supprimée sauf si
std::is_copy_constructible_v<T_i> et std::is_copy_assignable_v<T_i> sont tous deux true pour tout 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 tout T_i dans Types....2) Affectation par déplacement :
- Si
*thisetrhssont tous deux sans valeur par exception, ne fait rien. - Sinon, si
rhsest sans valeur, mais pas*this, détruit la valeur contenue dans*thiset le rend sans valeur. - Sinon, si
rhscontient la même alternative que*this, assignestd::move(*std::get_if<j>(std::addressof(rhs)))à la valeur contenue dans*this,jétantindex(). Si une exception est levée,*thisne devient pas sans valeur : la valeur dépend de la garantie de sécurité d'exception de l'affectation par déplacement de l'alternative. - Sinon (si
rhset*thiscontiennent 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 de déplacement deT_i,*thisdevientvalueless_by_exception.
Cette surcharge participe à la résolution de surcharge seulement si
std::is_move_constructible_v<T_i> et std::is_move_assignable_v<T_i> sont tous deux true pour tout 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 tout T_i dans Types....3) Affectation par conversion.
- Détermine le type alternatif
T_jqui serait sélectionné par la résolution de surcharge pour l'expressionF(std::forward<T>(t))s'il y avait une surcharge de la fonction imaginaireF(T_i)pour chaqueT_ideTypes...dans la portée au même moment, sauf que :
- Une surcharge
F(T_i)n'est considérée que si la déclarationT_i x[] = { std::forward<T>(t) };est valide pour une variable inventéex;
- Une surcharge
- Si
*thiscontient déjà unT_j, assignestd::forward<T>(t)à la valeur contenue dans*this. Si une exception est levée,*thisne devient pas sans valeur : la valeur dépend de la garantie de sécurité d'exception de l'affectation appelée. - Sinon, si
std::is_nothrow_constructible_v<T_j, T> || !std::is_nothrow_move_constructible_v<T_j>esttrue, équivalent àthis->emplace<j>(std::forward<T>(t)).*thispeut devenirvalueless_by_exceptionsi une exception est levée lors de l'initialisation à l'intérieur deemplace. - Sinon, équivalent à
this->emplace<j>(T_j(std::forward<T>(t))).
Cette surcharge participe à la résolution de surcharge seulement si std::decay_t<T>(jusqu'à C++20)std::remove_cvref_t<T>(depuis C++20) n'est pas le 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 susmentionné de fonctions imaginaires) est bien formée.
std::variant<std::string> v1;
v1 = "abc"; // OK
std::variant<std::string, std::string> v2;
v2 = "abc"; // Error
std::variant <std::string, bool> v3;
v3 = "abc"; // OK, chooses string; bool is not a candidate
std::variant<float, long, double> v4; // holds float
v4 = 0; // OK, holds long; float and double are not candidates
Paramètres
| rhs | - |
another
variant
|
| t | - | une valeur convertible en l'une des alternatives du variant |
Valeur de retour
* this
Exceptions
1)
Peut lever toute exception générée par l'assignation et l'initialisation par copie/déplacement de toute alternative.
2)
noexcept
spécification :
noexcept
(
(
(
std::
is_nothrow_move_constructible_v
<
Types
>
&&
std:: is_nothrow_move_assignable_v < Types > ) && ... ) )
std:: is_nothrow_move_assignable_v < Types > ) && ... ) )
3)
noexcept
spécification :
noexcept
(
std::
is_nothrow_assignable_v
<
T_j
&
, T
>
&&
std:: is_nothrow_constructible_v < T_j, T > )
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
Exécuter ce code
#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) |