2017-09-26 44 views
1

中實現標準迭代器我有一些通常使用標準容器作爲基礎字段的類。例如,我有一個類如何在類

template <typename T> 
class Vec_3D 
{ 
public: 
    /* ... */ 
    std::array<T, 3> vec; 
    /* ... */ 
}; 

它只有一個變量vec,其餘都只是功能與向量工作時,我需要的。我希望能夠使用的範圍爲基礎的for循環如

Vec_3D<double> vec; 
for (double val : vec) {/*...*/} 

應obviusly遍歷std::array<double, 3>

如何在我的類中實現迭代器,它應該反過來調用迭代器std::array<T, 3>

我開始與this question,並試圖在我的課定義爲迭代器

typedef std::iterator<std::random_access_iterator_tag, T, ptrdiff_t, T*, T&> iterator; 
typedef std::iterator<std::random_access_iterator_tag, const T, ptrdiff_t, const T*, const T&> const_iterator; 

inline iterator begin() noexcept { return vec.begin(); } 
inline const_iterator cbegin() const noexcept { return vec.cbegin(); } 
inline iterator end() noexcept { return vec.end(); } 
inline const_iterator cend() const noexcept { return vec.end(); } 

,但得到編譯錯誤

error: no match for ‘operator!=’ (operand types are ‘Vec_3D<double>::iterator {aka std::iterator<std::random_access_iterator_tag, double, long int, double*, double&>}’ and ‘Vec_3D<double>::iterator {aka std::iterator<std::random_access_iterator_tag, double, long int, double*, double&>}’) 

operator++, operator*

+1

'std :: iterator'不是你認爲的那樣 –

回答

4

一系列爲基礎的循環只需要您的類有begin()end()方法(或std::begin()std::end()重載)返回迭代器。它並不關心那些迭代器來自哪裏。所以,最簡單的解決方法就是使用,而不是試圖定義自己,例如數組自己的迭代器:

template <typename T> 
class Vec_3D 
{ 
public: 
    typedef typename std::array<T, 3> array_type; 
    typedef typename array_type::iterator iterator; 
    typedef typename array_type::const_iterator const_iterator; 
    // or: 
    // using array_type = std::array<T, 3>; 
    // using iterator = array_type::iterator; 
    // using const_iterator = array_type::const_iterator; 
    ... 

    inline iterator begin() noexcept { return vec.begin(); } 
    inline const_iterator cbegin() const noexcept { return vec.cbegin(); } 
    inline iterator end() noexcept { return vec.end(); } 
    inline const_iterator cend() const noexcept { return vec.end(); } 
    ... 

private: 
    array_type vec; 
}; 
+0

你應該解釋爲什麼'std :: iterator'不工作 –

2

的std :: iterator是一個基類只是,它基本上是一些特性的容器,但如果你想用它來實現你自己的迭代器類,你需要從它派生出來。

但是,您不需要使用它,有人建議不要使用它,您可以直接在您編寫的迭代器中定義這些特徵。下面的問題對建議的信息,並實現一個迭代器類幫助: - Preparation for std::iterator Being Deprecated

在您使用的基地,而不是一個類,實際上可以做任何迭代定義你的容器的迭代器類型的那一刻,這是爲什麼失敗。

您將該陣列公開爲公共成員。如果你很高興公開你的vec_3d是使用數組實現的(無論你是否繼續公開公開的成員數組),那麼你可以使用數組的迭代器 - 從你的迭代器需要任何定製行爲只是因爲你的容器增加了一些功能。

3

std::iterator是(是)一個輔助類型來定義typedef s表示一個典型的迭代器要求。類中的這些類型定義依次使std::iterator_traits與您的迭代器一起工作。

但是,它並沒有爲您實際實施所需的操作。

它被棄用,因爲std委員會不喜歡指定標準迭代器必須具有這些typedef,並且編寫typedefs並不比定義傳遞給std::iterator模板的參數體積大得多。

這裏要做的很簡單的事情就是竊取你的底層容器的迭代器。這會讓你的抽象泄漏,但它是高效和簡單的。

template <typename T> 
struct Vec_3D { 
    using container=std::array<T, 3>; 
    using iterator=typename container::iterator; 
    using const_iterator=typename container::const_iterator; 

    iterator begin() { return vec.begin(); } 
    iterator end() { return vec.end(); } 
    const_iterator begin() const { return vec.begin(); } 
    const_iterator end() const { return vec.end(); } 
private: 
    /* ... */ 
    container vec; 
    /* ... */ 
}; 

如果你不想暴露你的基礎容器類型,如果你願意保證您的基礎容器是一個連續的緩衝區,你可以這樣做:

template <typename T> 
struct Vec_3D { 
    using iterator=T*; 
    using const_iterator=T const*; 

    iterator begin() { return vec.data(); } 
    iterator end() { return vec.data()+vec.size(); } 
    const_iterator begin() const { return vec.data(); } 
    const_iterator end() const { return vec.data()+vec.size(); } 
private: 
    /* ... */ 
    std::array<T,3> vec; 
    /* ... */ 
}; 

的指針是有效的迭代器。

如果你發現你正在寫這個「我修改的集裝箱」樣板太多,你可以自動執行它:

template<class Container> 
struct container_wrapper { 
    using container=Container; 

    using iterator=typename container::iterator; 
    using const_iterator=typename container::const_iterator; 

    iterator begin() { return m_data.begin(); } 
    iterator end() { return m_data.end(); } 
    const_iterator begin() const { return m_data.begin(); } 
    const_iterator end() const { return m_data.end(); } 
protected: 
    Container m_data; 
}; 

然後

template <typename T> 
class Vec_3D:private container_wrapper<std::array<T,3>> { 
    // ... 
}; 

但即使這樣可能會有點很多,爲什麼不只是:

template <typename T> 
class Vec_3D:public std::array<T,3> { 
    // ... 
}; 

確實,刪除Vec_3D通過指針指向ba se是未定義的行爲,但誰刪除指向標準容器的指針?

如果你擔心:

template <typename T> 
class Vec_3D: private std::array<T,3> { 
    using container = std::array<T,3>; 
    using container::begin(); 
    using container::end(); 
    // ... 
}; 

讓你繼承私下,然後把某些操作放回範圍。

+1

@bob是的我有。 – Yakk