簡體   English   中英

在 c++ 中實現 const_iterator 時遇到問題

[英]Trouble implementing const_iterator in c++

我正在努力嘗試為我的容器 class 實現一個 const_iterator,我用一個基本數組做了一個簡短的可復制示例來顯示問題(我知道std::iterator已被棄用,但這是針對 C++98 標准中的一個項目):

#include <iostream>
#include <cstdlib>
#include <iterator>

template <
    typename T
> struct remove_const { typedef T type; };
template <
    typename T
> struct remove_const < const T > { typedef T type; };

template <
    typename T
> struct add_const { typedef const T type; };

template <
    class T,
    std::size_t size
> class Array {
    public:
        template <
            class U
        > class base_iterator : public std::iterator <
            std::random_access_iterator_tag,
            U
        > {
            public:
                typedef std::iterator <
                    std::random_access_iterator_tag,
                    U
                >   iterator_type;

                base_iterator() : ptr(NULL) { }
                base_iterator(U *p) : ptr(p) { }
                base_iterator(const base_iterator &other) : ptr(other.ptr) { }
                base_iterator(const base_iterator< remove_const< U > > &other) : ptr(other.ptr) { }
                base_iterator(const base_iterator< add_const< U > > &other) : ptr(other.ptr) { }

                base_iterator   &operator =(const base_iterator &other) {
                    ptr = other.ptr;
                    return *this;
                }
                base_iterator   &operator =(const base_iterator< remove_const< U > > &other) {
                    ptr = other.ptr;
                    return *this;
                }
                base_iterator   &operator =(const base_iterator< add_const< U > > &other) {
                    ptr = other.ptr;
                    return *this;
                }
                U               &operator *(void) { return *ptr; }
                U               &operator *(void) const { return *ptr; }
                U               *operator ->(void) { return ptr; }
                U               *operator ->(void) const { return *ptr; }
                base_iterator   &operator ++(void) {
                    ++ptr;
                    return *this;
                }
                base_iterator   operator ++(int) {
                    return base_iterator(ptr++);
                }
                base_iterator   &operator --(void) {
                    --ptr;
                    return *this;
                }
                base_iterator   operator --(int) {
                    return base_iterator(ptr++);
                }
                base_iterator   operator +(const typename iterator_type::difference_type &amount) const {
                    return base_iterator(ptr + amount);
                }
                base_iterator   operator -(const typename iterator_type::difference_type &amount) const {
                    return base_iterator(ptr - amount);
                }
                base_iterator   &operator +=(const typename iterator_type::difference_type &amount) {
                    ptr += amount;
                    return *this;
                }
                base_iterator   &operator -=(const typename iterator_type::difference_type &amount) {
                    ptr -= amount;
                    return *this;
                }
                bool            operator ==(const base_iterator &other) const {
                    return ptr == other.ptr;
                }
                bool            operator !=(const base_iterator &other) const {
                    return ptr != other.ptr;
                }
                bool            operator <(const base_iterator &other) const {
                    return ptr < other.ptr;
                }
                bool            operator <=(const base_iterator &other) const {
                    return ptr <= other.ptr;
                }
                bool            operator >(const base_iterator &other) const {
                    return ptr > other.ptr;
                }
                bool            operator >=(const base_iterator &other) const {
                    return ptr >= other.ptr;
                }
            private:
                U   *ptr;
        };
        typedef base_iterator< T >                      iterator;
        typedef base_iterator< const T >                const_iterator;
        typedef std::reverse_iterator< iterator >       reverse_iterator;
        typedef std::reverse_iterator< const_iterator > const_reverse_iterator;

        iterator                begin(void) { return iterator(data); }
        const_iterator          begin(void) const { return const_iterator(data); }
        iterator                end(void) { return iterator(data + size); }
        const_iterator          end(void) const { return const_iterator(data + size); }
        reverse_iterator        rbegin(void) { return reverse_iterator(data + size - 1); }
        const_reverse_iterator  rbegin(void) const { return const_reverse_iterator(data + size - 1); }
        reverse_iterator        rend(void) { return reverse_iterator(data - 1); }
        const_reverse_iterator  rend(void) const { return const_reverse_iterator(data - 1); }

    private:
        T   data[size];
};

int main(void) {
    Array< int, 20 >    a;

    for (Array< int, 20 >::iterator it = a.begin(); it != a.end(); ++it)
        *it = 42;
    for (Array< int, 20 >::const_iterator it = a.begin(); it != a.end(); ++it)
        std::cout << *it << std::endl;
}

編譯器輸出

problem.cpp:106:40: error: no viable conversion from 'base_iterator<int>' to 'base_iterator<const int>'
        for (Array< int, 20 >::const_iterator it = a.begin(); it != a.end(); ++it)
                                              ^    ~~~~~~~~~
problem.cpp:24:5: note: candidate constructor not viable: no known conversion from 'Array<int, 20>::iterator' (aka 'base_iterator<int>') to 'const int *' for 1st argument
                                base_iterator(U *p) : ptr(p) { }
                                ^
problem.cpp:25:5: note: candidate constructor not viable: no known conversion from 'Array<int, 20>::iterator' (aka 'base_iterator<int>') to 'const Array<int, 20>::base_iterator<const int> &' for 1st argument
                                base_iterator(const base_iterator &other) : ptr(other.ptr) { }
                                ^
1 error generated.

所以似乎問題在於base_iterator< T >不能轉換為base_iterator< const T > ,但首先我想知道為什么我們需要轉換? 由於beginend以及operator */->有 const 重載,它不應該調用 const 版本嗎? 其次,如果我們需要轉換,我不知道該怎么做

編輯 1:我實現了remove_constadd_const來進行轉換,但它仍然無法編譯

成員 function 的const限定版本是否被調用,僅取決於調用成員 function 的表達式的類型是否為const限定。

在您的示例中的a.begin()中, a被聲明為Array< int, 20 >這不是const 因此將調用begin()的非const限定版本。

如果您想讓您的容器 class 符合 C++ 標准庫中的容器要求,那么您必須使您的iterator可轉換為const_iterator 這是規定的要求之一,將使您的測試代碼按預期工作。

有關Container要求的完整列表,請參閱cppreference

您的編譯器告訴您它無法將您的iterator轉換為您的const_iterator

a.begin();

由於a是可變的 object,因此會調用返回iteratorbegin()重載,但會嘗試將結果存儲到const_iterator中,並且您設計迭代器類的方式不允許發生該轉換。

這與您不能采用例如std::vector<int>並將其分配給std::vector<const int>的原因相同。 這也是同樣的根本原因。 std::vector<int>std::vector<const int>是兩個完全不同的類,它們以任何形式或方式彼此都不相關。 您的兩個迭代器類在同一條船上。

您需要做的是重新設計您的迭代器類,以便這種轉換變得微不足道。

處理此問題的經典方法是讓迭代器從const iterator iterator ,例如:

class const_iterator {
protected:

    T *p;  // The underlying pointer, or whatever is being used to reference the iterator value and/or its container.

public:

    // Implement only the `const` methods here
};

class iterator : public const_iterator {

public:

    // Implement only the non-const methods here
};

現在,神奇的轉換會在需要的地方自動發生。 iteratorconst_iterator都可以完全訪問底層容器及其值。 const_iterator只需要注意保持const的正確性,即它的operator*重載返回一個const T & ,而iterator::operator*()返回一個T & ,依此類推。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM