纯虚方法采用各种迭代器?

Man*_*d3r 4 c++

让多态基类insert在 stl 容器成员(本例中为向量)上有一个纯虚方法。该函数应该能够采用集合、向量、列表等容器的迭代器,但也要考虑引用的类型(移动语义)

\n

函数的纯虚拟性质使得使用模板函数变得不可能。据我所知,stl 容器的迭代器是单独的类型,这就是模板有用的原因。然而,多态性是必要的。我还注意到 std::move_iterator 能够封装所有类型的迭代器。

\n

是否还有其他“迭代器包装器”,我可以用它来在 Base 中定义纯虚拟方法,该方法接受各种迭代器,并且也像完美转发函数模板一样,以便客户端可以传递迭代器并移动迭代器?

\n

在引入多态性之前,函数是这样的:

\n
vector<Class> v;\ntemplate<typename Iter>\nvoid insert(Iter begin, Iter end) {\n    v1.insert(begin, end, std::end(v));\n}\n
Run Code Online (Sandbox Code Playgroud)\n

但现在派生类在插入时的行为略有不同(互斥体、通知观察者等)。如果有类似下面的东西那就太好了:

\n
vector<Class> v;\n\nvirtual void Base::insert(GenericIter begin, GenericIter end) = 0;\n\n[\xe2\x80\xa6]\n\nvoid DerivedMT::insert(GenericIter begin, GenericIter end) override\n{\n    mutex.lock();\n    v1.insert(begin, end, std::end(v));\n    mutex.unlock();\n}\n\n[\xe2\x80\xa6]\n\nvoid DerivedObserved::insert(GenericIter begin, GenericIter end) override\n{\n    v1.insert(begin, end, std::end(v));\n    notifyObservers();\n}\n
Run Code Online (Sandbox Code Playgroud)\n

Ser*_*nik 5

您不能接受所有各种迭代器并维护运行时多态性,因为这样您就会违反里氏替换原则。也就是说,多态双向迭代器不适用于包装前向迭代器,因为后者只能递增。还有排序的关联容器,您不能使用其迭代器进行排序等:

  • 如果实现者不想跳过,而是对元素进行排序
  • 如果实现者想要进行特定类型的搜索

因此,函数模板迭代器的目的是为接口实现者提供一种自由,让他可以在有两个迭代器的情况下做任何他想做的事情。但是使用运行时多态迭代器,您限制了实现者(您应该这样)。

所以有两种方法:

  1. 幼稚的。只需声明您的接口即可insert(std::vector<YourType>)。这将处理您想要的所有通用迭代器,并且实现者可以自由地对该范围做任何他想做的事情。
  2. PolymorphicForwardIterator使用前向迭代器和类型擦除的特征来实现 const 。

以下是如何在不进行堆分配的情况下删除类型的示例:

class PolymorphicReference final
{
public:
    template <typename RefT>
    explicit PolymorphicReference(RefT &ref)
        : pVTable_(std::addressof(GetVTable(ref))),
          ref_(std::addressof(ref))
    {}

    void Say(const std::string& msg)
    {
        pVTable_->pSay(ref_, msg);
    }

    int Number() const
    {
        return pVTable_->pNumber(ref_);
    }

private:
    struct VTable
    {
        virtual void pSay(void *pRef, const std::string& msg) = 0;
        virtual int pNumber(const void *pRef) = 0;

    protected:
        ~VTable() = default;
    };

    template <typename RefT>
    static VTable &GetVTable(const RefT&)
    {
        struct : VTable
        {
            void pSay(void *pRef, const std::string& msg) override
            {
                static_cast<RefT*>(pRef)->Say(msg);
            }
            int pNumber(const void *pRef) override
            {
                return static_cast<const RefT*>(pRef)->Number();
            }
        } static vTable;

        return vTable;
    }

private:
    VTable *pVTable_;
    void *ref_;
};
Run Code Online (Sandbox Code Playgroud)