Namespaces
Variants

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

From cppreference.net
Utilities library
constexpr variant & operator = ( const variant & rhs ) ;
(1) (C++17以降)
constexpr variant & operator = ( variant && rhs ) noexcept ( /* 下記参照 */ ) ;
(2) (C++17以降)
template < class T >
variant & operator = ( T && t ) noexcept ( /* 下記参照 */ ) ;
(3) (C++17以降)
(C++20以降 constexpr)

既存の variant オブジェクトに新しい値を割り当てます。

1) コピー代入:
  • * this rhs の両方が例外によって値を持たない状態の場合、何も行わない。
  • それ以外の場合、 rhs が値を持たず、 * this が値を持つ場合、 * this に含まれる値を破棄し、値を持たない状態にする。
  • それ以外の場合、 rhs * this と同じ代替型を保持している場合、 rhs に含まれる値を * this に含まれる値に代入する。例外がスローされた場合、 * this は値を持たない状態にはならない: 値は代替型のコピー代入の例外安全性保証に依存する。
  • それ以外の場合、 rhs が保持する代替型がnothrowコピー構築可能であるか、 または nothrowムーブ構築可能でない場合(それぞれ std::is_nothrow_copy_constructible std::is_nothrow_move_constructible によって判定される)、 this - > emplace < rhs. index ( ) > ( * std:: get_if < rhs. index ( ) > ( std:: addressof ( rhs ) ) ) と等価。 * this valueless_by_exception になる可能性がある( emplace 内部でのコピー構築中に例外がスローされた場合)。
  • それ以外の場合、 this - > operator = ( variant ( rhs ) ) と等価。
このオーバーロードは、 std:: is_copy_constructible_v < T_i > および std:: is_copy_assignable_v < T_i > Types... 内のすべての T_i に対して両方とも true である場合を除き、削除済みとして定義されます。このオーバーロードは、 std:: is_trivially_copy_constructible_v < T_i > std:: is_trivially_copy_assignable_v < T_i > および std:: is_trivially_destructible_v < T_i > Types... 内のすべての T_i に対してすべて true である場合、自明となります。
2) ムーブ代入:
  • * this rhs の両方が例外によって値を持たない状態の場合、何も行わない。
  • それ以外の場合、 rhs が値を持たず、 * this が値を持つ場合、 * this に含まれる値を破棄し、値を持たない状態にする。
  • それ以外の場合、 rhs * this と同じ代替型を保持している場合、 std :: move ( * std:: get_if < j > ( std:: addressof ( rhs ) ) ) * this に含まれる値に代入する( j index() の値)。例外がスローされた場合、 * this は値を持たない状態にはならない:値は代替型のムーブ代入の例外安全性保証に依存する。
  • それ以外の場合( rhs * this が異なる代替型を保持している場合)、 this - > emplace < rhs. index ( ) > ( std :: move ( * std:: get_if < rhs. index ( ) > ( std:: addressof ( rhs ) ) ) ) と等価。 T_i のムーブコンストラクタによって例外がスローされた場合、 * this valueless_by_exception 状態になる。
このオーバーロードは、 std:: is_move_constructible_v < T_i > および std:: is_move_assignable_v < T_i > Types... 内のすべての T_i に対して true である場合にのみ、オーバーロード解決に参加します。このオーバーロードは、 std:: is_trivially_move_constructible_v < T_i > std:: is_trivially_move_assignable_v < T_i > 、および std:: is_trivially_destructible_v < T_i > Types... 内のすべての T_i に対して true である場合に、自明(trivial)となります。
3) Converting assignment.
  • 代替型 T_j を決定します。これは、以下の式に対するオーバーロード解決によって選択される型です: F ( std:: forward < T > ( t ) ) ただし、以下の仮定のもとで:すべての T_i に対して Types... から仮想関数 F ( T_i ) のオーバーロードが同じスコープに同時に存在する場合を想定します。ただし以下の例外を除きます:
  • オーバーロード F ( T_i ) は、宣言 T_i x [ ] = { std:: forward < T > ( t ) } ; が何らかの仮想的な変数 x に対して有効である場合にのみ考慮される;

このオーバーロードは、以下の条件を満たす場合にのみオーバーロード解決に参加します: std:: decay_t < T > (C++20まで) std:: remove_cvref_t < T > (C++20以降) variant と同じ型ではなく、かつ std:: is_assignable_v < T_j & , T > true であり、かつ std:: is_constructible_v < T_j, T > true であり、かつ式 F ( std:: forward < T > ( t ) ) (Fは前述の仮想関数の集合)が整形式である場合です。

std::variant<std::string> v1;
v1 = "abc"; // OK
std::variant<std::string, std::string> v2;
v2 = "abc"; // エラー
std::variant <std::string, bool> v3;
v3 = "abc"; // OK、stringを選択;boolは候補ではない
std::variant<float, long, double> v4; // floatを保持
v4 = 0; // OK、longを保持;floatとdoubleは候補ではない

目次

パラメータ

rhs - 別の variant
t - バリアントの代替型のいずれかに変換可能な値

戻り値

* this

例外

1) 任意の代替案の代入およびコピー/ムーブ初期化によってスローされる例外をスローする可能性があります。
2)
noexcept noexcept指定:
noexcept ( ( ( std:: is_nothrow_move_constructible_v < Types > &&
std:: is_nothrow_move_assignable_v < Types > ) && ... ) )
3)
noexcept specification:

注記

機能テスト マクロ 標準 機能
__cpp_lib_variant 202106L (C++20)
(DR)
完全な constexpr std::variant ( 3 )

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

出力例:

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

欠陥報告

以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。

DR 適用対象 公開時の動作 正しい動作
LWG 3024 C++17 コピー代入演算子がオーバーロード解決に参加しない
メンバー型がコピー可能でない場合
代わりにdelete定義される
LWG 3585 C++17 変換代入が予期せずill-formedになる場合があった
利用可能なムーブ代入が存在しないため
well-formedとなる
P0602R4 C++17 コピー/ムーブ代入がtrivialにならない場合がある
基盤となる操作がtrivialであっても
trivial性の伝播が要求される
P0608R3 C++17 変換代入が盲目的にオーバーロードセットを組み立て、
意図しない変換を引き起こす
縮小変換とブール変換は
考慮されない
P2231R1 C++20 変換代入 ( 3 ) constexpr ではなかった
必要な操作がC++20で constexpr 化可能であるにもかかわらず
constexpr 化される

関連項目

variant内に値をその場で構築する
(公開メンバ関数)