Namespaces
Variants

std:: variant

From cppreference.net
Utilities library
Определено в заголовочном файле <variant>
template < class ... Types >
class variant ;
(начиная с C++17)

Шаблон класса std::variant представляет типобезопасное объединение .

Экземпляр variant в любой момент времени либо содержит значение одного из своих альтернативных типов, либо в случае ошибки - не содержит значения (это состояние трудно достичь, см. valueless_by_exception ).

Как и в случае с объединениями, если вариант содержит значение некоторого объектного типа T , объект T является вложенным в объект variant .

Вариант не может содержать ссылки, массивы или тип void .

Варианту разрешено содержать один и тот же тип более одного раза, а также содержать по-разному cv-квалифицированные версии одного и того же типа.

В соответствии с поведением объединений при агрегатной инициализации , вариант по умолчанию содержит значение своей первой альтернативы, если эта альтернатива является конструируемой по умолчанию (в противном случае вариант также не является конструируемым по умолчанию). Вспомогательный класс std::monostate может использоваться для обеспечения возможности конструирования таких вариантов по умолчанию.

Программа, создающая экземпляр определения std::variant без аргументов шаблона, является некорректной. std :: variant < std:: monostate > может быть использован вместо этого.

Если программа объявляет явную или частичную специализацию std::variant , программа является некорректной, диагностика не требуется.

Содержание

Параметры шаблона

Types - типы, которые могут храниться в этом варианте. Все типы должны удовлетворять Destructible требованиям (в частности, массивы и не-объектные типы не допускаются).

Функции-члены

создает объект variant
(public member function)
уничтожает variant вместе с содержащимся значением
(public member function)
присваивает variant
(public member function)
Наблюдатели
возвращает индекс (с нуля) альтернативы, содержащейся в variant
(public member function)
проверяет, находится ли variant в невалидном состоянии
(public member function)
Модификаторы
создает значение в variant на месте
(public member function)
обменивается с другим variant
(public member function)
Посещение
(C++26)
вызывает предоставленный функтор с аргументом, содержащимся в variant
(public member function)

Функции, не являющиеся членами класса

(C++17)
вызывает предоставленный функтор с аргументами, содержащимися в одном или нескольких variant ах
(шаблон функции)
проверяет, содержит ли variant в данный момент заданный тип
(шаблон функции)
читает значение variant по индексу или типу (если тип уникален), генерирует исключение при ошибке
(шаблон функции)
(C++17)
получает указатель на значение указанного variant по индексу или типу (если уникален), возвращает null при ошибке
(шаблон функции)
(C++17) (C++17) (C++17) (C++17) (C++17) (C++17) (C++20)
сравнивает объекты variant как их содержащиеся значения
(шаблон функции)
специализирует алгоритм std::swap
(шаблон функции)

Вспомогательные классы

(C++17)
тип-заполнитель для использования в качестве первой альтернативы в variant для типов без конструктора по умолчанию
(класс)
исключение, выбрасываемое при недопустимом доступе к значению variant
(класс)
получает размер списка альтернатив variant во время компиляции
(шаблон класса) (шаблон переменной)
получает тип альтернативы, указанной по её индексу, во время компиляции
(шаблон класса) (шаблон псевдонима)
поддержка хеширования для std::variant
(специализация шаблона класса)

Вспомогательные объекты

индекс variant в невалидном состоянии
(константа)

Примечания

Макрос тестирования возможностей Значение Стандарт Возможность
__cpp_lib_variant 201606L (C++17) std::variant : типобезопасное объединение
202102L (C++23)
(DR17)
std::visit для классов, производных от std::variant
202106L (C++23)
(DR20)
Полностью constexpr std::variant
202306L (C++26) Функция-член visit

Пример

#include <cassert>
#include <iostream>
#include <string>
#include <variant>
int main()
{
    std::variant<int, float> v, w;
    v = 42; // v содержит int
    int i = std::get<int>(v);
    assert(42 == i); // успешно
    w = std::get<int>(v);
    w = std::get<0>(v); // тот же эффект, что и в предыдущей строке
    w = v; // тот же эффект, что и в предыдущей строке
//  std::get<double>(v); // ошибка: нет double в [int, float]
//  std::get<3>(v);      // ошибка: допустимые значения индекса 0 и 1
    try
    {
        std::get<float>(w); // w содержит int, а не float: выбросит исключение
    }
    catch (const std::bad_variant_access& ex)
    {
        std::cout << ex.what() << '\n';
    }
    using namespace std::literals;
    std::variant<std::string> x("abc");
    // преобразующие конструкторы работают, когда однозначны
    x = "def"; // преобразующее присваивание также работает, когда однозначно
    std::variant<std::string, void const*> y("abc");
    // преобразуется в void const* при передаче char const*
    assert(std::holds_alternative<void const*>(y)); // успешно
    y = "xyz"s;
    assert(std::holds_alternative<std::string>(y)); // успешно
}

Возможный вывод:

std::get: wrong index for variant

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

Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Applied to Behavior as published Correct behavior
LWG 2901 C++17 specialization of std::uses_allocator provided,
but variant cannot properly support allocators
specialization removed
LWG 3990 C++17 a program could declare an explicit or
partial specialization of std::variant
the program is ill-formed in this
case (no diagnostic required)
LWG 4141 C++17 the requirement for storage
allocation was confusing
the contained object must be
nested within the variant object

Смотрите также

тег для конструирования на месте
(тег)
(C++17)
обёртка, которая может содержать или не содержать объект
(шаблон класса)
(C++17)
объекты, содержащие экземпляры любого CopyConstructible типа
(класс)