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

std::variant<Types...>::variant

Материал из cppreference.com
 
 
Библиотека утилит
Языковая поддержка
Поддержка типов (базовые типы, 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++14)
(C++11)
(C++11)
(C++11)
(C++17)
Общие лексические типы
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)
Элементарные преобразования строк
(C++17)
(C++17)
 
 
<tbody> </tbody>
constexpr variant() noexcept(/* смотрите ниже */);
(1) (начиная с C++17)
constexpr variant( const variant& other );
(2) (начиная с C++17)
constexpr variant( variant&& other ) noexcept(/* смотрите ниже */);
(3) (начиная с C++17)
template< class T > constexpr variant( T&& t ) noexcept(/* смотрите ниже */);
(4) (начиная с C++17)
template< class T, class... Args > constexpr explicit variant( std::in_place_type_t<T>, Args&&... args );
(5) (начиная с C++17)
template< class T, class U, class... Args > constexpr explicit variant( std::in_place_type_t<T>, std::initializer_list<U> il, Args&&... args );
(6) (начиная с C++17)
template< std::size_t I, class... Args > constexpr explicit variant( std::in_place_index_t<I>, Args&&... args );
(7) (начиная с C++17)
template< std::size_t I, class U, class... Args > constexpr explicit variant( std::in_place_index_t<I>, std::initializer_list<U> il, Args&&... args );
(8) (начиная с C++17)

Создаёт новый объект variant.

1) Конструктор по умолчанию. Создаёт variant, содержащий инициализированное значением значение первой альтернативы (index() равно нулю).
  • Этот конструктор является constexpr тогда и только тогда, когда инициализация значения альтернативного типа T_0 соответствует требованиям для функций constexpr.
  • Эта перегрузка участвует в разрешении перегрузки, только если std::is_default_constructible_v<T_0> равно true.
2) Конструктор копирования. Если other не является valueless_by_exception, создаёт variant, содержащий ту же альтернативу, что и other, и напрямую инициализирует содержащееся значение с помощью *std::get_if<other.index()>(std::addressof(other)). Иначе инициализирует вариант valueless_by_exception.
  • Этот конструктор определяется как удалённый, если только std::is_copy_constructible_v<T_i> не равно true для всех T_i в Types....
  • Он тривиальный, если std::is_trivially_copy_constructible_v<T_i> равно true для всех T_i в Types....
3) Конструктор перемещения. Если other не является valueless_by_exception, создаёт variant, содержащий ту же альтернативу, что и other, и напрямую инициализирует содержащееся значение с помощью std::move(*std::get_if<other.index()>(std::addressof(other))). Иначе инициализирует вариант valueless_by_exception.
  • Эта перегрузка участвует в разрешении перегрузки, только если std::is_move_constructible_v<T_i> равно true для всех T_i в Types....
  • Он тривиальный, если std::is_trivially_move_constructible_v<T_i> равно true для всех T_i в Types....
4) Преобразующий конструктор. Создаёт variant, содержащий альтернативный тип T_j, который будет выбран разрешением перегрузки для выражения F(std::forward<T>(t)), если одновременно произошла перегрузка воображаемой функции F(T_i) для каждого T_i из Types... в области видимости, за исключением того, что:
  • Перегрузка F(T_i) рассматривается только в том случае, если объявление T_i x[] = { std::forward<T>(t) }; допустимо для некоторой искусственной переменной x.
Инициализирует напрямую содержащееся значение, как если бы это была прямая инициализация не списком из std::forward<T>(t).
  • Эта перегрузка участвует в разрешении перегрузки, только если
    • sizeof...(Types) > 0,
    • std::decay_t<T> (до C++20)std::remove_cvref_t<T> (начиная с C++20) не является ни тем же типом, что variant, ни специализацией std::in_place_type_t, ни специализацией std::in_place_index_t,
    • std::is_constructible_v<T_j, T> равно true,
    • и выражение F(std::forward<T>(t)) (где F это вышеупомянутый набор мнимых функций) является корректным.
  • Этот конструктор является конструктором constexpr, если конструктор, выбранный T_j, является конструктором constexpr.
std::variant<std::string> v("abc"); // OK
std::variant<std::string, std::string> w("abc"); // некорректно
std::variant<std::string, const char*> x("abc"); // OK, выбирает const char*
std::variant<std::string, bool> y("abc"); // OK, выбирает string;
                                          // bool не является кандидатом
std::variant<float, long, double> z = 0; // OK, содержит long
                                         // float и double не являются кандидатами
5) Создаёт variant с указанной альтернативой T и инициализирует содержащееся значение аргументами std::forward<Args>(args)....
  • Если выбранный конструктор T является конструктором constexpr, этот конструктор также является конструктором constexpr.
  • Эта перегрузка участвует в разрешении перегрузки, только если имеется ровно одно вхождение T в Types... и std::is_constructible_v<T, Args...> равно true.
