0

How to access std::variant using std::get by specifying the type info during runtime. Below is a non working code that I tried

#include <iostream>
#include <string>
#include <variant>

class A {
public:
    A(const int a) {
        va = a;
        // below line doesn't compile
        // variant_type = int;
    }

    A(const std::string& a) {
        va = a;
        // below line doesn't compile
        // variant_type = std::string;
    }

    // type variant_type;
    // above line doesn't compile
    std::variant<int, std::string> va{};
};

int main() {
    std::variant<int, std::string> va{"abcd"};
    std::cout << std::get<1>(va) << std::endl;

    va = 23;
    std::cout << std::get<0>(va) << std::endl;

    const A a_obj{1};
    // below line doesn't compile
    // std::get<a_obj.type>(a_obj);

    const A b_obj{"abc"};
    // below line doesn't compile
    // std::get<b_obj.type>(b_obj);
}
2
  • 2
    Either use std::get with a specific type, or std::visit. Commented Sep 4, 2024 at 11:54
  • 1
    type isn't a type, and types aren't values Commented Sep 4, 2024 at 11:57

1 Answer 1

2

Types are not values that you can store in a data member.

In order to access the std::variant data based on its type, you have several options:

  1. Use std::get with a specific type. If you know it at compile-time you can use it plainly. If you want to check the type at runtime before the call to std::get, you can use std::holds_alternative.
  2. Use std::visit with a generic lambda. Will be resolved in runtime.
  3. Use std::visit with a lambda per variant type. This is useful if you need separate logic per type (will be also resolved in runtime).
#include <variant>
#include <string>
#include <iostream>

class A {
public:
    A(const int a) { va = a; }
    A(const std::string& a) { va = a; }
    std::variant<int, std::string> va{};
};

void A_visitor_generic_lambda(A const& a) {
    std::visit([](auto&& arg) { std::cout << arg << std::endl; }, a.va);
}

template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
// explicit deduction guide (not needed as of C++20)
template<class... Ts>
overloaded(Ts...)->overloaded<Ts...>;

void A_visitor_separate_lambdas(A const& a) {
    std::visit(overloaded{
                 [](int arg) { std::cout << arg << std::endl; },
                 [](std::string const& arg) { std::cout << arg << std::endl; } },
               a.va);
}

int main() {
     const A a_obj{ 1 };
     const A b_obj{ "abc" };

    // 1. Use `std::get` with a specific type, after checking the type with `std::holds_alternative`:
    if (std::holds_alternative<int>(a_obj.va)) {
        std::cout << std::get<int>(a_obj.va) << std::endl;
    }
    if (std::holds_alternative<std::string>(b_obj.va)) {
        std::cout << std::get<std::string>(b_obj.va) << std::endl;
    }

    // 2. Use `std::visit` with a generic labmda:
    A_visitor_generic_lambda(a_obj);
    A_visitor_generic_lambda(b_obj);

    // 3. Use `std::visit` with a separate overload lambdas:
    A_visitor_separate_lambdas(a_obj);
    A_visitor_separate_lambdas(b_obj);
}

Output:

1
abc
1
abc
1
abc

Live demo

Sign up to request clarification or add additional context in comments.

2 Comments

std::holds_alternative might also worth checking out.
@Raildex good point, added.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.