std::variant<Types...>:: operator=
|
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
オブジェクトに新しい値を割り当てます。
- * 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 ) ) と等価。
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
である場合、自明となります。
- * 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状態になる。
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)となります。
-
代替型
T_jを決定します。これは、以下の式に対するオーバーロード解決によって選択される型です: F ( std:: forward < T > ( t ) ) ただし、以下の仮定のもとで:すべてのT_iに対してTypes...から仮想関数 F ( T_i ) のオーバーロードが同じスコープに同時に存在する場合を想定します。ただし以下の例外を除きます:
-
-
オーバーロード
F
(
T_i
)
は、宣言
T_i x
[
]
=
{
std::
forward
<
T
>
(
t
)
}
;
が何らかの仮想的な変数
xに対して有効である場合にのみ考慮される;
-
オーバーロード
F
(
T_i
)
は、宣言
T_i x
[
]
=
{
std::
forward
<
T
>
(
t
)
}
;
が何らかの仮想的な変数
-
*
this
が既に
T_jを保持している場合、 std:: forward < T > ( t ) を * this に含まれる値に代入する。例外が発生した場合、 * 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
(
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
例外
std:: is_nothrow_move_assignable_v < Types > ) && ... ) )
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 |
コピー代入演算子がオーバーロード解決に参加しない
メンバー型がコピー可能でない場合 |
代わりに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内に値をその場で構築する
(公開メンバ関数) |