Namensräume
Varianten
Aktionen

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

Von cppreference.com
< cpp‎ | utility‎ | variant
 
 
Dienstprogramm-Bibliotheken
Sprachunterstützung
Typunterstützung (Basistypen, RTTI)
Bibliotheks-Feature-Test-Makros (C++20)
Programm-Dienstprogramme
Variadische Funktionen
Coroutine-Unterstützung (C++20)
Vertragsunterstützung (C++26)
Drei-Wege-Vergleich
(C++20)
(C++20)(C++20)(C++20)  
(C++20)(C++20)(C++20)

Allgemeine Hilfsmittel
Relationale Operatoren (in C++20 veraltet)
 
 
constexpr variant& operator=( const variant& rhs );
(1) (seit C++17)
constexpr variant& operator=( variant&& rhs ) noexcept(/* siehe unten */);
(2) (seit C++17)
template< class T >
variant& operator=( T&& t ) noexcept(/* siehe unten */);
(3) (seit C++17)
(constexpr seit C++20)

Weist einem bestehenden variant-Objekt einen neuen Wert zu.

1) Kopierzuweisung
  • Wenn sowohl *this als auch rhs wertlos durch Ausnahme sind, tut dies nichts.
  • Andernfalls, wenn rhs wertlos ist, aber *this nicht, wird der in *this enthaltene Wert zerstört und dieser wird wertlos.
  • Andernfalls, wenn rhs dieselbe Alternative wie *this enthält, wird der in rhs enthaltene Wert dem in *this enthaltenen Wert zugewiesen. Wenn eine Ausnahme ausgelöst wird, wird *this nicht wertlos: Der Wert hängt von der Ausnahme-Sicherheitsgarantie der Kopierzuweisung der Alternative ab.
  • Andernfalls, wenn die von rhs gehaltene Alternative entweder nicht mit Ausnahme kopierkonstruierbar oder nicht nicht mit Ausnahme bewegungskonstruierbar ist (bestimmt durch std::is_nothrow_copy_constructible bzw. std::is_nothrow_move_constructible), äquivalent zu this->emplace<rhs.index()>(*std::get_if<rhs.index()>(std::addressof(rhs))). *this kann valueless_by_exception werden, wenn bei der Kopierkonstruktion innerhalb von emplace eine Ausnahme ausgelöst wird.
  • Andernfalls äquivalent zu this->operator=(variant(rhs)).
Diese Überladung ist als gelöscht definiert, es sei denn, std::is_copy_constructible_v<T_i> und std::is_copy_assignable_v<T_i> sind beide true für alle T_i in Types.... Diese Überladung ist trivial, wenn std::is_trivially_copy_constructible_v<T_i>, std::is_trivially_copy_assignable_v<T_i> und std::is_trivially_destructible_v<T_i> alle true für alle T_i in Types... sind.
2) Zuweisung durch Verschieben
  • Wenn sowohl *this als auch rhs wertlos durch Ausnahme sind, tut dies nichts.
  • Andernfalls, wenn rhs wertlos ist, aber *this nicht, wird der in *this enthaltene Wert zerstört und dieser wird wertlos.
  • Andernfalls, wenn rhs dieselbe Alternative wie *this enthält, wird std::move(*std::get_if<j>(std::addressof(rhs))) dem in *this enthaltenen Wert zugewiesen, wobei j index() ist. Wenn eine Ausnahme ausgelöst wird, wird *this nicht wertlos: Der Wert hängt von der Ausnahme-Sicherheitsgarantie der Zuweisung durch Verschieben der Alternative ab.
  • Andernfalls (wenn rhs und *this unterschiedliche Alternativen enthalten), äquivalent zu this->emplace<rhs.index()>(std::move(*std::get_if<rhs.index()>(std::addressof(rhs)))). Wenn durch den Move-Konstruktor von T_i eine Ausnahme ausgelöst wird, wird *this zu valueless_by_exception.
Diese Überladung nimmt nur an der Überladungsauflösung teil, wenn std::is_move_constructible_v<T_i> und std::is_move_assignable_v<T_i> für alle T_i in Types... beide true sind. Diese Überladung ist trivial, wenn std::is_trivially_move_constructible_v<T_i>, std::is_trivially_move_assignable_v<T_i> und std::is_trivially_destructible_v<T_i> für alle T_i in Types... alle true sind.
3) Konvertierende Zuweisung.
  • Bestimmt die alternative Art T_j, die durch Überladungsauflösung für den Ausdruck F(std::forward<T>(t)) ausgewählt würde, wenn es eine Überladung der imaginären Funktion F(T_i) für jedes T_i aus Types... im Gültigkeitsbereich gäbe, mit der Ausnahme, dass
  • Eine Überladung F(T_i) wird nur berücksichtigt, wenn die Deklaration T_i x[] = { std::forward<T>(t) }; für eine erfundene Variable x gültig ist.

Diese Überladung nimmt nur an der Überladungsauflösung teil, wenn std::decay_t<T>(bis C++20)std::remove_cvref_t<T>(seit C++20) nicht denselben Typ wie variant hat und std::is_assignable_v<T_j&, T> true ist und std::is_constructible_v<T_j, T> true ist und der Ausdruck F(std::forward<T>(t)) (wobei F die oben erwähnte Menge imaginärer Funktionen ist) gut geformt ist.

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

Inhalt

[edit] Parameter

rhs - ein anderer variant
t - ein Wert, der in eine der Alternativen des Variants konvertierbar ist

[edit] Rückgabewert

*this

[edit] Ausnahmen

1) Kann jede Ausnahme auslösen, die durch Zuweisung und Kopier-/Move-Initialisierung einer beliebigen Alternative ausgelöst wird.
2)
noexcept-Spezifikation:  
noexcept(((std::is_nothrow_move_constructible_v<Types> &&
           std::is_nothrow_move_assignable_v<Types>) && ...))
3)
noexcept-Spezifikation:  
noexcept(std::is_nothrow_assignable_v<T_j&, T> &&
         std::is_nothrow_constructible_v<T_j, T>)

[edit] Hinweise

Feature-Test-Makro Wert Std Feature
__cpp_lib_variant 202106L (C++20)
(DR)
Vollständig constexpr std::variant (3)

[edit] Beispiel

#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';
}

Mögliche Ausgabe

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: ""

[edit] Fehlerberichte

Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR angewendet auf Verhalten wie veröffentlicht Korrigiertes Verhalten
LWG 3024 C++17 Kopierzuweisungsoperator nimmt nicht an der Überladungsauflösung teil
wenn irgendein Mitgliedstyp nicht kopierbar ist
wird stattdessen als gelöscht definiert
LWG 3585 C++17 Konvertierende Zuweisung war manchmal unerwartet schlecht geformt
weil keine Move-Zuweisung verfügbar war
wurde wohlgeformt gemacht
P0602R4 C++17 Kopie-/Move-Zuweisung ist möglicherweise nicht trivial
auch wenn die zugrunde liegenden Operationen trivial sind
erforderlich, um Trivialität zu propagieren
P0608R3 C++17 Konvertierende Zuweisung fügt blind einen Überladungssatz zusammen,
was zu unbeabsichtigten Konvertierungen führt
Verengungs- und boolesche Konvertierungen
nicht betrachtet
P2231R1 C++20 konvertierende Zuweisung (3) war nicht constexpr
während die erforderlichen Operationen in C++20 constexpr sein können
zu constexpr gemacht

[edit] Siehe auch

erstellt einen Wert im variant, in situ
(public member function) [edit]