我当前正在更新一个组件,以使用PMR::Vector容器,而不是STD::Vector。不幸的是,组件是复杂的,并且在组件外部有大量的类层次结构和依赖关系。此外,std::vector是其中许多接口的一部分。
因为std::vector和pmr::vector不兼容,所以我很难隔离组件中的任何更新。由于组件有点大,我想进行增量更新,但我不能考虑一个好的方法来这样做,这并不是因为缺乏努力。
通常,我会使用适配器类并重写对基类的函数调用,如下所示。
class OldClass { public: virtual ~OldClass() = default; virtual std::vector DoSomething() const { return some std::vector; } }; class NewClass { public: pmr::vector DoSomething() const { return some pmr::vector; } }; class Adapter : public OldClass { private: NewClass *adaptee_; public: Adapter(NewClass *adaptee) : adaptee_(adaptee) {} pmr::vec DoSomething() const override { } };
class ComponentObjects { public: struct ObjectParameters { size_t number_of_steps; double time; }; ComponentObjects(ObjectParameters one, ObjectParameters two); void Update(const std::vector<OtherClass>& par1, const OtherClassTwo& par2, const double par4, const OtherClassThree& par5, OtherClassFour<>* par6, uint64_t par7, const OtherClassFive& par8, const OtherClassSix& par9); const std::vector<OtherClassSeven>& DoSomething() const { return priv_mem_one; } const std::vector<OtherClassEight>& DoSomethingElse() const { return priv_mem_two; } private: std::vector<ClassA> priv_mem_one{}; std::vector<ClassA> priv_mem_two{}; const ObjectParameter par_one_{}; const ObjectParameter par_two_{}; };
事先谢谢你的帮助。
从std::vector
到pmr::vector
的增量转换的一个选项是键入擦除API上的vector
对象,而使用一个既可转换为std::vector
又可转换为pmr::vector
的对象。如果此转换是隐式的,则当您更改组件以使用PMR
时,旧代码将继续工作而不作更改
您可以简单地在任何地方使用一个转换函数--但这可能导致在每个组件上进行较小的增量更改所需的大量更改。将其隐藏在类型之后,使得在转换发生时,旧代码的行为与以前一样。
关于如何实现这一点的一个简短的提纲是执行以下操作
std::vector
和std::pmr::vector
之间创建转换函数,反之亦然std::vector
和std::pmr::vector
中隐式构造,std::vector
和std::pmr::vector
以及我将在下面更详细地讨论这一点。
我必须强调,这种代价是暂时的,因为一旦一切都过渡过去,它就会消失。
您仍然需要转换实用程序,正如Mikael在他的回答中所建议的那样;这些将为自动转换对象奠定基础。
我制作了一个简单的转换器,它只需根据allocator
类型更改vector
。这没有考虑pmr类型的新memory_resource
--因此根据需要,您可能需要更多的内容。
// Conversion functions for copying/moving between vectors
namespace detail {
// Conversion that copies all entries (const lvalue vector)
template <typename NewAllocator, typename T, typename OldAllocator>
std::vector<T, NewAllocator> convert_vector(const std::vector<T, OldAllocator>& v)
{
auto result = std::vector<T, NewAllocator>{};
result.reserve(v.size());
result.assign(v.begin(), v.end());
return result;
}
// conversion that moves all entries (rvalue vector)
template <typename NewAllocator, typename T, typename OldAllocator>
std::vector<T, NewAllocator> convert_vector(std::vector<T, OldAllocator>&& v)
{
auto result = std::vector<T, NewAllocator>{};
result.reserve(v.size());
result.assign(
std::make_move_iterator(v.begin()),
std::make_move_iterator(v.end())
);
return result;
}
} // namespace detail
有了这个,我们只需要一个简单的类型,我们可以在API上使用它,以某种方式对向量进行规范化。我们需要两个关键的东西:
std::vector
和std::pmr::vector
中隐式构造,那么我们可以将此类型用于API上的参数--因为它可以接受这两者。std::vector
和std::pmr::vector
,那么我们可以在组件的返回类型上使用它,因为使用者可以直接赋值给它,它就“正常工作”。所以让我们制作这样的类型:
// Type erased class that can behave as either vector
// Normalizes all vectors to a std::pmr::vector
template <typename T>
class AnyVector
{
public:
// Implicitly constructible from both std::vector and pmr::vector
// std::vector overloads need to convert to pmr::vector
AnyVector(const std::vector<T>& vec)
: m_storage{detail::convert_vector<std::pmr::polymorphic_allocator<T>>(vec)}
{}
AnyVector(std::vector<T>&& vec)
: m_storage{detail::convert_vector<std::pmr::polymorphic_allocator<T>>(std::move(vec))}
{}
AnyVector(const std::pmr::vector<T>& vec) // no cost
: m_storage{vec}
{}
AnyVector(std::pmr::vector<T>&& vec) // no cost
: m_storage{std::move(vec)}
{}
AnyVector(const AnyVector&) = default;
AnyVector(AnyVector&&) = default;
// AnyVector& operator= for vector objects is less important, since this is meant
// to exist on the API boundaries -- but could be implemented if there's a need.
// Implicitly convertible to std::vector
operator std::vector<T>() const
{
return detail::convert_vector<std::allocator<T>>(current);
}
operator std::vector<T>() &&
{
return detail::convert_vector<std::allocator<T>>(std::move(current));
}
// Implicitly convertible to std::pmr::vector
operator std::pmr::vector<T>() const
{
return m_storage;
}
operator std::pmr::vector<T>() &&
{
return std::move(m_storage);
}
private:
std::pmr::vector<T> m_storage;
};
这很简单:它是一个可以从std::vector
和std::pmr::vector
隐式构造的类型,它也可以转换为这两种类型。在内部,它在std::pmr::vector
上保持规范化,因为这是最终目标。
现在,您可以在您想要支持转换的API上使用它。使用问题中的代码:
class ComponentObjects
{
public:
...
void Update(AnyVector<OtherClass> par1,
const OtherClassTwo& par2,
const double par4,
const OtherClassThree& par5,
OtherClassFour<>* par6,
uint64_t par7,
const OtherClassFive& par8,
const OtherClassSix& par9);
AnyVector<OtherClassSeven> DoSomething() const { return priv_mem_one; }
AnyVector<OtherClassEight> DoSomethingElse() const { return priv_mem_two; }
private:
std::pmr::vector<ClassA> priv_mem_one{};
std::pmr::vector<ClassA> priv_mem_two{};
const ObjectParameter par_one_{};
const ObjectParameter par_two_{};
};
这里需要注意的事项:
要检查向量是否为空,我可以使用或。我查看了cplike上的签名,但缺乏理解它们的知识。它们如何相互关联?一个实现调用另一个实现吗? 我知道其中一个来自容器库,另一个来自迭代器库,但仅此而已。
https://godbolt.org/z/P97MaK 我玩的概念和预期d::is_equality_comparable工作矢量,但它没有。 编译错误在 内部失败,而不是在受概念保护的函数边界处失败。 这是错误还是预期行为?
我以前见过这样做,但我不记得如何有效地初始化已知长度的与长度相同的。这里有一个很好的例子: 我已经仔细阅读了这一页关于高级矩阵初始化的内容,但是没有明确解释执行此操作的方法。
下面的代码显示了我要做的:
错误:无法将类型为“std::_bit_reference&”的非常量lvalue引用绑定到类型为“std::vector::reference”{aka“std::_bit_reference”}的rvalue 因此,它抱怨,因为只有第二个参数是rvalue
我有一个整数向量: 考虑到将始终为偶数。 我只是想把相邻的元素转换成一对,像这样: 即,两个相邻元件接合成一对。 我可以使用什么STL算法轻松实现这一点?有没有可能通过一些标准算法来实现这一点? 当然,我可以很容易地编写一个旧的索引for循环来实现这一点。但我想知道最简单的解决方案是什么,使用rangebased for循环或任何其他STL算法,比如,等等。