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:
- 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.
- Use
std::visit with a generic lambda. Will be resolved in runtime.
- 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
std::getwith a specific type, orstd::visit.typeisn't a type, and types aren't values