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
所持可选项满足不抛出复制构造
或
不满足不抛出移动构造(分别由
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 - > operator = ( 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
。
- 若 * 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
,
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
,则此重载是平凡重载。
-
确定备选类型
T_j,该类型将通过重载决议为表达式 F ( std:: forward < T > ( t ) ) 选择,假设对于Types...中的每个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"; // 正确 std::variant<std::string, std::string> v2; v2 = "abc"; // 错误 std::variant <std::string, bool> v3; v3 = "abc"; // 正确,选择 string;bool 不是候选类型 std::variant<float, long, double> v4; // 持有 float v4 = 0; // 正确,持有 long;float 和 double 不是候选类型
目录 |
参数
| rhs | - |
另一个
variant
|
| t | - | 可转换为 variant 任一备选类型的值 |
返回值
* 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++ 标准。
| 缺陷报告 | 应用于 | 发布时的行为 | 正确行为 |
|---|---|---|---|
| LWG 3024 | C++17 |
若任何成员类型不可复制时
拷贝赋值运算符不参与重载决议 |
改为定义为删除状态 |
| LWG 3585 | C++17 |
由于没有可用的移动赋值操作
转换赋值有时意外地形成病式表达式 |
改为良构 |
| P0602R4 | C++17 |
即使底层操作是平凡的
拷贝/移动赋值可能不是平凡的 |
要求传播平凡性 |
| P0608R3 | C++17 |
转换赋值盲目组合重载集
导致非预期的转换 |
不考虑窄化和布尔转换 |
| P2231R1 | C++20 |
转换赋值
(
3
)
不是
constexpr
而在 C++20 中所需操作可以是 constexpr |
改为 constexpr |
参见
在
variant
中就地构造值
(公开成员函数) |