std::visit
Обрабатывайте альтернативы variant
«std::visit» — бесплатный урок C++ Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C++ Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C++ Academy содержит 4 уроков всего.
Зачем нужен std::visit
Ручная проверка каждой альтернативы с помощью get_if быстро становится громоздкой. std::visit применяет вызываемый объект к типу, который вариант содержит в данный момент, и самостоятельно выполняет диспетчеризацию.
#include <iostream>
#include <variant>
int main() {
std::variant<int, double> v = 4;
std::visit([](auto x){ std::cout << x << "\n"; }, v);
}Универсальный посетитель на основе лямбда-выражения
Лямбда-выражение, принимающее auto, работает с каждой альтернативой, если его тело компилируется для всех них. Здесь мы выводим активное значение независимо от его типа.
#include <iostream>
#include <string>
#include <variant>
int main() {
std::variant<int, std::string> v = std::string("hi");
std::visit([](const auto& x){ std::cout << x << "\n"; }, v);
}Возврат значения
std::visit может возвращать значение. Каждая ветвь должна возвращать один и тот же тип.
#include <iostream>
#include <variant>
int main() {
std::variant<int, double> v = 2.5;
double d = std::visit([](auto x){ return x * 2.0; }, v);
std::cout << d << "\n";
}Поведение для каждого типа с помощью if constexpr
Чтобы выполнять разные действия для разных типов внутри одного универсального лямбда-выражения, объедините if constexpr с std::decay_t и std::is_same_v.
#include <iostream>
#include <string>
#include <variant>
#include <type_traits>
int main() {
std::variant<int, std::string> v = 5;
std::visit([](const auto& x){
using T = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<T, int>) std::cout << "int " << x << "\n";
else std::cout << "str " << x << "\n";
}, v);
}Посетитель-структура
Можно также написать структуру с несколькими перегрузками operator(), по одной для каждого типа. Компилятор выбирает подходящую перегрузку.
#include <iostream>
#include <string>
#include <variant>
struct Printer {
void operator()(int i) const { std::cout << "int " << i << "\n"; }
void operator()(const std::string& s) const { std::cout << "str " << s << "\n"; }
};
int main() {
std::variant<int, std::string> v = std::string("yo");
std::visit(Printer{}, v);
}Идиома overloaded
Популярный вспомогательный приём объединяет несколько лямбда-выражений в одного посетителя. Каждое лямбда-выражение обрабатывает определённый тип.
#include <iostream>
#include <string>
#include <variant>
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
int main() {
std::variant<int, std::string> v = 8;
std::visit(overloaded{
[](int i){ std::cout << "i=" << i << "\n"; },
[](const std::string& s){ std::cout << "s=" << s << "\n"; }
}, v);
}Полнота обработки
Посетитель должен обрабатывать каждую альтернативу, иначе код не скомпилируется. Эта проверка во время компиляции не позволяет забыть один из вариантов.
Посещение с изменением значения
Если передать вариант по неконстантной ссылке, посетитель сможет изменить хранимое значение непосредственно на месте.
#include <iostream>
#include <variant>
int main() {
std::variant<int, double> v = 10;
std::visit([](auto& x){ x += 1; }, v);
std::cout << std::get<int>(v) << "\n";
}Несколько вариантов
std::visit может одновременно принимать несколько вариантов; тогда посетитель получает по одному аргументу для каждого варианта.
#include <iostream>
#include <variant>
int main() {
std::variant<int, double> a = 2;
std::variant<int, double> b = 3.0;
auto sum = std::visit([](auto x, auto y){ return x + y; }, a, b);
std::cout << sum << "\n";
}Выбор стиля посетителя
Используйте универсальное лямбда-выражение с auto для единообразной обработки, идиому overloaded для ясной логики отдельных типов, а посетителя-структуру — когда поведение нужно повторно использовать в разных местах вызова.
Посещение и get_if
get_if подходит для одной быстрой проверки, но std::visit лучше масштабируется: он требует обработки всех альтернатив и хранит всю логику для отдельных типов в одном месте.
Быстрая проверка
Проверьте, насколько хорошо Вы поняли std::visit.
Итоги
Вы узнали о std::visit:
- Он передаёт вызов вызываемому объекту для активной альтернативы.
- Используйте универсальные лямбда-выражения,
if constexpr, посетителей-структуры или идиому overloaded. - Посетители должны обрабатывать все альтернативы (проверка во время компиляции).
- Они могут возвращать значения и одновременно посещать несколько вариантов.
Часто задаваемые вопросы
Урок «std::visit» бесплатный?
Да — полный текст урока «std::visit» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C++ Academy, подпишись на CoddyKit PRO. Курс C++ Academy содержит 4 уроков всего.
Чему я научусь в уроке «std::visit»?
Обрабатывайте альтернативы variant Ты практикуешь C++ Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C++ Academy?
Предыдущий опыт не требуется. C++ Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «std::visit»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C++ Academy?
Да. Каждый урок C++ Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.