对存储在boost :: any中的向量调用vector :: size()

时间:2014-09-05 13:52:47

标签: c++ boost

我将值存储在boost::any中,如果boost::any拥有std::vector,我希望有一个能够返回元素数量的函数。

以下是使用示例:

int a = 42;
vector<int> v = {1,2,3,4};
vector<int> w;

boost::any aa = a;
boost::any av = v;
boost::any aw = w;

// I would like to have this function `count`
count( aa ) // return 1
count( av ) // return 4
count( aw ) // return 0

// I can do following. But I do not like the template argument.
count<int>( aa ) // return 1
count<int>( av ) // return 4
count<int>( aw ) // return 0
count<float>( aa ) // error

问题在于我无法在不指定vector<T>的情况下转向T。有办法吗?

2 个答案:

答案 0 :(得分:2)

解决方案可能是使用中间容器:

class vector_holder_base {
public:
    virtual std::size_t size() = 0;
}

template <class T, class... Others>
class vector_holder : public vector_holder_base {
public:
    vector_holder(const std::vector<T, Others...>& val) {...}
    vector_holder(std::vector<T, Others...>&& val) {...}
    vector_holder& operator=(const std::vector<T, Others...>& val) {...}
    vector_holder& operator=(std::vector<T, Others...>&& val) {...}

    std::size_t size() override {
        return values.size();
    }
private:
    std::vector<T, Others...> values;
}

然后你所要做的就是:

boost::any aa = vector_holder<int>(a);
std::size_t count = boost::any_cast<vector_holder_base>(aa).size();

正如您在使用此技巧时所看到的,在检索大小时无需知道矢量模板类型。

然而,您需要考虑矢量的多个副本(将其传递给vector_holder时,然后将vector_holder复制到boost::any时(考虑移动)语义)。

答案 1 :(得分:1)

std::vector<int>std::vector<float>在运行时是不相关的类型。

boost::any类型将复制和提取删除到它自己的类型(确切地),而不再删除。

如果你想采用不相关的(运行时)类型并键入erase其他属性,你应该检查boost.TypeErasure,或者自己做这样的擦除。

或者,增强的any(类型已删除size)可以正常工作。假设C ++ 11支持:

struct sized_any;
typedef std::size_t(sizer_t*)(sized_any const*)>;
template<class ValueType>
struct make_sizer {
  sizer_t operator()() const {
    return [](sized_any const*){return 1;}
  }
};
template<class ValueType, class... Whatever>
struct make_sizer< std::vector<ValueType, Whatever...> > {
  sizer_t operator()() const {
    return [](sized_any const* n){
      // convert n to a const std::vector<ValueType, Whatever...>*
      // invoke .size()
    }
  }
};
struct sized_any : private boost::any {
  sized_any( sized_any const& o ) = default;
  sized_any( sized_any && o ) = default;
  sized_any():boost::any(), size([](sized_any const*){return 0;}) {}
  sized_any & operator=(const sized_any &) = default;
  sized_any & operator=(sized_any &&) = default;
  template<typename ValueType> sized_any(const ValueType &v):boost::any(v), sizer(make_sizer<ValueType>{}())
  {}
  template<typename ValueType> sized_any(ValueType &&v):boost::any(std::move(v)), sizer(make_sizer<ValueType>{}())
  {}
  template<typename ValueType> sized_any & operator=(const ValueType & v){
    this->boost::any::operator=(v);
    sizer=make_sizer<ValueType>{}();
    return *this;
  }
  template<typename ValueType> sized_any & operator=(ValueType && v) {
    this->boost::any::operator=(std::move(v));
    sizer=make_sizer<ValueType>{}();
    return *this;
  }

  ~sized_any() = default;

  // modifiers
  sized_any & swap(sized_any & o) { this->boost::any::swap(o); std::swap( sizer, o.sizer ); }
  std::size_t size() const { return sizer(this); }
private:
  sizer_t sizer;
};

boost::any的私有继承是阻止直接调用boost::any::swap,或者是可以更改boost::any中存储的类型的其他函数。您必须重新执行/转发在boost::any上运行的功能才能在sized_any上运行。

基本设计很简单。我们维护一个boost::any,每当它的类型改变时,我们构建一个新的函数指针,可以从中提取适当的大小。 sizer获取指向我们的sized_any的指针,使我们的复制/赋值操作符更容易,加上它需要的所有状态(因此我们不需要在函数指针中存储任何状态)。

以上不是一个完整的实现,而是一个草图。

必须独立维护额外状态(函数指针),因此any的无状态修改是不可能的。