我正在编写一个链表实现,但是我一直陷于如何实现与常规迭代器一起通过cbegin()
访问的const迭代器的问题。这是我尝试解决的方法:
#include <iostream>
using namespace std;
template <typename T>
class ListNode {
public:
ListNode<T>* next_;
ListNode<T>* prev_;
T data_;
ListNode():
next_(nullptr),
prev_(nullptr)
{}
};
template <typename T>
class ListIterator
{
typedef ListNode<T> node;
typedef ListNode<T>* pointer;
pointer p_;
public:
ListIterator(pointer p) : p_(p) {}
T& operator*() { return p_->data_; }
};
template<typename T>
class List
{
public:
typedef ListNode<T> node;
typedef ListNode<T>* pointer;
typedef ListIterator<T> iterator;
typedef ListIterator<const T> constIterator;
List() :
head_(nullptr),
tail_(nullptr),
size_(0)
{}
void pushBack(pointer p) {
p->next_ = nullptr;
p->prev_ = nullptr;
if (size_ == 0) {
head_ = p;
} else {
tail_->next_ = p;
p->prev_ = tail_;
}
tail_ = p;
++size_;
}
iterator begin() { return head_; }
iterator end() { return nullptr; }
constIterator cbegin() { return head_; }
constIterator cend() { return nullptr; }
private:
pointer head_;
pointer tail_;
unsigned int size_;
};
class Dog {
public:
int age;
};
int main() {
auto list = List<Dog>();
auto dogNode = ListNode<Dog>();
list.pushBack(&dogNode);
auto b = list.cbegin();
}
当我尝试运行此命令时,出现错误
error: no viable conversion from returned value of type 'List<Dog>::pointer' (aka 'ListNode<Dog> *') to function return type
'List<Dog>::constIterator' (aka 'ListIterator<const Dog>')
这个错误对我来说很有意义,但我想不出一个不错的解决方法,该方法不涉及编写单独的ConstListIterator
类(此方法有效,但是复制粘贴所有操作符重载感觉不对。 ListIterator
中的代码-此示例中省略了大部分代码。)
在this question中,作者使用了ListIterator
参数化TNode
的方法,在这种情况下,它将是ListNode<Dog>
而不是Dog
。这种方法的问题在于operator*
不能返回实际的Dog
,因为ListIterator
类不知道类型名Dog
。因此,该解决方案仅以data_
类型进行硬编码,因此您将失去元编程的所有好处。
是否有使它正常工作的技巧,还是应该只另设一个ConstListIterator
类?
谢谢!
答案 0 :(得分:2)
发生错误的原因是,您试图从具有返回类型head
的函数(也称为ListNode<T>*
)返回constIterator
类型的ListIterator<const T>
。 / p>
要回答您的问题,iterator
和const_iterator
之间的唯一区别是const_iterator
返回对容器value_type
的const引用,而不仅仅是参考。因此,将const T
作为模板参数传递应该会产生所需的功能。由于operator*
返回T&
,因此如果T
改为const T
,则它返回const T&
,这是正确的。如上所述,您遇到的问题似乎是因为您从iterator
函数返回了错误的类型。
您的迭代器函数应如下所示:
iterator begin() { return iterator{head_}; }
iterator end() { return iterator{nullptr}; }
constIterator cbegin() { return constIterator{head_}; }
constIterator cend() { return constIterator{nullptr}; }
这将返回iterator
和constIterator
对象,这些对象是使用指针head_
和nullptr
构造的。
您用于迭代器的模板参数,列表的value_type
是正确的。
答案 1 :(得分:2)
将节点类型作为迭代器的模板参数是合理且允许的
using constIterator=ListIterator<const ListNode<T>>;
可方便地排除结构修改和内容修改。它使cbegin
可以按书面形式工作(在const
的类型上隐式添加head_
)。它还允许T
本身就是const
(适用于链表:它never needs to relocate anything)。
要定义operator*
,只需使用auto
:
auto& operator*() const {return p_->data_;}
*p_
的常量性会延续到data_
,然后返回到返回类型。
在C ++ 11中,您可以为ListNode
配备
using value_type=T;
并使用is_const
和conditional
之类的类型特征从const T
派生const ListNode<T>
。
在C ++ 03中,您可以为此直接编写基于SFINAE的特征。