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) :
Types...のすべての型Tiについて、is_move_constructible_v<Ti> && is_move_assignable_v<Ti>がtrueであること
- (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であること
- C++17 : ここで説明用に、
効果
- (1) :
*thisとrhsがどちらも値を保持していない場合、なにもしない*thisが値を保持し、rhsが保持していない場合、*thisが値を保持していない状態にするindex() == rhs.index()である場合、rhsが保持している値を*thisが保持する値としてコピー代入する (型の切り替えを行わない)rhs.index()をj、Types...の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) :
- (3) :
*thisがTj型の値を保持している場合、std::forward<T>(rhs)の値を*thisに代入する (型の切り替えを行わない)is_nothrow_constructible_v<Tj, T> || !is_nothrow_move_constructible_v<Tj>がtrueである場合、emplace<j>(std::forward<T>(rhs))の呼び出しと等価- いずれにも当てはまらない場合、
operator=(variant(std::forward<T>(rhs)))呼び出しと等価
戻り値
*this
事後条件
- (1), (2) :
index() == rhs.index() - (3) :
holds_alternative<Tj>(*this)がtrueであること
例外
- (2) :
noexcept演算子内部の式は、以下と等価となる:Types...のすべての型Tiについて、is_nothrow_move_constructible_v<Ti> && is_nothrow_move_assignable_v<Ti>
t.index()をj、Types...のj番目の型をTjとして、型Tjのムーブ構築中に例外が発生した場合、そのvariantオブジェクトは値を保持しない状態になるt.index()をj、Types...のj番目の型をTjとして、型Tjのムーブ代入中に例外が発生した場合、型Tjのムーブ代入演算子が保証する例外安全性が定義する値の保持状態となり、*thisのindex()はjとなる
- (3) :
noexcept演算子内部の式は、以下と等価となる:is_nothrow_assignable_v<Tj&, T> && is_nothrow_constructible_v<Tj, T>
- 値を保持する
*thisに対してstd::forward<T>(rhs)の代入中に例外が発生した場合、*thisが保持する値とrhsの値は、代入式の例外安全性が保証する状態となり、valueless_by_exception()はfalseとなる - 保持する値の初期化中に例外が発生した場合、
variantオブジェクトは値を保持しない可能性がある
トリビアルに定義される条件
- (1) :
Types...のすべての型Tiについて、is_trivially_copy_constructible_v<Ti> && is_trivially_copy_assignable_v<Ti> && is_trivially_destructible_v<Ti>がtrueであること - (2) :
Types...のすべての型Tiについて、is_trivially_move_constructible_v<Ti> && is_trivially_move_assignable_v<Ti> && is_trivially_destructible_v<Ti>がtrueであること
delete定義される条件
- (1) :
Types...のすべての型Tiについて、is_copy_constructible_v<Ti> && is_copy_assignable_v<Ti>がtrueでないこと
備考
- (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
処理系
- Clang: 4.0.1 ✅
- GCC: 7.3 ✅
- Visual C++: ??