How do we know which container data is present in boost variant? My variant is having any datatype or container. how to access the type of the data from the container?
boost::variant<string, int> myvar = 245;
if(myvar.type() == typeid(int)){
std::cout<<"integer data type"<< '\n';//I am able to get the type of integer/string
}
boost::variant<vector<int>, list<string>> v {1,2,3,4};//???
CodePudding user response:
boost::variant<vector<int>, list<string>> v {1,2,3,4};//???
fails because the compiler can not determine the type from the given initializer list.
You simply can provide the type and all works as expected:
boost::variant<std::vector<int>, std::list<std::string>> v=std::vector<int> {1,2,3,4};
BTW: Why use boost::variant
? You also have std::variant
which fits maybe better?
CodePudding user response:
There are mainly 2 ways for you to access the underlying element of a variant
:
- A compile-time type safe value visitation with
apply_visitor
- A run-time checked explicit value retrieval with
get<T>
To use apply_visitor
, you would first create a visitor functor by inherit from boost::static_visitor<T>
, where T
is the return type of the visitor:
struct my_visitor : boost::static_visitor<size_t>
{
size_t operator()(std::vector<int> vec) const
{
for(int i : vec) std::cout << i << ',';
return vec.size();
}
size_t operator()(std::list<std::string> list) const
{
for(std::string s : list) std::cout << s << ',';
return list.size();
}
};
Here both version of the visitor well print out the entire container, and return the size of the container. Notice the parameter type would correspond to the each types included with the variant. Then you can apply the visitor to the variant with:
size_t size = boost::apply_visitor(my_visitor(), v);
Also, since the two paths of the visitor behave almost the same, you can also just write a single template function:
struct my_visitor : boost::static_visitor<int>
{
template<typename Container>
std::size_t operator()(Container cont) const
{
for(auto s : cont) std::cout << s << ',';
return cont.size();
}
};
With C 14 or later, you may also use a lambda instead of a functor:
size_t size = apply_visitor(
[](auto cont){
for(auto s : cont) std::cout << s << ',';
return cont.size();
}, v
);
The other way is to rely on run-time check:
auto& vec = boost::get<std::vector<int>>(v);
Now vec
would be a std::vector<int>&
. If the contained type is not a std::vector<int>
, this will throw a boost::bad_get
. And if you used a type that's not included in the variant
you provided, it will be a compile time error.