名前空間
変種
操作

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

From cppreference.com
< cpp‎ | utility‎ | variant
 
 
ユーティリティライブラリ
言語サポート
型のサポート (基本型、RTTI)
ライブラリ機能検査マクロ (C++20)
プログラムユーティリティ
可変引数関数
コルーチンサポート (C++20)
契約サポート (C++26)
三方比較
(C++20)
(C++20)(C++20)(C++20)  
(C++20)(C++20)(C++20)

汎用ユーティリティ
関係演算子 (C++20で非推奨)
 
 
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が保持する代替型が、例外なしでコピー構築可能であるか、または例外なしでムーブ構築可能でない(それぞれstd::is_nothrow_copy_constructibleおよびstd::is_nothrow_move_constructibleによって決定される)場合、this->emplace<rhs.index()>(*std::get_if<rhs.index()>(std::addressof(rhs)))と同等です。emplace内のコピー構築で例外がスローされた場合、*thisvalueless_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) ムーブ代入
  • *thisrhsの両方が例外により無価値な場合、何も行いません。
  • それ以外の場合で、rhsが無価値だが*thisが無価値でない場合、*thisが保持する値を破棄し、無価値にします。
  • それ以外の場合で、rhs*thisと同じ代替型を保持している場合、jindex()として、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のムーブコンストラクタによって例外がスローされた場合、*thisvalueless_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内の初期化で例外がスローされた場合、*thisvalueless_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>) && ...))
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)
完全な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) [編集]
English 日本語 中文(简体) 中文(繁體)