Namespaces
Variants

std::variant<Types...>::operator=

De fr.cppreference.net
 
 
Bibliothèque d'utilitaires
Support du langage
Support des types (types de base, RTTI)
Macros de test de fonctionnalités de la bibliothèque (C++20)
Utilitaires de programme
Fonctions variadiques
Support des coroutines (C++20)
Support des contrats (C++26)
Comparaison à trois voies
(C++20)
(C++20)(C++20)(C++20)    
(C++20)(C++20)(C++20)

Utilitaires généraux
Opérateurs relationnels (déprécié en C++20)
 
 
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 *this et rhs sont tous deux sans valeur par exception, ne fait rien.
  • Sinon, si rhs est sans valeur, mais pas *this, détruit la valeur contenue dans *this et le rend sans valeur.
  • Sinon, si rhs contient la même alternative que *this, assigne 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é d'exception de l'affectation par copie de l'alternative.
  • Sinon, si l'alternative contenue par rhs est 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))). *this peut devenir valueless_by_exception si une exception est levée lors de la construction par copie à l'intérieur de emplace.
  • 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 *this et rhs sont tous deux sans valeur par exception, ne fait rien.
  • Sinon, si rhs est sans valeur, mais pas *this, détruit la valeur contenue dans *this et le rend sans valeur.
  • Sinon, si rhs contient la même alternative que *this, assigne std::move(*std::get_if<j>(std::addressof(rhs))) à la valeur contenue dans *this, j étant index(). Si une exception est levée, *this ne 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 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 de déplacement de T_i, *this devient valueless_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_j qui serait sélectionné par la résolution de surcharge pour l'expression F(std::forward<T>(t)) s'il y avait une surcharge de la fonction imaginaire F(T_i) pour chaque T_i de Types... dans la portée au même moment, 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 ;
  • 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é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> est true, équivalent à this->emplace<j>(std::forward<T>(t)). *this peut devenir valueless_by_exception si une exception est levée lors de l'initialisation à l'intérieur de emplace.
  • 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 > ) && ... ) )
3)
noexcept spécification :

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)