std::variant<Types...>::operator=
From cppreference.com
| 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が保持する代替型が、例外なしでコピー構築可能であるか、または例外なしでムーブ構築可能でない(それぞれstd::is_nothrow_copy_constructibleおよびstd::is_nothrow_move_constructibleによって決定される)場合、this->emplace<rhs.index()>(*std::get_if<rhs.index()>(std::addressof(rhs)))と同等です。emplace内のコピー構築で例外がスローされた場合、*thisはvalueless_by_exceptionになることがあります。 - それ以外の場合、
*this = variant(rhs)と同等です。
このオーバーロードは、
Types...のすべてのT_iに対してstd::is_copy_constructible_v<T_i>とstd::is_copy_assignable_v<T_i>が両方ともtrueである場合を除き、削除されたものとして定義されます。Types...のすべてのT_iに対してstd::is_trivially_copy_constructible_v<T_i>、std::is_trivially_copy_assignable_v<T_i>、およびstd::is_trivially_destructible_v<T_i>がすべてtrueである場合、このオーバーロードは自明です。2) ムーブ代入
*thisとrhsの両方が例外により無価値な場合、何も行いません。- それ以外の場合で、
rhsが無価値だが*thisが無価値でない場合、*thisが保持する値を破棄し、無価値にします。 - それ以外の場合で、
rhsが*thisと同じ代替型を保持している場合、jをindex()として、std::move(*std::get_if<j>(std::addressof(rhs)))を*thisが保持する値に代入します。例外がスローされた場合、*thisは無価値になりません。値は、代替型のムーブ代入の例外安全保証に依存します。 - それ以外の場合(
rhsと*thisが異なる代替型を保持している場合)、this->emplace<rhs.index()>(std::move(*std::get_if<rhs.index()>(std::addressof(rhs)))))と同等です。T_iのムーブコンストラクタによって例外がスローされた場合、*thisはvalueless_by_exceptionになります。
このオーバーロードは、
Types...のすべてのT_iに対してstd::is_move_constructible_v<T_i>とstd::is_move_assignable_v<T_i>が両方ともtrueである場合にのみ、オーバーロード解決に参加します。Types...のすべてのT_iに対してstd::is_trivially_move_constructible_v<T_i>、std::is_trivially_move_assignable_v<T_i>、およびstd::is_trivially_destructible_v<T_i>がすべてtrueである場合、このオーバーロードは自明です。3) 変換代入。
- オーバーロード解決によって選択される代替型
T_jを決定します。これは、すべてのTypes...からのT_iに対してF(T_i)のオーバーロードを持つ仮想関数F(std::forward<T>(t))の式に対して行われますが、ただし、
T_i x[] = { std::forward<T>(t) };という宣言が、ある仮想変数xに対して有効である場合のみ、F(T_i)のオーバーロードが考慮されます。
*thisがすでにT_jを保持している場合、*thisが保持する値にstd::forward<T>(t)を代入します。例外がスローされた場合、*thisは無価値になりません。値は、代入操作の例外安全保証に依存します。- それ以外の場合で、
std::is_nothrow_constructible_v<T_j, T> || !std::is_nothrow_move_constructible_v<T_j>がtrueである場合、this->emplace<j>(std::forward<T>(t))と同等です。emplace内の初期化で例外がスローされた場合、*thisはvalueless_by_exceptionになることがあります。 - それ以外の場合、
this->emplace<j>(T_j(std::forward<T>(t)))と同等です。
このオーバーロードは、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でのF(std::forward<T>(t))という式がwell-formedである場合にのみ、オーバーロード解決に参加します。
std::variant<std::string> v1; v1 = "abc"; // OK std::variant<std::string, std::string> v2; v2 = "abc"; // Error std::variant <std::string, bool> v3; v3 = "abc"; // OK, chooses string; bool is not a candidate std::variant<float, long, double> v4; // holds float v4 = 0; // OK, holds long; float and double are not candidates
目次 |
[編集] パラメータ
| rhs | - | 別のvariant |
| t | - | variantの代替型に変換可能な値 |
[編集] 戻り値
*this
[編集] 例外
1) 代替型の任意の代入およびコピー/ムーブ初期化によってスローされる可能性のある例外をスローすることがあります。
2)
noexcept 指定:
noexcept(((std::is_nothrow_move_constructible_v<Types> &&
std::is_nothrow_move_assignable_v<Types>) && ...))
std::is_nothrow_move_assignable_v<Types>) && ...))
3)
noexcept 指定:
noexcept(std::is_nothrow_assignable_v<T_j&, T> &&
std::is_nothrow_constructible_v<T_j, T>)
std::is_nothrow_constructible_v<T_j, T>)
[編集] ノート
| 機能テストマクロ | 値 | 規格 | 機能 |
|---|---|---|---|
__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 | コピー代入演算子がオーバーロード解決に参加しない いずれかのメンバ型がコピー可能でない場合 |
代わりに削除される |
| LWG 3585 | C++17 | 変換代入が予期せずill-formedになることがあった 利用可能なムーブ代入がなかったため |
適切な形式になった |
| P0602R4 | C++17 | コピー/ムーブ代入は自明でない場合がある 基になる操作が自明であっても |
自明性の伝播が必要です。 |
| P0608R3 | C++17 | 変換代入が単純にオーバーロードセットを組み立てる 意図しない変換につながる |
ナローイングおよびブール変換 考慮されなかった |
| P2231R1 | C++20 | 変換代入(3)はconstexprではなかったC++20では、必要な操作は constexprにできるのに |
constexprではありませんでした。 |
[編集] 関連項目
variant内に値を構築します。インプレースで。(public member function) |