C++ 引用包装的常量正确性
在各种情况下,我有一个集合,例如需要由许多函数处理的对象向量。一些函数需要修改对象,而其他函数则不需要。对象的类可以从抽象基类继承。因此,我有这样的想法:C++ 引用包装的常量正确性,c++,c++11,reference-wrapper,C++,C++11,Reference Wrapper,在各种情况下,我有一个集合,例如需要由许多函数处理的对象向量。一些函数需要修改对象,而其他函数则不需要。对象的类可以从抽象基类继承。因此,我有这样的想法: class A { public: virtual void foo() const = 0; virtual void bar() = 0; /* ... */ }; void process_1(std::vector<std::reference_wrapper<A>> const &
class A
{
public:
virtual void foo() const = 0;
virtual void bar() = 0;
/* ... */
};
void process_1(std::vector<std::reference_wrapper<A>> const &vec);
void process_2(std::vector<std::reference_wrapper<A const>> const &vec);
显然,我不能将相同的std::reference_包装向量同时传递给进程_1和进程_2。到目前为止,我考虑的解决方案包括:
对vec引用使用C样式转换或重新解释_转换
编写自己的引用包装器,其中包含T&get和T const&get const,而不是T&get const
使用例如采用包装器而不是向量的方法进行重构
有带常数和不带常数的向量的副本
在reference\u包装器的参数中不使用const
这些似乎都不是很优雅。还有什么我可以做的吗?范围适配器
范围适配器将范围作为输入。容器是一个范围,因为它具有开始和结束返回迭代器,并返回具有不同属性的范围
在取消引用迭代器时,您会将引用包装器强制转换为const变量
boost有迭代器,可以为您完成转换迭代器,以及帮助编写一致性迭代器的工具,但它可以通过一些工作从零开始完成
一点额外的工作甚至可以使类型名保持正常。范围适配器
范围适配器将范围作为输入。容器是一个范围,因为它具有开始和结束返回迭代器,并返回具有不同属性的范围
在取消引用迭代器时,您会将引用包装器强制转换为const变量
boost有迭代器,可以为您完成转换迭代器,以及帮助编写一致性迭代器的工具,但它可以通过一些工作从零开始完成
一点额外的工作甚至可以使字体名称保持正常。即使缺乏优雅,我也会做一个参考包装:
#include <functional>
template <typename T>
class ReferenceWrapper
{
public:
ReferenceWrapper(T& ref)
: m_ref(ref)
{}
ReferenceWrapper(const std::reference_wrapper<T>& ref)
: m_ref(ref)
{}
const T& get() const noexcept { return m_ref.get(); }
T& get() noexcept { return m_ref.get(); }
operator const T& () const noexcept { return m_ref.get(); }
operator T& () noexcept { return m_ref.get(); }
private:
std::reference_wrapper<T> m_ref;
};
这是一个模拟原始需求的小类。即使缺乏优雅,我也会做一个参考包装:
#include <functional>
template <typename T>
class ReferenceWrapper
{
public:
ReferenceWrapper(T& ref)
: m_ref(ref)
{}
ReferenceWrapper(const std::reference_wrapper<T>& ref)
: m_ref(ref)
{}
const T& get() const noexcept { return m_ref.get(); }
T& get() noexcept { return m_ref.get(); }
operator const T& () const noexcept { return m_ref.get(); }
operator T& () noexcept { return m_ref.get(); }
private:
std::reference_wrapper<T> m_ref;
};
它是一个模拟原始需求的小类。我不认为有一个引用为常量的引用包装器有什么意义。这不是为了修改其他位置的数据,而是为了共享数据的所有权。这就是std::shared_ptr的设计目的,并且工作得非常好。我认为std::reference_包装器只设计用于非常量引用,这解释了为什么只提供了一个T&get const重载。std::shared_ptr也有T*get const,所以我认为在这种情况下它对我没有帮助。我可能应该提到A是抽象的。我希望通过使用引用而不是指针来增加一些安全性。我不认为有一个引用为常量的引用包装器有什么意义。这不是为了修改其他位置的数据,而是为了共享数据的所有权。这就是std::shared_ptr的设计目的,并且工作得非常好。我认为std::reference_包装器只设计用于非常量引用,这解释了为什么只提供了一个T&get const重载。std::shared_ptr也有T*get const,所以我认为在这种情况下它对我没有帮助。我可能应该提到A是抽象的。我希望通过使用引用而不是指针来增加安全性。