2016-02-04 68 views
1

我有有std::shared_ptr秒的私人收藏,像類派生:從標準容器的迭代器

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*(); 
    } 
}; 

然後換Foo提供beginend方法:

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

只要繼承是私有的,就可以從幾乎任何類中安全地派生出來。您需要使用'聲明來重新導出您想要訪問的成員。 –

回答

3

雖然大多數類型的標準庫沒有被設計成可以源自,在這種情況下,應該沒問題。繼承的兩個危險是切割和非虛擬破壞;對於迭代器來說,這些都不會發生。沒有切片,因爲迭代器作爲模板參數傳遞,因此總是使用確切類型,並且沒有非虛擬銷燬,因爲沒有人會在自由存儲中創建迭代器的副本,並通過指向基本類型的指針刪除它們(假設他們可以弄清楚它是什麼)。

編輯:爲迪特爾·勒金所指出的,你還需要爲iterator_type符合您的類型提供一個typedef:

typedef Iterator iterator_type; 

編輯:爲迪特爾·勒金指出,獨此一家是不夠的。您提供了operator*,並且需要提供所有引用該運算符的返回類型的typedef。

+0

沒有沒有那個typedef,你需要指針,value_type和引用 –

+0

@DieterLücking - 是不是從基類繼承的足夠? –

+0

不,value_type是shared_ptr ,但迭代器返回T –

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); 
} 

到這一點,你可以使用任何隨機訪問迭代器(向量,雙端隊列,...),並使用任何指針類型(原始指針,shared_ptr的, ...)

注意:在你的情況下 - 當你從載體的迭代器派生時,你也必須調整類型定義。

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