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);
}
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:
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.std::visit with a generic lambda. Will be resolved in runtime.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