我将值存储在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
。有办法吗?
答案 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
的无状态修改是不可能的。