我仍在尝试实现我自己的LinkedList类版本,现在我遇到了为常量迭代器重载方法的问题。例如,当我尝试使用以下代码打印出列表时:
cout << "citer:" << endl;
for (UberList<int>::CIter it = ulist.begin(); it != ulist.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
我有这些错误:
Error E2034 UberList2.cpp 532: Cannot convert 'UberList<int>::Iter' to 'UberList<int>::CIter' in function main()
Error E2094 UberList2.cpp 532: 'operator!=' not implemented in type 'UberList<int>::CIter' for arguments of type 'UberList<int>::Iter' in function main()
据我所知,这意味着使用那些通常的end和begin迭代器方法。以下是我的课程中声明这些方法的方法:
Iter begin();
Iter end();
CIter begin() const;
CIter end() const;
和
template<class T>
typename UberList<T>::Iter UberList<T>::begin()
{
Iter it;
it.curr = head;
return it;
}
template<class T>
typename UberList<T>::Iter UberList<T>::end()
{
Iter it;
it.curr = tail->next;
return it;
}
template<class T>
typename UberList<T>::CIter UberList<T>::begin() const
{
CIter it;
it.ccurr = head;
return it;
}
template<class T>
typename UberList<T>::CIter UberList<T>::end() const
{
CIter it;
it.ccurr = tail->next;
return it;
}
有什么方法可以强制我的程序将这些const方法用于常量迭代器而不是通常的迭代器?我很高兴听到任何建议。
哦,这是我的课程代码,以防万一:http://pastebin.com/Jbvv5Hht
答案 0 :(得分:7)
您应提供从Iter
到CIter
的转化。标准容器(表65,在23.1“容器要求”中表示X::iterator
可转换为X::const_iterator
)
调用者可以通过使用const
引用确保调用const
重载,但是你不应强迫他们这样做,因为他们必须编写如下内容:
UberList<int>::CIter it = static_cast<const UberList<int> &>(ulist).begin()
如果您提供“必需”转换,则您的调用者无需执行任何特殊操作:您的原始代码将起作用,就像对标准容器一样。
答案 1 :(得分:1)
对OP代码的更多评论。考虑分离这个巨大的uberl33tlist类并将其分解为更小的文件。看到所有这些朋友的课堂宣言让我感到很不舒服。当你使用像
这样的东西时,还有一些棘手的语义friend class UberList;
friend class CIter;
在某些情况下,如果那些类尚不存在,那么这些语句最终也会向转发声明这些类。在这里还有一些关于你的任务操作员不太正确的事情:
UberList<T> operator = (const UberList<T>& OL)
{
UberList<T> NL = new (OL);
return NL;
}
另外在你的主要你有
it2++;
ulist.insertAfter(b, it2);
//...
你正在使用postfix operator ++ for it2但是没有实现你的迭代器类。 Borland通过使用前缀来接受它,但会发出警告。 Gcc实际上将其标记为错误并拒绝代码。可能想看看那个
答案 2 :(得分:1)
叹息:这里有一定程度的hackery旨在隐藏这样一个事实,即概念上你想要做的事情不能在C ++中自动完成,因为它不了解方差。其他一些语言(包括Ocaml)可以。
如果你有一个仿函数(这是C ++程序员的模板类),问题是它和各种函数如何用参数的方差表现,例如从T到T的转换。你真正想要的是:
List<T> --> List<T const>
换句话说,你希望List仿函数是协变的。但不,它不是..所以实际上List模板根本不是一个仿函数,因为仿函数必须是结构保留的,并且转换不会根据需要反映出来。反过来,这意味着C ++模板被破坏或者const的概念被破坏,因为不支持参数多态的类型系统被规范打破了:)
提供“const_iterator”并不能解决这个问题,只是简单地修补了这个问题。 volatile和const_volatile版本在哪里?双重间接怎么样?
如果你不理解双重间接:考虑T的向量树,这是两个模板:
Tree<Vector<T>>
这里最好的解决方案是放弃支持const_iterator。只是不要打扰。无论如何它都很混乱:“const vector”怎么样?那是什么?你不能再做一个矢量,但它仍然允许你写元素吗?
实际要求是变换通勤,例如:
vector<T> const == vector<T const>
[或者如果变换是反变的,他们反通勤]
事实并非如此,这表明矢量不是函数,换句话说,模板不能有效地用于参数多态。如果你想真正地将你的短裤绑在一个结上,请考虑带有函数参数的模板,并询问函数返回类型和参数的方差,以及这可能如何影响容器。一个很好的例子是如何组合两个函数,以便它们在一对上工作。如果它们是变异器,那么“const”如何工作呢?
答案 3 :(得分:0)
你需要
teamplate<class T> bool operator!=(UberList<T>::CIter,UberList<T>::CIter);
答案 4 :(得分:-2)
它使用常规begin方法,因为变量不是const。因此,修复它的一种方法是创建另一个(引用)变量const:
UberList<int> const & culist = ulist;
for (UberList<int>::Citer it = culist.begin(); ...)
或者,使用const_cast。