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++: ??