名稱空間
變體
操作

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

來自 cppreference.com
< cpp‎ | utility‎ | variant
 
 
 
 
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) 複製賦值
  • 如果 *thisrhs 都因異常而無值,則不執行任何操作。
  • 否則,如果 rhs 無值,但 *this 有值,則銷燬 *this 中包含的值並使其無值。
  • 否則,如果 rhs 包含的備選項與 *this 相同,則將 rhs 中包含的值賦給 *this 中包含的值。如果丟擲異常,*this 不會變為無值:值取決於備選項的複製賦值的異常安全保證。
  • 否則,如果 rhs 持有的備選項是 nothrow 複製可構造的,或者 不是 nothrow 移動可構造的(分別由 std::is_nothrow_copy_constructiblestd::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_istd::is_copy_constructible_v<T_i>std::is_copy_assignable_v<T_i> 都為 true,否則此過載被定義為刪除。如果 Types... 中所有 T_istd::is_trivially_copy_constructible_v<T_i>std::is_trivially_copy_assignable_v<T_i>std::is_trivially_destructible_v<T_i> 都為 true,則此過載是平凡的。
2) 移動賦值
  • 如果 *thisrhs 都因異常而無值,則不執行任何操作。
  • 否則,如果 rhs 無值,但 *this 有值,則銷燬 *this 中包含的值並使其無值。
  • 否則,如果 rhs 包含的備選項與 *this 相同,則將 std::move(*std::get_if<j>(std::addressof(rhs))) 賦給 *this 中包含的值,其中 jindex()。如果丟擲異常,*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_istd::is_move_constructible_v<T_i>std::is_move_assignable_v<T_i> 都為 true 時,此過載才參與過載決議。如果 Types... 中所有 T_istd::is_trivially_move_constructible_v<T_i>std::is_trivially_move_assignable_v<T_i>std::is_trivially_destructible_v<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)

僅當 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"; // 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>) && ...))
3)
noexcept 規範:  
noexcept(std::is_nothrow_assignable_v<T_j&, T> &&
         std::is_nothrow_constructible_v<T_j, T>)

[編輯] 注意

特性測試 標準 特性
__cpp_lib_variant 202106L (C++20)
(DR)
完全 constexprstd::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 中原地構造一個值
(公共成員函式) [編輯]