# std::variant<Types...>::operator=

< cpp‎ | utility‎ | variant

constexpr variant& operator=( const variant& rhs ); | (1) | (C++17 起)
constexpr variant& operator=( variant&& rhs ) noexcept(/* see below */); | (2) | (C++17 起)
| (3) |
template< class T > variant& operator=( T&& t ) noexcept(/* see below */); |  | (C++17 起) (C++20 前)
template< class T > constexpr variant& operator=( T&& t ) noexcept(/* see below */); |  | (C++20 起)

给既存的 `variant` 对象赋新值。

1) 复制赋值：

- 若 *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()>(get<rhs.index()>(rhs)) 。若 `emplace` 内的复制构造抛异常，则 *this 可能变为因异常无值（ `valueless_by_exception` ）。
- 否则，等价于 this->operator=(variant(rhs)) 。

定义此重载为被删除，除非 std::is_copy_constructible_v<T_i> 与 std::is_copy_assignable_v<T_i> 对 `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 则此重载为平凡。
2) 移动赋值：

- 若 *this 与 `rhs` 均因异常无值，则不做任何事
- 否则，若 `rhs` 无值，但 *this 非无值，则销毁 *this 中所含值并使之无值
- 否则，若 `rhs` 保有与 *this 相同的可选项，则赋值 std::get<j>(std::move(rhs)) 给中所含值 *this ，其中 `j` 为 `index()` 。若抛出异常，则 *this 不变为无值：值依赖于可该选项的移动赋值的异常安全保证。
- 否则（若 `rhs` 与 *this 保有不同可选项），等价于 this->emplace<rhs.index()>(get<rhs.index()>(std::move(rhs))) 。若 `T_i` 的移动构造函数抛出异常，则 *this 变为因异常无值。

此重载仅若 `std::is_move_constructible_v<T_i>` 与 std::is_move_assignable_v<T_i> 对 `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 则此重载为平凡。
3) 转换赋值：

- 确定若有对每个来自 `Types...` 的 `T_i` 的虚构重载函数 F(T_i) 同时在作用域中，则重载决议是否为表达式 F(std::forward<T>(t)) 选择可选项类型 `T_j` ，除了：

  - 仅若声明 T_i x[] = { std::forward<T>(t) }; 对某个虚设变量 `x` 合法才考虑 F(T_i) ；
  - 若 `T_i` 是（可有 cv 限定的） bool ，则仅若 std:remove_cvref_t<T> 亦为 bool 才考虑 F(T_i) 。

- 若 *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 可能变为因异常无值。
- 否则，等价于 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<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 | - | 可转换成 `variant` 的可选项之一的值

### 返回值

*this

### 异常

1) 可能抛出任何可选项的赋值及复制/移动初始化所抛的异常。
2)
`noexcept` 说明：
noexcept(((std::is_nothrow_move_constructible_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>)

### 示例

    #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 | 若任何成员类型不可复制则复制赋值运算符不参与重载决议 | 改为定义为被删除
P0602R4 | C++17 | 即使底层操作平凡，复制/移动运算符亦可能不平凡 | 要求传播平凡性
P0608R3 | C++17 | 转换赋值盲目地组成重载集，导致不想要的转换 | 不考虑窄化和布尔转换
P2231R1 | C++20 | 转换赋值不是 constexpr 而要求的操作在 C++20 中可以是 | 使之为 constexpr
LWG 3585 | C++17 | 转换赋值有时意外地非良构，因为无可用的移动赋值 | 使之良构

### 参阅

emplace | 原位构造 `variant` 中的值 (公开成员函数)