From cppreference.com
constexprvariant&operator=(constvariant&rhs); (1) (since C++17)constexprvariant&operator=(variant&&rhs)noexcept(/* see below */); (2) (since C++17)template<classT>variant&operator=(T&&t)noexcept(/* see below */); (3)(since C++17)
(constexpr since C++20)Assigns a new value to an existing variant object.
1) Copy-assignment:
If both *this and rhs are valueless by exception, does nothing.
Otherwise, if rhs is valueless, but *this is not, destroys the value contained in *this and makes it valueless.
Otherwise, if rhs holds the same alternative as *this, assigns the value contained in rhs to the value contained in *this. If an exception is thrown, *this does not become valueless: the value depends on the exception safety guarantee of the alternative's copy assignment.
Otherwise, if the alternative held by rhs is either nothrow copy constructible or not nothrow move constructible (as determined by
std::is_nothrow_copy_constructible
and
std::is_nothrow_move_constructible
, respectively), equivalent to this->emplace<rhs.index()>(*std::get_if<rhs.index()>(std::addressof(rhs))). *this may become
if an exception is thrown on the copy-construction inside
.
Otherwise, equivalent to this->operator=(variant(rhs)).
This overload is defined as deleted unless std::is_copy_constructible_v<T_i> and std::is_copy_assignable_v<T_i> are both true for all T_i in Types.... This overload is trivial if std::is_trivially_copy_constructible_v<T_i>,std::is_trivially_copy_assignable_v<T_i> and std::is_trivially_destructible_v<T_i> are all true for all T_i in Types....
2) Move-assignment:
If both *this and rhs are valueless by exception, does nothing.
Otherwise, if rhs is valueless, but *this is not, destroys the value contained in *this and makes it valueless.
Otherwise, if rhs holds the same alternative as *this, assigns std::move(*std::get_if<j>(std::addressof(rhs))) to the value contained in *this, with j being index(). If an exception is thrown, *this does not become valueless: the value depends on the exception safety guarantee of the alternative's move assignment.
Otherwise (if rhs and *this hold different alternatives), equivalent to this->emplace<rhs.index()>(std::move(*std::get_if<rhs.index()>(std::addressof(rhs)))). If an exception is thrown by T_i's move constructor, *this becomes
.
This overload participates in overload resolution only if std::is_move_constructible_v<T_i> and std::is_move_assignable_v<T_i> are both true for all T_i in Types.... This overload is trivial if std::is_trivially_move_constructible_v<T_i>, std::is_trivially_move_assignable_v<T_i>, and std::is_trivially_destructible_v<T_i> are all true for all T_i in Types....
3) Converting assignment.
Determines the alternative type T_j that would be selected by overload resolution for the expression F(std::forward<T>(t)) if there was an overload of imaginary function F(T_i) for every T_i from Types... in scope at the same time, except that:
An overload F(T_i) is only considered if the declaration T_ix[]={std::forward<T>(t)}; is valid for some invented variable x;
If *this already holds a T_j, assigns std::forward<T>(t) to the value contained in *this. If an exception is thrown, *this does not become valueless: the value depends on the exception safety guarantee of the assignment called.
Otherwise, if std::is_nothrow_constructible_v<T_j,T>||!std::is_nothrow_move_constructible_v<T_j> is true, equivalent to this->emplace<j>(std::forward<T>(t)). *this may become
if an exception is thrown on the initialization inside
.
Otherwise, equivalent to this->emplace<j>(T_j(std::forward<T>(t))).
This overload participates in overload resolution only if std::decay_t<T>(until C++20)std::remove_cvref_t<T>(since C++20) is not the same type as
and std::is_assignable_v<T_j&,T> is true and std::is_constructible_v<T_j,T> is true and the expression F(std::forward<T>(t)) (with F being the above-mentioned set of imaginary functions) is well formed.
std::variant<std::string>v1;v1="abc";// OKstd::variant<std::string,std::string>v2;v2="abc";// Errorstd::variant<std::string,bool>v3;v3="abc";// OK, chooses string; bool is not a candidatestd::variant<float,long,double>v4;// holds floatv4=0;// OK, holds long; float and double are not candidatesParameters
rhs - another variantt - a value convertible to one of the variant's alternatives Return value
*this
Exceptions
1) May throw any exception thrown by assignment and copy/move initialization of any alternative.
2)
specification:
noexcept(((std::is_nothrow_move_constructible_v<Types>&&std::is_nothrow_move_assignable_v<Types>)&&...))3)
specification:
noexcept(std::is_nothrow_assignable_v<T_j&,T>&&std::is_nothrow_constructible_v<T_j,T>)Notes
macro ValueStdFeature
(C++20)
(DR)Fully constexprstd::variant(
)Example
Run this code
#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){usingT=std::decay_t<decltype(arg)>;ifconstexpr(std::is_same_v<T,int>)os<<arg;elseifconstexpr(std::is_same_v<T,std::string>)os<<std::quoted(arg);},va);returnos<<" };\n";}intmain(){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::strings{"CppNow"};std::cout<<"s: "<<std::quoted(s)<<'\n';a=std::move(s);std::cout<<"a"<<a<<"s: "<<std::quoted(s)<<'\n';}Possible output:
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: "" Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR Applied to Behavior as published Correct behavior
C++17 copy assignment operator doesn't participate in overload resolution
if any member type is not copyable defined as deleted instead
C++17 converting assignment was sometimes unexpectedly ill-formed
because there was no available move assignment made well-formed
C++17 copy/move assignment may not be trivial
even if underlying operations are trivial required to propagate triviality
C++17 converting assignment blindly assembles an overload set,
leading to unintended conversions narrowing and boolean conversions
not considered
C++20 converting assignment (
) was not constexpr
while the required operations can be constexpr in C++20 made constexprSee also
constructs a value in the variant, in place
(public member function)