从标准容器迭代器派生

时间:2016-02-04 16:49:24

标签: c++ stl iterator

我有一个拥有std::shared_ptr s私人集合的类,如:

class Foo
{
private:
     using Bars = std::vector<std::shared_ptr<Bar>>;
     Bars items_;
}

给定Foo的实例,我希望能够直接迭代Bar中的items_个对象 - 隐藏该集合实际上包含指针。我认为唯一需要从Bars::const_iterator更改的内容是operator*,是否可以从中导出并实现operator*?即。

class Iterator : public Bars::const_iterator
{
public:
    Iterator(Bars::const_iterator it) : Bars::const_iterator {it} {}

    const string& operator*() const
    {
        return *Bars::const_iterator::operator*();
    }
};

然后为begin提供endFoo方法:

Foo::Iterator Foo::begin() const noexcept { return Iterator {std::cbegin(items_)}; }
Foo::Iterator Foo::end()   const noexcept { return Iterator {std::cend(items_)}; }

2 个答案:

答案 0 :(得分:3)

虽然标准库中的大多数类型都不是为了派生而来的,但在这种情况下应该没问题。继承的两个危险是切片和非虚拟破坏;对于迭代器来说,这些都不会发生。没有切片因为迭代器是作为模板参数传递的,所以总是使用确切的类型,并且没有非虚拟破坏,因为正确思想中的任何人都不会在免费存储上创建迭代器的副本,并通过指向基类型的指针删除它们(假设他们可以弄清楚它是什么。)

编辑:正如DieterLücking指出的那样,你还需要为iterator_type提供与你的类型匹配的typedef:

typedef Iterator iterator_type;
编辑:正如DieterLücking指出的那样,单凭这一个还不够。您正在提供operator*,并且需要提供引用该运算符的返回类型的所有typedef。

答案 1 :(得分:3)

为了灵活性,你可以写一个适配器:

#include <type_traits>

template <typename Iterator>
class random_access_pointer_iterator
{
    // Types
    // =====

    public:
    typedef Iterator iterator_type;
    typedef std::random_access_iterator_tag iterator_category;
    using difference_type = typename iterator_type::difference_type;
    using pointer = decltype(&**std::declval<iterator_type>());
    using value_type = typename std::remove_pointer<pointer>::type;
    typedef value_type& reference;

    // Construction
    // ============

    public:
    explicit random_access_pointer_iterator(iterator_type iterator)
    :   m_iterator(iterator)
    {}

    // Element Access
    // ==============

    public:
    const iterator_type& base() const { return m_iterator; }
    iterator_type& base() { return m_iterator; }
    operator iterator_type () const { return m_iterator; }

    // Iterator
    // ========

    public:
    reference operator * () const { return **m_iterator; }
    pointer operator -> () const { return &(**m_iterator); }

    random_access_pointer_iterator& operator ++ () {
        ++m_iterator;
        return *this;
    }
    random_access_pointer_iterator operator ++ (int) {
        random_access_pointer_iterator tmp(*this);
        ++m_iterator;
        return tmp;

    }
    random_access_pointer_iterator& operator += (difference_type n) {
        m_iterator += n;
        return *this;
    }

    random_access_pointer_iterator& operator -- () {
        --m_iterator;
        return *this;
    }
    random_access_pointer_iterator operator -- (int) {
        random_access_pointer_iterator tmp(*this);
        --m_iterator;
        return tmp;
    }

    random_access_pointer_iterator& operator -= (difference_type n) {
        m_iterator -= n;
        return *this;
    }

    private:
    iterator_type m_iterator;
};

template <typename Iterator>
inline random_access_pointer_iterator<Iterator> operator + (
    random_access_pointer_iterator<Iterator> i,
    typename random_access_pointer_iterator<Iterator>::difference_type n) {
    return i += n;
}

template <typename Iterator>
inline random_access_pointer_iterator<Iterator> operator - (
    random_access_pointer_iterator<Iterator> i,
    typename random_access_pointer_iterator<Iterator>::difference_type n) {
    return i -= n;
}

template <typename Iterator>
inline typename random_access_pointer_iterator<Iterator>::difference_type
operator - (
    const random_access_pointer_iterator<Iterator>& a,
    const random_access_pointer_iterator<Iterator>& b) {
    return a.base() - b.base();
}

template <typename Iterator>
inline bool operator == (
    const random_access_pointer_iterator<Iterator>& a,
    const random_access_pointer_iterator<Iterator>& b) {
    return a.base() == b.base();
}

template <typename Iterator>
inline bool operator != (
    const random_access_pointer_iterator<Iterator>& a,
    const random_access_pointer_iterator<Iterator>& b) {
    return a.base() != b.base();
}

template <typename Iterator>
inline bool operator <  (
    const random_access_pointer_iterator<Iterator>& a,
    const random_access_pointer_iterator<Iterator>& b) {
    return a.base() <  b.base();
}

template <typename Iterator>
inline bool operator <= (
    const random_access_pointer_iterator<Iterator>& a,
    const random_access_pointer_iterator<Iterator>& b) {
    return a.base() <= b.base();
}

template <typename Iterator>
inline bool operator >  (
    const random_access_pointer_iterator<Iterator>& a,
    const random_access_pointer_iterator<Iterator>& b) {
    return a.base() >  b.base();
}

template <typename Iterator>
inline bool operator >= (
    const random_access_pointer_iterator<Iterator>& a,
    const random_access_pointer_iterator<Iterator>& b) {
    return a.base() >= b.base();
}


#include <cassert>
#include <memory>
#include <vector>

int main() {
    using vector = std::vector<std::shared_ptr<int>>;
    auto p = std::make_shared<int>(0);
    vector v = { p };

    using iterator = random_access_pointer_iterator<vector::iterator>;
    iterator a(v.begin());
    iterator b(v.end());

    assert(*a == 0);
    assert(a.operator -> () == &*p);
    ++a;
    assert(a == b);
    --a;
    assert(a != b);
    assert(a++ != b);
    assert(a-- == b);
    assert(a + 1 == b);
    assert(a == b - 1);
    assert(b - a == 1);
    assert(a <  b);
    assert(a <= b);
    assert(b >  a);
    assert(b >= a);
}

有了这个,你可以使用任何随机访问迭代器(vector,deque,...)并使用任何指针类型(原始指针,shared_ptr,...)

注意:在您的情况下 - 当您从向量的迭代器派生时,您也必须调整类型定义。

注意:我不喜欢'random_access_pointer_iterator',但我没有更好的想法。