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是抽象的。我希望通过使用引用而不是指针来增加安全性。