6) Создаёт variant с указанной альтернативой T и инициализирует содержащееся значение аргументами il, std::forward<Args>(args)....
  • Если выбранный конструктор T является конструктором constexpr, этот конструктор также является конструктором constexpr.
  • Эта перегрузка участвует в разрешении перегрузки, только если имеется ровно одно вхождение T в Types... и std::is_constructible_v<T, initializer_list<U>&, Args...> равно true.
7) Создаёт variant с альтернативой T_i, указанной индексом I, и инициализирует содержащееся значение аргументами std::forward<Args>(args)....
  • Если выбранный конструктор T_i является конструктором constexpr, этот конструктор также является конструктором constexpr.
  • Эта перегрузка участвует в разрешении перегрузки, только если I < sizeof...(Types) и std::is_constructible_v<T_i, Args...> равно true.
8) Создаёт variant с альтернативой T_i, указанной индексом I, и инициализирует содержащееся значение аргументами il, std::forward<Args>(args)....
  • Если выбранный конструктор T_i является конструктором constexpr, этот конструктор также является конструктором constexpr.
  • Эта перегрузка участвует в разрешении перегрузки, только если I < sizeof...(Types) и std::is_constructible_v<T_i, std::initializer_list<U>&, Args...> равно true.

Параметры

other другой объект variant, содержащий значение для копирования/перемещения
t значение, которым инициализировать содержащееся значение
args... аргументы, которыми инициализировать содержащееся значение
il список инициализаторов, которыми инициализировать содержащееся значение

Исключения

1) Может вызвать любое исключение, вызванное инициализацией значения первой альтернативы.
спецификация noexcept:  
noexcept(std::is_nothrow_default_constructible_v<T_0>)
2) Может вызвать любое исключение, вызванное прямой инициализацией любого T_i в Types...
3) Может вызвать любое исключение, вызванное созданием перемещением любого T_i в Types....
спецификация noexcept:  
noexcept((std::is_nothrow_move_constructible_v<Types> && ...))
4) Может вызвать любое исключение, вызванное инициализацией выбранной альтернативы T_j.
спецификация noexcept:  
noexcept(std::is_nothrow_constructible_v<T_j, T>)
5-8) Может вызвать любое исключение, вызванное выбранным конструктором выбранной альтернативы.

Пример

#include <cassert>
#include <iostream>
#include <string>
#include <variant>
#include <vector>

using vector_t = std::vector<int>;

auto& operator<<(auto& out, const vector_t& v)
{
    out << "{ ";
    for (int e: v)
        out << e << ' ';
    return out << '}';
}

int main()
{
    // инициализация значением первой альтернативы
    std::variant<int, std::string> var0;
    assert(std::holds_alternative<int>(var0) and
           var0.index() == 0 and
           std::get<int>(var0) == 0);

    // инициализация первой альтернативы с помощью std::string{"STR"};
    std::variant<std::string, int> var1{"STR"};
    assert(var1.index() == 0);
    std::cout << "1) " << std::get<std::string>(var1) << '\n';

    // инициализация второй альтернативы с помощью int == 42;
    std::variant<std::string, int> var2{42};
    assert(std::holds_alternative<int>(var2));
    std::cout << "2) " << std::get<int>(var2) << '\n';

    // инициализация первой альтернативы с помощью std::string{4, 'A'};
    std::variant<std::string, vector_t, float> var3
    {
        std::in_place_type<std::string>, 4, 'A'
    };
    assert(var3.index() == 0);
    std::cout << "3) " << std::get<std::string>(var3) << '\n';

    // инициализация второй альтернативы с помощью std::vector{1,2,3,4,5};
    std::variant<std::string, vector_t, char> var4
    {
        std::in_place_type<vector_t>, {1,2,3,4,5}
    };
    assert(var4.index() == 1);
    std::cout << "4) " << std::get<vector_t>(var4) << '\n';

    // инициализация первой альтернативы с помощью std::string{"ABCDE", 3};
    std::variant<std::string, vector_t, bool> var5 {std::in_place_index<0>, "ABCDE", 3};
    assert(var5.index() == 0);
    std::cout << "5) " << std::get<std::string>(var5) << '\n';

    // инициализация второй альтернативы с помощью std::vector(4, 42);
    std::variant<std::string, vector_t, char> var6 {std::in_place_index<1>, 4, 42};
    assert(std::holds_alternative<vector_t>(var6));
    std::cout << "6) " << std::get<vector_t>(var6) << '\n';
}

Вывод:

1) STR
2) 42
3) AAAA
4) { 1 2 3 4 5 }
5) ABC
6) { 42 42 42 42 }

Отчёты о дефектах

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

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