std::visit în C++

Apelează o funcție cu valoarea curentă dintr-un std::variant, oricare ar fi tipul ei.

Sintaxă
#include <variant>
template<class Visitor, class... Variants>
constexpr decltype(auto) visit(Visitor&& vis, Variants&&... vars);

Ce face std::visit

std::visit(f, v) se uită ce tip conține v și apelează f cu valoarea de acel tip. f trebuie să poată primi fiecare tip posibil: o lambda generică (auto) sau un obiect cu mai mulți operator().

Tehnica „overloaded” combină mai multe lambda într-un singur obiect, câte una pentru fiecare tip. Dacă uiți un tip, codul nu compilează, așa că nu poți rata un caz.

Parametri

Parametru Descriere
vis Funcția sau obiectul apelat cu valoarea curentă.
vars Unul sau mai multe std::variant.

Ce returnează

Ce returnează vis (același tip pentru toate variantele).

Exemple

Exemplul 1: Lambda generică

#include <print>
#include <string>
#include <variant>
#include <vector>

int main() {
    std::vector<std::variant<int, double, std::string>> valori{42, 2.5, std::string("Ana")};
    for (const auto& v : valori) {
        std::visit([](const auto& x) { std::println("valoare: {}", x); }, v);
    }
}

Rezultat

valoare: 42
valoare: 2.5
valoare: Ana

Exemplul 2: Câte o funcție pentru fiecare tip (overloaded)

Structura overloaded moștenește toate lambda-urile primite, deci are câte un operator() pentru fiecare tip.

#include <print>
#include <string>
#include <variant>
#include <vector>

template <class... Fs>
struct overloaded : Fs... {
    using Fs::operator()...;
};

struct Cerc { double r; };
struct Dreptunghi { double a, b; };
using Figura = std::variant<Cerc, Dreptunghi>;

int main() {
    std::vector<Figura> figuri{Cerc{1}, Dreptunghi{2, 3}};
    for (const auto& f : figuri) {
        double arie = std::visit(overloaded{
            [](const Cerc& c) { return 3.14159 * c.r * c.r; },
            [](const Dreptunghi& d) { return d.a * d.b; },
        }, f);
        std::println("arie: {:.2f}", arie);
    }
}

Rezultat

arie: 3.14
arie: 6.00

Greșeli frecvente

  • Variantele din lambda-urile overloaded returnează tipuri diferite (de exemplu int și double). std::visit cere același tip de retur pentru toate; convertește explicit.

Comenzi înrudite

  • std::variant: O valoare care are, la un moment dat, exact unul dintre mai multe tipuri posibile (union sigur).
  • std::holds_alternative: holds_alternative verifică ce tip are acum un variant; get_if returnează pointer la valoare sau nullptr.
  • lambda ([](){}): O funcție fără nume, scrisă direct acolo unde e folosită; poate „captura” variabile din jur.