Convert std :: vector of type boost :: variant

How to implement the function below to convert from a value vector to a Container ? I want to argue that if not all members of values are of the same type, i.e. If the vector contains a combination of strings and ints. This is because the return value of the function is either std::vector<int> or std::vector<std::string> .

 typedef boost::variant<int, std::string> Value; typedef boost::variant<std::vector<int>, std::vector<std::string> > Container; Container valuesToContainer(const std::vector<Value>& values) { return Container(); } 
+4
source share
2 answers
  struct converter_visitor : public boost::static_visitor<Container> { const std::vector<Value> & _cont; converter_visitor(const std::vector<Value> &r) : _cont(r) {} template<class T> Container operator()(const T &) const { std::vector<T> ans; ans.reserve(_cont.size()); for (int i=0;i < _cont.size();++i) ans.push_back( boost::get<T>(_cont[i])); return ans; } }; Container valuesToContainer(const std::vector<Value> & values) { //assuming !values.empty() return boost::apply_visitor( converter_visitor(values),values.front()); } 

This will call bad_get if not all values elements are of the same type.

+3
source

It may come in handy, maybe:

 template <typename... T> using VariantVector = std::vector<boost::variant<T...>>; template <typename... T> using VectorPack = std::tuple<std::vector<T>...>; template <typename... T> VectorPack<T...> splitVectors(VariantVector<T...> const &values); 

The difference with the function requested by the OP is that instead of an โ€œerrorโ€ when not all types of elements are consistent, it will return a tuple of vectors (โ€œVectorPackโ€) and you can simply choose which one you want.

Demo program:

 #include <boost/variant.hpp> #include <boost/variant/static_visitor.hpp> #include <tuple> #include <vector> using std::get; template <typename... T> using VariantVector = std::vector<boost::variant<T...>>; template <typename... T> using VectorPack = std::tuple<std::vector<T>...>; namespace detail { template <typename T> struct VectorSplitterMixin { void operator()(T const& v) { _bucket.push_back(v); } std::vector<T> _bucket; }; template <typename... T> struct VectorSplitter : boost::static_visitor<>, VectorSplitterMixin<T>... { typedef VectorPack<T...> product_t; product_t product() { return product_t { std::move(static_cast<VectorSplitterMixin<T>*>(this)->_bucket)... }; } }; } template <typename T> struct X; template <typename... T> VectorPack<T...> splitVectors(VariantVector<T...> const &values) { auto splitter = detail::VectorSplitter<T...>(); for (auto& val : values) boost::apply_visitor(splitter, val); return splitter.product(); } int main() { typedef boost::variant<int, std::string> Value; typedef boost::variant<std::vector<int>, std::vector<std::string> > Container; const std::vector<Value> vec { 42, "hello world", 1, -99, "more" }; auto vectorPack = splitVectors<int, std::string>(vec); for (auto i : get<0>(vectorPack)) std::cout << "int:" << i << ", "; std::cout << "\n"; for (auto& s : get<1>(vectorPack)) std::cout << "string:" << s << ", "; std::cout << "\n"; } 

Print

 int:42, int:1, int:-99, string:hello world, string:more, 
+1
source

All Articles