【问题标题】:Convert a std::vector of a boost::variant type转换 boost::variant 类型的 std::vector
【发布时间】:2013-03-21 12:52:25
【问题描述】:

如何实现下面的函数将Value 的向量转换为Container?我想断言values 的所有成员是否都属于同一类型,即向量是否包含字符串和整数的混合。这是因为函数的返回值要么是std::vector<int>,要么是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();
}

【问题讨论】:

  • 你在问什么。您想知道如何检查元素是否都属于同一类型吗?或者你在问如何进行转换?你都尝试了些什么?你知道boost::apply_visitor吗?

标签: c++ boost c++98


【解决方案1】:
  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());
   }

如果不是values 的所有元素都属于同一类型,这将抛出bad_get

【讨论】:

    【解决方案2】:

    这可能会派上用场,也许:

    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);
    

    与 OP 请求的函数的不同之处在于,当并非所有元素类型都同意时,它不会“出错”,而是返回一个 tuple 向量(“VectorPack”),您可以简单地选择你想要的那个。

    演示程序:

    #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";
    }
    

    印刷:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-02-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-06
      • 2018-04-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多