TGViewer
Библиотека C/C++ разработчика | cpp, boost, qt Библиотека C/C++ разработчика | cpp, boost, qt @cppproglib · 16.9K subscribers
Post #6104 2.37K
👁 std::variant — типобезопасный union

std::variant (C++17) — это union, который знает свой текущий тип и гарантирует безопасность.


🐤 Старый подход:

// C-style union — опасно!
union Data {
int i;
double d;
char* str;
};

Data data;
data.i = 42;
std::cout << data.d; // ❌ Читаем не то, что записали



🐸 Современный подход:

std::variant<int, double, std::string> data;

data = 42; // Хранит int
data = 3.14; // Теперь хранит double
data = "hello"; // Теперь хранит string

// Безопасное получение значения
if (auto* val = std::get_if<int>(&data)) {
std::cout << "int: " << *val << '\n';
}



🥨 Базовые операции:

std::variant<int, std::string, double> v;

// Установка значения
v = 100;
v = "text";
v.emplace<std::string>("constructed in place");

// Проверка текущего типа
std::cout << v.index(); // Индекс типа: 0, 1, или 2

if (std::holds_alternative<int>(v)) {
std::cout << "Содержит int\n";
}

// Получение значения
try {
auto val = std::get<int>(v); // Бросит std::bad_variant_access
} catch (const std::bad_variant_access&) {
std::cerr << "Неверный тип!\n";
}

auto* ptr = std::get_if<std::string>(&v); // nullptr если не string



🐾 std::visit — главная фишка:

std::variant<int, double, std::string> v = 42;

// Обработка всех возможных типов
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;

if constexpr (std::is_same_v<T, int>) {
std::cout << "int: " << arg << '\n';
} else if constexpr (std::is_same_v<T, double>) {
std::cout << "double: " << arg << '\n';
} else {
std::cout << "string: " << arg << '\n';
}
}, v);



🍪 Перегруженный visitor (C++17 трюк):

cpptemplate<class... Ts>
struct overloaded : Ts... {
using Ts::operator()...;
};

template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;

// Элегантная обработка!
std::visit(overloaded{
[](int i) { std::cout << "int: " << i << '\n'; },
[](double d) { std::cout << "double: " << d << '\n'; },
[](const std::string& s) { std::cout << "string: " << s << '\n'; }
}, v);



✏️ Пример: Обработка ошибок

template<typename T>
using Result = std::variant<T, std::string>; // Value или Error

Result<int> divide(int a, int b) {
if (b == 0) return "Division by zero";
return a / b;
}

auto result = divide(10, 0);
std::visit(overloaded{
[](int value) { std::cout << "Result: " << value << '\n'; },
[](const std::string& err) { std::cerr << "Error: " << err << '\n'; }
}, result);



❗️ Важно:

std::variant никогда не пустой (кроме исключительных ситуаций). Первый тип должен быть конструируемым по умолчанию.


❗️std::any:

Используйте std::variant когда набор типов известен. std::any — для действительно произвольных типов.


Библиотека C/C++ разработчика

#буст
  • 👍 7
  • 🔥 4
  • ❤ 3
More from @cppproglib
  1. Sep 19, 2026А вы уже забрали свой подарок ко Дню программиста? К вашему профессиональному празднику Tp…
  2. Sep 18, 2026От исходного кода до процессора: разберись, как работает программа 💻 Стартует практически…
  3. Sep 15, 2026😭 Как не потратить недельный лимит AI-кодинга за три дня? Разберём на вебинаре, как трати…
  4. Sep 13, 2026🤪 Если бы можно было задать один вопрос про AI в разработке — что бы вы спросили? Как выб…
  5. Sep 13, 2026🤩 Inline static в классах — забудь про .cpp Сколько раз ты забывал добавить определение s…
  6. Sep 13, 2026🌸 Вселенная намекает: пора уже начать этот курс С 14 сентября цены в Proglib Academy выра…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →