我正在努力嘗試為我的容器類實作 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 >,但首先我想知道為什么我們需要轉換?由于beginand end, and有 const 多載operator */->,它不應該呼叫 const 版本嗎?其次,如果我們需要轉換,我不知道該怎么做
編輯 1:我實作remove_const并add_const進行轉換,但它仍然無法編譯
uj5u.com熱心網友回復:
是否const呼叫成員函式的限定版本,僅取決于呼叫成員函式的運算式的型別是否const限定。
在a.begin()你的例子中a被宣告為Array< int, 20 >which is not const。因此將呼叫非const限定版本begin()。
如果您希望您的容器類兼容的容器在C 標準庫的要求,那么你必須讓你iterator轉換為const_iterator。這是規定的要求之一,將使您的測驗代碼按預期作業。
有關容器要求的完整串列,請參閱cppreference。
uj5u.com熱心網友回復:
您的編譯器告訴您它無法將您iterator的const_iterator.
a.begin();
由于a是可變物件,因此會呼叫begin()回傳a 的多載iterator,但會嘗試將結果存盤到 a 中const_iterator,并且您設計迭代器類的方式不允許進行該轉換。
例如,這std::vector<int>與您不能將 a像這樣賦值給 的原因相同std::vector<const int>。這是同樣的根本原因。std::vector<int>并且std::vector<const int>是兩個完全不同的類,它們在任何形式或方式上都沒有關聯。您的兩個迭代器類在同一條船上。
您需要做的是重新設計您的迭代器類,以便這種轉換變得微不足道。
處理這個問題的經典方法是iterator繼承自const 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
};
現在,神奇的轉換會在需要的地方自動發生。雙方iterator并const_iterator有底層容器完全的完全訪問權限,而其價值。const_iterator只需要足夠小心以保持const正確性,即它的operator*多載回傳 a const T &,而iterator::operator*()回傳 a T &,依此類推。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/394780.html
下一篇:在C 中遇到類問題
