Namespaces
Variants

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

cppreference.net에서 가져옴
 
 
유틸리티 라이브러리
일반 유틸리티
관계 연산자 (C++20에서 폐지)
정수 비교 함수
(C++20)(C++20)(C++20)    
(C++20)
Swap 및 타입 연산
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
공통 어휘 타입
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)



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

기존 variant 객체에 새 값을 할당합니다.

1) 복사 할당:
  • *this와 rhs가 모두 예외로 인해 값이 없으면 아무것도 하지 않습니다.
  • 그렇지 않고, rhs가 값이 없지만 *this가 값이 있으면, *this에 포함된 값을 파괴하고 값이 없도록 만듭니다.
  • 그렇지 않고, rhs가 *this와 같은 대안을 보유하면, rhs에 포함된 값을 *this에 포함된 값에 할당합니다. 예외가 발생하면 *this는 값이 없게 되지 않습니다: 값은 대안의 복사 할당에 대한 예외 안전성 보장에 따라 달라집니다.
  • 그렇지 않고, rhs가 보유한 대안이 nothrow 복사 생성 가능하거나 not 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))와 동일합니다.
이 오버로드는 std::is_copy_constructible_v<T_i>과 std::is_copy_assignable_v<T_i>가 모두 true 안의 모든 T_i에 대해 Types...인 경우에만 삭제된 것으로 정의됩니다. 이 오버로드는 std::is_trivially_copy_constructible_v<T_i>,std::is_trivially_copy_assignable_v<T_i> 및 std::is_trivially_destructible_v<T_i>가 모두 true 안의 모든 T_i에 대해 Types...인 경우 사소합니다.
2) 이동 할당:
  • *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가 됩니다.
이 오버로드는 std::is_move_constructible_v<T_i>과 std::is_move_assignable_v<T_i>가 모두 true 안의 모든 T_i에 대해 Types...인 경우에만 오버로드 해결에 참여합니다. 이 오버로드는 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_i에 대해 Types...인 경우 사소합니다.
3) 변환 할당.
  • 다음을 제외하고, 동시에 T_j로부터의 모든 F(std::forward<T>(t))에 대해 가상 함수 F(T_i)의 오버로드가 있다면 표현식 T_i에 대해 오버로드 해결에 의해 선택될 대안 타입 Types...를 결정합니다:
  • 선언 F(T_i)이 어떤 발명된 변수 T_i x[] = { std::forward<T>(t) };에 대해 유효한 경우에만 오버로드 x가 고려됩니다;
  • *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))와 동일합니다. *this는 valueless_by_exception 내부 초기화 중 예외가 발생하면 emplace이 될 수 있습니다.
  • 그렇지 않으면 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"; // 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 - another variant
t - variant의 대안 중 하나로 변환 가능한 값

반환값

* this

예외

1) 대안(alternative)의 할당 및 복사/이동 초기화에서 발생하는 모든 예외를 던질 수 있습니다.
2)
noexcept 명세:
noexcept ( ( ( std:: is_nothrow_move_constructible_v < Types > &&
std:: is_nothrow_move_assignable_v < Types > ) && ... ) )
3)

참고 사항

기능 테스트 매크로 값 표준 기능
__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였음
사용 가능한 이동 할당이 없었기 때문
well-formed로 변경됨
P0602R4 C++17 복사/이동 할당이 trivial하지 않을 수 있음
기본 연산들이 trivial한 경우에도
triviality 전파 요구됨
P0608R3 C++17 변환 할당이 무분별하게 오버로드 집합을 구성하여
의도하지 않은 변환으로 이어짐
축소 변환과 불린 변환
고려되지 않음
P2231R1 C++20 변환 할당 ( 3 ) 가 constexpr 이 아니었음
필요한 연산들이 C++20에서 constexpr 이 될 수 있음에도
constexpr 으로 변경됨

참고 항목

variant 내에 값을 직접 생성
(public member function)