Namespaces
Variants

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

From cppreference.net
Utilities library
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) Copy-Zuweisung:
  • Wenn sowohl * this als auch rhs wertlos durch Exception sind, tut nichts.
  • Andernfalls, wenn rhs wertlos ist, aber * this nicht, zerstört den enthaltenen Wert in * this und macht ihn wertlos.
  • Andernfalls, wenn rhs die gleiche Alternative enthält wie * this , weist den in rhs enthaltenen Wert dem in * this enthaltenen Wert zu. Wenn eine Exception ausgelöst wird, wird * this nicht wertlos: der Wert hängt von der Exception-Sicherheitsgarantie der Copy-Zuweisung der Alternative ab.
  • Andernfalls, wenn die von rhs gehaltene Alternative entweder nothrow copy-konstruierbar oder nicht nothrow move-konstruierbar 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 eine Exception bei der Copy-Konstruktion innerhalb von emplace 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) Move-Zuweisung:
  • Wenn sowohl * this als auch rhs wertlos durch Exception sind, tut nichts.
  • Andernfalls, wenn rhs wertlos ist, aber * this nicht, zerstört den in * this enthaltenen Wert und macht ihn wertlos.
  • Andernfalls, wenn rhs dieselbe Alternative wie * this enthält, weist std :: move ( * std:: get_if < j > ( std:: addressof ( rhs ) ) ) dem in * this enthaltenen Wert zu, wobei j gleich index() ist. Wenn eine Exception ausgelöst wird, wird * this nicht wertlos: Der Wert hängt von der Exception-Sicherheitsgarantie der Move-Zuweisung der Alternative ab.
  • Andernfalls (wenn rhs und * this verschiedene Alternativen enthalten), äquivalent zu this - > emplace < rhs. index ( ) > ( std :: move ( * std:: get_if < rhs. index ( ) > ( std:: addressof ( rhs ) ) ) ) . Wenn eine Exception durch den Move-Konstruktor von T_i ausgelöst wird, wird * this zu valueless_by_exception .
Diese Überladung nimmt nur dann an der Überladungsauflösung teil, wenn std:: is_move_constructible_v < T_i > und std:: is_move_assignable_v < T_i > beide true für alle T_i in Types... 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 > alle true für alle T_i in Types... sind.
3) Converting assignment.
  • Bestimmt den alternativen Typ T_j der durch Überladungsauflösung für den Ausdruck F ( std:: forward < T > ( t ) ) ausgewählt würde, wenn es gleichzeitig Überladungen einer imaginären Funktion F ( T_i ) für jeden 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 dann an der Überladungsauflösung teil, wenn std:: decay_t < T > (bis C++20) std:: remove_cvref_t < T > (seit C++20) nicht derselbe Typ wie variant ist 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) wohlgeformt ist.

std::variant<std::string> v1;
v1 = "abc"; // OK
std::variant<std::string, std::string> v2;
v2 = "abc"; // Fehler
std::variant <std::string, bool> v3;
v3 = "abc"; // OK, wählt string; bool ist kein Kandidat
std::variant<float, long, double> v4; // enthält float
v4 = 0; // OK, enthält long; float und double sind keine Kandidaten

Inhaltsverzeichnis

Parameter

rhs - another variant
t - ein in eine der Varianten-Alternativen konvertierbarer Wert

Rückgabewert

* this

Exceptions

1) Kann jede Ausnahme werfen, die durch Zuweisung und Kopier-/Verschiebeinitialisierung 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:

Hinweise

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

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

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 Copy-Zuweisungsoperator nimmt nicht an der Überladungsauflösung teil
falls ein Mitgliedstyp nicht kopierbar ist
stattdessen als gelöscht definiert
LWG 3585 C++17 Konvertierungszuweisung war manchmal unerwartet ungültig
da keine Move-Zuweisung verfügbar war
als gültig gemacht
P0602R4 C++17 Copy-/Move-Zuweisung könnte nicht trivial sein
selbst wenn zugrundeliegende Operationen trivial sind
muss Trivialität propagieren
P0608R3 C++17 Konvertierungszuweisung stellt blind einen Überladungssatz zusammen,
was zu unbeabsichtigten Konvertierungen führt
Einschränkende und boolesche Konvertierungen
werden nicht berücksichtigt
P2231R1 C++20 Konvertierungszuweisung ( 3 ) war nicht constexpr
obwohl die erforderlichen Operationen in C++20 constexpr sein können
als constexpr gemacht

Siehe auch

Konstruiert einen Wert im variant , direkt vor Ort
(öffentliche Member-Funktion)