Daily bit(e) C++. std::visit

Добавлено 7 августа 2026 в 12:10

Daily bit(e) C++ 66, обработка активного члена std::variant с помощью std::visit.

Daily bit(e) C++

При работе с std::variant обработка текущего активного члена может привести к созданию громоздкого кода.

Альтернативой, особенно если код обработки является универсальным, является функция std::visit.

Для std::visit в качестве аргумента требуется вызываемый объект, совместимый с каждым из содержащихся типов. Этого можно достичь за счет сочетания конкретных и универсальных перегрузок operator().

#include <variant>
#include <print>

std::variant<int,double,std::string> v = "hello world!";

// Обобщенный visit, создаст экземпляр универсальной
// лямбда-функции для каждого типа:
std::visit([](auto&& x) {
    std::println("{}", x);
}, v);
// напечатает "hello world!"


// Вспомогательный шаблон, использующий CTAD.
// Наследуется от аргументов конструктора и
// предоставляет доступ к их оператору вызова.
template <typename ...Ts>
struct overloaded : Ts... 
{
    using Ts::operator()...;
};

v = 2.4;
// Создаем новый тип, унаследовав его от лямбда-функций,
// обрабатывающих каждый тип:
std::visit(overloaded{
    [](int& x) {
        std::println("Contains 'int', value: {}", x);
    },
    [](double& x) {
        std::println("Contains 'double', value: {}", x);
    },
    [](std::string& x) {
        std::println("Contains 'std::string', value: {}", x);
    }
}, v);
// напечатает "Contains 'double', value: 2.4"


// Можно обрабатывать несколько variant'ов,
// каждый из которых соответствует аргументу функции:
std::variant<std::string,int> a("hello world!");
std::variant<double,char> b('X');

std::visit([](auto&& first, auto&& second) {
    std::println("First argument:");
    std::println("\ttype == {}", typeid(first).name());
    std::println("\tvalue == {}", first);
    std::println("Second argument:");
    std::println("\ttype == {}", typeid(second).name());
    std::println("\tvalue == {}", second);
}, a, b);
// напечатает (имена типов зависят от реализации):
// First argument:
//   type == NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
//   value == hello world!
// Second argument:
//   type == c 
//   value == X


std::variant<int,long long,float,double> x = 7.4;
// Вызываемые объекты могут возвращать значение.
// При этом все перегрузки должны возвращать значения одного типа.

// Не скомпилируется:
// auto r1 = std::visit([](auto e) { return e; }, x);

auto r1 = std::visit([](auto e) {
    return static_cast<int>(e);
}, x);
// r1 == 7, decltype(r1) == int

// C++20 добавил версию visit, которая позволяет нам указывать 
// общий тип возвращаемого значения
auto r2 = std::visit<int>([](auto e) {
    return e;
}, x);
// r2 == 7, decltype(r2) == int

Пример на Compiler Explorer

Теги

C++ / CppDaily bit(e) C++Программирование