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
가 보유한 대체 타입이 nothrow 복사 생성 가능하거나
아니면
nothrow 이동 생성 가능하지 않은 경우(각각
std::is_nothrow_copy_constructible
와
std::is_nothrow_move_constructible
로 결정됨),
this
-
>
emplace
<
rhs.
index
(
)
>
(
*
std::
get_if
<
rhs.
index
(
)
>
(
std::
addressof
(
rhs
)
)
)
와 동일합니다.
*
this
는
emplace내부의 복사 생성에서 예외가 발생하면valueless_by_exception이 될 수 있습니다. - 그렇지 않으면 this - > operator = ( variant ( rhs ) ) 와 동일합니다.
- 만약 * 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가 됩니다.
-
오버로드 해결이 다음 표현식에 대해 선택할 대체 타입
T_j를 결정합니다: F ( std:: forward < T > ( t ) ) 단, 다음과 같은 가정 하에: 모든T_i에 대해 가상 함수 F ( T_i ) 의 오버로드가Types...내의 각 타입에 대해 동시에 스코프 내에 존재한다고 가정합니다. 단, 다음 예외 사항이 적용됩니다:
-
-
오버로드
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
)
)
와 동등합니다.
*
this
는
emplace내부 초기화 과정에서 예외가 발생하면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 | - |
another
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++ 표준에 소급 적용되었습니다.
| 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) |