Namespaces
Variants

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

From cppreference.net
Utilities library
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.

1) Copie par affectation :
  • 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_exception si une exception est levée lors de la construction par copie dans 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 tous les 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... .
2) Affectation par déplacement :
  • 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 étant index() . 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 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 tous les 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... .
3) Converting assignment.
  • 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 existait une surcharge de la fonction imaginaire F ( T_i ) pour chaque T_i de Types... 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 ;

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

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)