2013-03-21 2 views
4

Как я могу реализовать функцию ниже для преобразования из вектора Value в Container? Я хочу утверждать, что если не все члены values имеют один и тот же тип, т. Е. Если вектор содержит комбинацию строк и целых чисел. Это связано с тем, что возвращаемое значение функции является либо std::vector<int>, либо std::vector<std::string>.Преобразование std :: vector boost :: variant type

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(); 
} 
+0

Что вы спрашиваете. Вы хотите знать, как вы можете проверить, все ли элементы одного типа? Или вы спрашиваете, как сделать конверсию? что ты уже испробовал? Вы знаете о «boost :: apply_visitor»? – sellibitze

ответ

3
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()); 
    } 

Это будет бросать bad_get, если не все элементы values одного и того же типа.

1

Это может пригодиться, может быть:

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 является то, что вместо «erroring», когда не все типы элементов согласен, он будет возвращать кортеж из векторы («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, 
Смежные вопросы