最終更新日時(UTC):
が更新

履歴 編集

function
<variant>

std::variant::operator=(C++17)

constexpr variant& operator=(const variant& rhs);              // (1)
constexpr variant& operator=(variant&& t) noexcept(see below); // (2)

template <class T>
variant& operator=(T&& rhs) noexcept(see below);               // (3) C++17
template <class T>
constexpr variant& operator=(T&& rhs) noexcept(see below);     // (3) C++23

概要

variantオブジェクトもしくは候補型の値を代入する。

  • (1) : コピー代入演算子
  • (2) : ムーブ代入演算子
  • (3) : クラスのテンプレート引数で指定した候補型のうち、いずれかの型の値を代入する

テンプレートパラメータ制約

  • (2) :
  • (3) :
    • C++17 : ここで説明用に、*thisが保持している型Tjと、そのインデックス値jを定義する。Types...の各型Tiに対して擬似的な関数FUN(Ti)を定義したとして、FUN(std::forward<T>(t))呼び出しによって選択されたオーバーロードされた関数のパラメータ型を、代入してその後含まれる値の型をTjとする
    • C++20 : ここで説明用に、*thisが保持している型Tjと、そのインデックス値jを定義する。Types...の各型Tiを、縮小変換を受け付けない型であり (Ti x[] = {std::forward<T>(t)};)、CV修飾付きboolの場合にCV修飾を外したbool型になるとして、その型に対して擬似的な関数FUN(Ti)を定義したとして、FUN(std::forward<T>(t))呼び出しによって選択されたオーバーロードされた関数のパラメータ型を、代入してその後含まれる値の型をTjとする
    • is_same_v<decay_t<T>, variant>falseであること
    • is_assignable_v<Tj&, T> && is_constructible_v<Tj, T>trueであること

効果

  • (1) :
    • *thisrhsがどちらも値を保持していない場合、なにもしない
    • *thisが値を保持し、rhsが保持していない場合、*thisが値を保持していない状態にする
    • index() == rhs.index()である場合、rhsが保持している値を*thisが保持する値としてコピー代入する (型の切り替えを行わない)
    • rhs.index()jTypes...j番目の型をTjとして、is_nothrow_copy_constructible_v<Tj> == trueもしくはis_nothrow_move_constructible_v<Tj> == falseである場合、emplace<j>(get<j>(rhs))と等価
    • いずれにも当てはまらない場合、operator=(variant(rhs))と等価
  • (2) :
    • *thistがどちらも値を保持していない場合、なにもしない
    • *thisが値を保持し、tが保持していない場合、*thisが値を保持していない状態にする
    • index() == t.index()である場合、tが保持している値を*thisが保持する値としてムーブ代入する (型の切り替えを行わない)
    • いずれにも当てはまらない場合、t.index()jとして、emplace<j>(get<j>(std::move(t)))と等価
  • (3) :

戻り値

*this

事後条件

例外

  • (2) :
    • noexcept演算子内部の式は、以下と等価となる:
    • t.index()jTypes...j番目の型をTjとして、型Tjのムーブ構築中に例外が発生した場合、そのvariantオブジェクトは値を保持しない状態になる
    • t.index()jTypes...j番目の型をTjとして、型Tjのムーブ代入中に例外が発生した場合、型Tjのムーブ代入演算子が保証する例外安全性が定義する値の保持状態となり、*thisindex()jとなる
  • (3) :
    • noexcept演算子内部の式は、以下と等価となる:
    • 値を保持する*thisに対してstd::forward<T>(rhs)の代入中に例外が発生した場合、*thisが保持する値とrhsの値は、代入式の例外安全性が保証する状態となり、valueless_by_exception()falseとなる
    • 保持する値の初期化中に例外が発生した場合、variantオブジェクトは値を保持しない可能性がある

トリビアルに定義される条件

delete定義される条件

備考

  • (3) : 以下のコードは不適格となる。第1テンプレート引数の型をとるコンストラクタオーバーロードと、第2テンプレート引数の型をとるコンストラクタオーバーロードが定義されるため、曖昧になる:
    std::variant<std::string, std::string> v;
    v = "abc"; // コンパイルエラー!
    

基本的な使い方

#include <cassert>
#include <variant>

int main()
{
  // (1) コピー代入
  {
    std::variant<int, char, double> v1 = 1;
    std::variant<int, char, double> v2;
    v2 = v1;

    assert(std::holds_alternative<int>(v1));
    assert(std::holds_alternative<int>(v2));
    assert(std::get<int>(v1) == 1);
    assert(std::get<int>(v2) == 1);
  }

  // (2) ムーブ代入
  {
    std::variant<int, char, double> v1 = 1;
    std::variant<int, char, double> v2;
    v2 = std::move(v1);

    assert(std::holds_alternative<int>(v2));
    assert(std::get<int>(v2) == 1);
  }

  // (3) 型と値の切り替え
  {
    std::variant<int, char, double> v = 1;

    // 値を更新
    v = 2;

    // 保持する型を切り替え
    v = 'a';

    assert(std::holds_alternative<char>(v));
    assert(std::get<char>(v) == 'a');
  }
}

出力

あいまいになりそうな代入の例 (C++20)

#include <cassert>
#include <variant>
#include <string>

int main()
{
  // 縮小変換 (narrowing conversion) は行われないので、
  // 0がfloat型に代入されたりはしない
  {
    std::variant<float, int> v;
    v = 0;
    assert(std::holds_alternative<int>(v));
  }

  {
    // 文字列リテラルは、C++17ではstd::stringよりもboolに優先的に変換されてしまう
    std::variant<std::string, bool> v;
    v = "abc";
    assert(std::holds_alternative<std::string>(v)); // C++17ではbool、C++20ではstd::string

    std::variant<std::string> v2;
    v2 = "abc";
    assert(std::holds_alternative<std::string>(v2));

    std::variant<std::string, bool> v3;
    v3 = std::string("abc"); // C++17/C++20でstd::string
    assert(std::holds_alternative<std::string>(v3));
  }
}

出力

バージョン

言語

  • C++17

処理系

参照