繁体   English   中英

继承抽象迭代器接口

[英]Inheriting a abstract iterator interface

我想为容器类继承一个迭代器。 它应始终具有与实际实现无关的相同签名。

但我在这个问题ContainerImpl返回的Container::IteratorContainerImpl::begin()切片从覆盖的方法ContainerImpl::Iterator返回的那些Container::Iterator

如何强制使用更具体的方法? 还是可以重写我的类,使其表现得像那样?

下面是一个工作示例。 它至少针对C ++ 17进行编译。

#include <tuple>

using std::tuple;

class Container {
    // some code

public:

    class Iterator {
    public:
        virtual tuple<int, int> &operator*() {};

        virtual Iterator &operator++() {};

        virtual bool operator!=(const Iterator &rhs) const {};
    };

    virtual Iterator begin() = 0;

    virtual Iterator end() = 0;
};

class ContainerImpl : public Container {
    // some code

public:

    class Iterator : public Container::Iterator {
    public:
        Iterator(ContainerImpl &containerImpl) {
            // init
        }

        Iterator() {
            // end_iterator
        }

        virtual tuple<int, int> &operator*() override {
            // impl
        };

        virtual Container::Iterator &operator++() override {
            // impl
        };

        virtual bool operator!=(const Container::Iterator &rhs) const override {
            // impl
        };
    };

    virtual Container::Iterator begin() override {
        return Iterator{*this};
    };

    virtual Container::Iterator end() override {
        return Iterator{};
    };
};


int main() {
    ContainerImpl cont{};
    for (auto &entry : cont) {
        // here Container::Iterator::operator++() is called
        // instead of ContainerImpl::Iterator::operator++()
    }
}

编辑:

谢谢! 我通读了您的评论,并发现我应该尝试使用模板的静态方法。 对于那些迭代器,性能非常重要。 这将需要在我使用此代码的地方重构其他代码。 但这应该适中。

这是我想出的:

#include <tuple>
#include <type_traits>

using std::tuple;

template<class SubContainer>
class Container;


template<class ContImpl>
class Iterator {
    static_assert(std::is_base_of<Container<ContImpl>, ContImpl>::value, "ContImpl not derived from Container");
public:

    tuple<int, int> &operator*();

    Iterator<ContImpl> &operator++();

    bool operator!=(const Iterator<ContImpl> &rhs) const;
};



template<class SubContainer>
class Container {
public:
    Iterator<SubContainer> begin();

    Iterator<SubContainer> end();

};

class ContImpl;

template<>
class Iterator<ContImpl> {
public:
    ContImpl &container;

    Iterator(ContImpl &container, bool is_end = false) : container(container) { init(); }

    void init() {
    }

    tuple<int, int> &operator*() {
    }

    Iterator<ContImpl> &operator++() {
    }

    bool operator!=(const Iterator<ContImpl> &rhs) const {
    }
};

class ContImpl : public Container<ContImpl> {
public:
    Iterator<ContImpl> begin() {
        return Iterator<ContImpl>(*this, false);
    }

    Iterator<ContImpl> end() {
        return Iterator<ContImpl>(*this, true);
    }
};


int main() {
    ContImpl cont{};
    for (auto &entry : cont) {
        // Iterator<ContImpl>::operator++() is called.
    }
}

如果您想动态地抽象出例如std::list<int>std::vector<int>之间的差异,那么您想要的就是类型Erase 但是请注意,使用模板模板参数之类的东西,还可以对具有相似接口(具有相同或不同元素类型)的容器进行静态抽象,这(如果满足您的要求)应该更快。

关于基于模板的方法:虽然它可能具有文档价值,但Container中的方法是不必要的:静态多态不需要任何“基本函数”来覆盖。 如果删除它们,则可以完全不用该CRTP类。 然后,类似地,您可以用简单的类ContImpl::iterator替换Iterator类模板。

当然,到那时,剩下的就是与标准容器之间相同的接口兼容性(它允许类似

template<template<class> class C>
C<int> makeInts(/*...*/);

void f() {
  auto d=makeInts<std::deque>(/*...*/);
  // ...
}

我在上面建议)。 有趣的练习是在包装器类后面或使用traits接口隐藏另一个容器接口。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM