Объекты · Классы и память

std::variant

Одно из нескольких — без наследования

~25 мин 5 шагов

После урока ты сможешь

  • Хранить значение одного из нескольких типов
  • Обрабатывать все варианты через std::visit
  • Выбирать между variant и виртуальными функциями

Шаг 1 из 5

Одно из нескольких

Сообщение в чате бывает текстом, фотографией или стикером. У каждого вида свои данные: у текста строка, у фото адрес и подпись, у стикера номер. Как хранить их в одном векторе?

Можно сделать иерархию классов с виртуальными функциями, как в прошлом уроке. Но если вариантов немного и они известны заранее, в C++17 есть более простой и быстрый инструмент — std::variant: значение, которое в каждый момент содержит ровно один тип из перечисленных.

main.cpp
#include <print>
#include <string>
#include <variant>
​
int main() {
    std::variant<int, double, std::string> value = 42;
    std::println("индекс типа: {}", value.index());   // 0 — int
​
    value = std::string("привет");
    std::println("индекс типа: {}", value.index());   // 2 — string
​
    if (std::holds_alternative<std::string>(value)) {
        std::println("строка: {}", std::get<std::string>(value));
    }
}

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