C++ Variant

Da Andreabont's Wiki.

Variant è un tipo introdotto in C++17 per gestire le union type-safe. Permette di salvare tipi diversi nella stessa variabile (non contemporaneamente).

Esempio base

#include <iostream>
#include <variant>

int main() {

    std::variant<int, double> numero;

    numero = 1;

    std::cout << "Numero: " << std::get<int>(numero) << std::endl;

    numero = 1.2;

    std::cout << "Numero: " << std::get<double>(numero) << std::endl;

}

Esempio visitor

Tramite il pattern visitor è possibile scorrere dei contenitori contenenti dei variant. La gestione dei vari tipi avviene grazie alla natura template della lambda con parametro auto.

std::vector<std::variant<int, double>> vettore = {12, 1.3};

for(auto i : vettore) {
    std::visit([](auto j){
        std::cout << j << std::endl;
    }, i);
}

Oppure è possibile usare il pattern visitor classico:

#include <iostream>
#include <vector>
#include <variant>

class base {};
class a : public base {};
class b : public base {};

struct visitAB {
   void operator() (a instA) {
      std::cout << "Type 'a'" << std::endl;  
   }
   void operator() (b instB) {
      std::cout << "Type 'b'" << std::endl;
   }
};

int main () {

    std::vector<std::variant<a, b>> myVector;
    
    a instA;
    b instB;
    
    myVector.push_back(instA);
    myVector.push_back(instB);
    
    for(std::variant<a, b> myVar : myVector) {
        std::visit(visitAB(), myVar);
    }
    
}

Oppure è possibile usare un "trucco" per effettuare l'overload delle lambda:

#include <iostream>
#include <vector>
#include <variant>

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; }; // (1)
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;  // (2)

class base {};
class a : public base {};
class b : public base {};

int main () {

    std::vector<std::variant<a, b>> myVector;
    
    a instA;
    b instB;
    
    myVector.push_back(instA);
    myVector.push_back(instB);
    
    for(std::variant<a, b> myVar : myVector) {
        std::visit(overloaded {
            [](a instA) { std::cout << "Type 'a'" << std::endl; },
            [](b instB) { std::cout << "Type 'b'" << std::endl; },
        }, myVar);
    }
    
}