Пространства имён
Варианты
Действия

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

Материал из cppreference.com
< cpp‎ | utility‎ | variant
 
 
Библиотека утилит
Языковая поддержка
Поддержка типов (базовые типы, RTTI)
Макросы тестирования функциональности библиотеки (C++20)    
Управление динамической памятью
Программные утилиты
Поддержка сопрограмм(C++20)
Вариативные функции
Трёхстороннее сравнение (C++20)
(C++20)
(C++20)(C++20)(C++20)(C++20)(C++20)(C++20)
Общие утилиты
Дата и время
Функциональные объекты
Библиотека форматирования(C++20)
(C++11)
Операторы отношения (устарело в C++20)
Целочисленные функции сравнения
(C++20)(C++20)(C++20)    
(C++20)
Операции обмена и типа
(C++11)
(C++11)
(C++17)
Общие лексические типы
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)
Элементарные преобразования строк
(C++17)
(C++17)
 
 
constexpr variant& operator=(const variant& rhs );
(1) (начиная с C++17)
constexpr variant& operator=( variant&& rhs )noexcept(/* смотрите ниже */);
(2) (начиная с C++17)
(3)
template<class T >
variant& operator=( T&& t )noexcept(/* смотрите ниже */);
(начиная с C++17)
(до C++20)
template<class T >
constexpr variant& operator=( T&& t )noexcept(/* смотрите ниже */);
(начиная с C++20)

Присваивает новое значение существующему объекту variant.

1) Присваивание копированием:
  • Если оба *this и rhs не имеют значения в силу исключения, ничего не делает.
  • Иначе, если 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))). *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";// OKstd::variant<std::string, std::string> v2; v2 ="abc";// Ошибкаstd::variant<std::string, bool> v3; v3 ="abc";// OK, выбирает string; bool не является кандидатомstd::variant<float, long, double> v4;// содержит float v4 =0;// OK, содержит long; float и double не являются кандидатами

Содержание

[править]Параметры

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:  

[править]Пример

#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)>;ifconstexpr(std::is_same_v<T, int>) os << arg;elseifconstexpr(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 ), где T является int\n"; a =2019;std::cout<<"a"<< a <<'\n';   std::cout<<"(3) operator=( T&& t ), где T является 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 ), где T является int a: { 2019 };   (3) operator=( T&& t ), где T является std::string s: "CppNow" a: { "CppNow" }; s: ""

[править]Отчёты о дефектах

Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:

Номер Применён Поведение в стандарте Корректное поведение
LWG 3024 C++17 оператор присваивания копированием не участвует в разрешении
перегрузки, если какой-либо тип элемента не копируемый
вместо этого определяется как
удалённый
WG не указан C++17 присваивание копированием/перемещением может быть
нетривиальным, даже если базовые операции тривиальны
требуется для распространения
тривиальности
WG не указан C++17 преобразующее присваивание вслепую собирает набор перегрузок,
что приводит к непреднамеренным преобразованиям
сужение и логические преобразования
не учитываются
WG не указан C++20 преобразующее присваивание не было constexpr, в то время как
необходимые операции могут быть в C++20
сделано constexpr
LWG 3585 c++17 преобразующее присваивание иногда было некорректным, потому
что не было доступного присваивания перемещением
сделано корректным

[править]Смотрите также

создаёт значение в variant на месте
(public функция-элемент)[править]
close