我正在大学学习OOP课程(C ++是一门基础语言)。我的任务是实现自己的链表模板容器类。我几乎完全做到了,但遇到了问题。众所周知,STL提供iterator
和const_iterator
类用于迭代列表。它们具有几乎相同的实现,主要区别在于迭代器的方法返回引用而const_iterator的方法 - 常量引用。我按照https://stackoverflow.com/a/3582733/2108548创建了分隔的模板类ListIterator
。然后我在课程typedef
内的Iterator
班ConstIterator
和List
宣布。
我有这样的事情:
template<typename T>
class ListNode
{
public:
ListNode(T *node_value = nullptr, ListNode *node_prev = nullptr, ListNode *node_next = nullptr):
value(node_value), prev(node_prev), next(node_next) { }
T *value;
ListNode *prev, *next;
};
template<typename T>
class ListIterator
{
typedef ListNode<T> Node;
public:
ListIterator();
ListIterator(Node *node);
ListIterator(ListIterator const &other);
ListIterator &operator++();
// ...
Node *i;
};
template<typename T>
class List: public Container
{
typedef ListIterator<T> Iterator;
typedef ListIterator<T const> ConstIterator;
// ...
Iterator begin() const
{
return Iterator(m_first->next);
}
ConstIterator const_begin() const
{
return ConstIterator(begin());
}
// ...
};
一切顺利,直到我决定制作“copy-constructor”Iterator
- &gt; ConstIterator
。所以我需要获取ListIterator<T>
的构造函数方法(其中T
是数据类名称)并创建新的对象类型ListIterator<T const>
。但实际上ConstIterator
的构造函数将T const
作为模板参数,因此我需要删除构造函数参数的const
。我发现标题type_traits
就是这样做的。所以我写了“copy-constructor”:
typedef typename std :: remove_cv :: type NoConstT;
ListIterator(ListIterator const&amp; other);
但它不起作用!我在请求const_begin()后得到了这个错误:
List<int> list1;
list1 << 1 << 2 << 3;
int i = *list1.const_begin();
error: 'ListIterator<T>::ListIterator(const ListIterator<typename std::remove_cv<_Tp>::type>&) [with T = int; typename std::remove_cv<_Tp>::type = int]' cannot be overloaded with 'ListIterator<T>::ListIterator(const ListIterator<T>&) [with T = int; ListIterator<T> = ListIterator<int>]'
但这不是全部。要实现我的目标,还必须将ListNode<T>
转换为ListNode<T const>
。但是我还有一个问题:每个列表节点都包含指向前一个和下一个节点的指针,如果我尝试在节点的构造函数中初始化它们,我将得到递归。当然,我可以通过迭代来创建处理将所有ListNode<T>
节点转换为ListNode<T const>
的函数。但我不喜欢这个解决方案:它有巨大的开销!
我问老师这个问题。几分钟他无法理解,然后当他拿到它时说:“这是基本的!” - “但我坚持了3-4个小时!” - “如果是这样,扔掉const迭代器并在没有它们的情况下完成列表容器。我需要时间来理解你的代码”(因为你看我的代码在我看来很简单)。据我所知,他不知道这个问题的答案。但我真的想知道如何制作它!我该如何解决这个问题?
对不起大量的错误 - 我不是以英语为母语的人。
答案 0 :(得分:3)
你确实可以使用<type_traits>
,而不是你所描述的方式。一种方法是始终声明来自相同类型的构造函数,并且仅当模板参数确实不是常量时,才使用enable_if
从非const中有效地声明。并且节点应始终为非const,这可以使用remove_const
。
#include <type_traits>
template<typename T>
class ListNode
{
//...
};
template<typename T>
class ListIterator
{
typedef ListNode<typename std::remove_const<T>::type> Node;
public:
ListIterator() {}
ListIterator(Node*) {}
ListIterator(ListIterator const&) {}
template <typename U>
ListIterator(ListIterator<U> const&, typename std::enable_if<!std::is_const<U>()>::type* = nullptr) {}
};
template<typename T>
class List
{
public:
typedef ListIterator<T> Iterator;
typedef ListIterator<T const> ConstIterator;
// ...
Iterator begin()
{
return Iterator(/*...*/);
}
ConstIterator const_begin() const
{
return ConstIterator(/*...*/);
}
// ...
};
int main() {
List<int> list;
List<int>::ConstIterator ci = list.const_begin();
List<int>::Iterator i = list.begin();
ci = i; // works fine as expected
i = ci; // fails as expected
i = i; // works fine as expected
ci = ci; // works fine as expected
return 0;
}