看起来如果不修改构造函数boost::container::flat 是不可能的。
在不修改任何一个类的情况下,似乎只有 hack 才能做到这一点,例如使用reinterpret_cast。
我找到的解决方案是使用vector 的替代实现或非常丑陋的代码。
在进入我的解决方案之前,我必须说这可能是一个
两个类的缺陷。这些类应该有一组
release()/aquire(start, end)函数分别表示
返回指向释放所有权的数据的指针范围和
从那时起获取拥有它的指针范围。另一种选择可能是
有一个构造函数,该构造函数从任何其他具有
数据成员函数。
使用reinterpret_cast 和vector 的不同实现的解决方案
原来reinterpret_casting 从std::vector 到boost::container::flat_set 是不可能的,因为布局不兼容。
但是,可以开箱即用地将 boost::container::vector 重新解释为 boost::container::flat_set(这是因为它们有一个共同的实现)。
#include<cassert>
#include<boost/container/flat_set.hpp>
int main(){
boost::container::vector<double> v = {1.,2.,3.};
boost::container::flat_set<double> fs = std::move(reinterpret_cast<boost::container::flat_set<double>&>(v));
assert(v.size() == 0);
assert(*fs.find(2.) == 2.);s
assert(fs.find(4.) == fs.end());
}
所以,我可以将std::vector 替换为boost::container::vector,然后我可以将数据移动到flat_set。
使用std::vector 和丑陋代码的非便携式解决方案
std::vector和boost::container::vector的布局不同的原因是boost::container::vector是这样存储元数据的:
class boost::container::vector{
pointer m_start;
size_type m_size;
size_type m_capacity;
}
而std::vector(在 GCC 中)基本上是纯指针,
class std::vector{
pointer _M_start;
pointer _M_finish;
pointer _M_end_of_storage;
}
因此,我的结论是,鉴于我使用的 std::vector 的实现与 boost::container::flat_set 不兼容,因此只有通过 hack 才能移动。
在极端情况下,可以这样做(对不起,如果此代码冒犯了某人,该代码不可移植):
template<class T>
boost::container::flat_set<T> to_flat_set(std::vector<T>&& from){
// struct dummy_vector{T* start; T* finish; T* end_storarge;}&
// dfrom = reinterpret_cast<dummy_vector&>(from);
boost::container::flat_set<T> ret;
struct dummy_flat_set{T* start; std::size_t size; std::size_t capacity;}&
dret = reinterpret_cast<dummy_flat_set&>(ret);
dret = {from.data(), from.size(), from.capacity()};
// dfrom.start = dfrom.finish = dfrom.end_storarge = nullptr;
new (&from) std::vector<T>();
return ret;
};
int main(){
std::vector<double> v = {1.,2.,3.};
boost::container::flat_set<double> fs = to_flat_set(std::move(v));
assert(v.size() == 0);
assert(*fs.find(2.) == 2.);
assert(fs.find(4.) == fs.end());
}
请注意,我根本没有考虑分配器问题。我不确定如何在这里处理分配器。
回想起来,对于这个特定问题,我不介意使用cast 的形式,因为我必须以某种方式告诉向量在移动到flat_set 之前已排序。 (问题是这变得极端,因为它是reinterpret_cast。)
不过这是次要问题,应该有合法的方式从std::vector 转移到boost::container::vector。