2010-01-25 86 views
5

我在使用gcc的非const容器上使用const反向迭代器时遇到了问题。那么,只有某些版本的gcc。gcc reverse_iterator比较运算符缺失?

#include <vector> 
#include <iostream> 

using namespace std; 

int main() { 
    const char v0[4] = "abc"; 
    vector<char> v(v0, v0 + 3); 

    // This block works fine 
    vector<char>::const_iterator i; 
    for (i = v.begin(); i != v.end(); ++i) 
     cout << *i; 
    cout << endl; 

    // This block generates compile error with gcc 3.4.4 and gcc 4.0.1 
    vector<char>::const_reverse_iterator r; 
    for (r = v.rbegin(); r != v.rend(); ++r) 
     cout << *r; 
    cout << endl; 

    return 0; 
} 

这个程序编译OK,并用gcc 4.2.1(苹果豹),并与Visual Studio 8和9(Windows)中运行,并与GCC 4.1.2(Linux)的。

但是,gcc 3.4.4(cygwin)和gcc 4.0.1(Mac Snow Leopard)存在编译错误。

test.cpp:18: error: no match for 'operator!=' in 'r != std::vector<_Tp, _Alloc>::rend() [with _Tp = char, _Alloc = std::allocator<char>]()' 

这是早期版本的gcc中的错误吗?

由于Mac上gcc 4.2.1的其他问题,我们需要在Mac上使用gcc 4.0.1,所以使用新的编译器对我来说不是一个完美的解决方案。所以我想我需要改变我如何使用反向迭代器。有什么建议么?

+0

对于解决方法,'!(r == v.rend())'工作吗?或者,您可以通过'r.base()'与非反向版本一起尝试。 – 2010-01-25 19:47:49

+0

更可能是遗漏;我认为对整个STL的全力支持*仍然在继续,尽管非常接近。在3.4.4的日子里,它有点不完整。 – meagar 2010-01-25 19:49:42

+0

@gf尼斯尝试,“!(r == v.rend())”不起作用。缺少“!=”和“==”运算符。 – 2010-01-25 20:58:18

回答

10

这是当前标准的缺陷:http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#280

编辑:阐述了一下: 问题是,在目前的标准:

  • vector::reverse_iterator被指定为std::reverse_iterator<vector::iterator>,和vector::const_reverse_iterator as std::reverse_iterator<vector::const_iterator>
  • 关于std::reverse_iterator的关系运算符是使用单个模板参数定义的,因此reverse_iterator<iterator>reverse_iterator<const_iterator>是不可比较的。

在代码中,您比较const_reverse_iterator与调用的“撕裂)(”关于非const的载体,它是一个(非const)reverse_iterator结果。

在C++ 0x中,两个相关的改变都是为了解决这样的问题:

  • 上reverse_iterator的关系运营商现在需要两个模板参数
  • 容器,如矢量有额外的方法来明确地要求为const_iterator :cbegin(),cend(),crbegin()和crend()。

在你的情况,一个解决方法是明确地请求用于撕裂()的的const_reverse_iterator:

vector<char>::const_reverse_iterator r; 
const vector<char>::const_reverse_iterator crend = v.rend(); 
for (r = v.rbegin(); r != crend; ++r) 
    cout << *r; 
+0

不错的答案。这是标准中的一个错误,而不是gcc中的错误。 – 2010-01-25 20:45:33

+0

@Christopher Bruns:我想让crend非const,就像r一样,会使事情发挥作用。 – 2010-01-25 21:12:00

+0

@Eric Malenfant:你的拳头要点:我认为const_reverse_iterator被定义为“reverse_iterator ”,而不仅仅是“const_iterator” – 2010-01-25 21:17:47

2

随机的事情,我会尝试:

演员从撕裂()的返回到的const_reverse_iterator,看看问题是否是在比较正规的常量迭代:

r != static_cast<vector<char>::const_reverse_iterator>(v.rend()) 

如果没有按” t工作,如何将r从const_reverse_iterator更改为常规反向迭代器。

没有线索,如果这些工作,但这就是我想在这种情况下尝试。

+0

该投射确实解决了问题。这不是很漂亮,但它确实有效。 – 2010-01-25 20:43:49

1

可能是gcc旧版本中的一个bug,但我的猜测是这个bug在你的代码中 - 你没有登录#include <iterator>。如果解决这个问题并不能解决问题,那么只需要进一步研究。

在另一方面,如果你使用的reverse_iterator如图所示(即循环体是cout << *r;)你应该只使用std::copy

std::ostream_iterator<char> output(std::cout); 

// frontwards 
std::copy(v.begin(), v.end(), output); 

// backwards 
std::copy(v.rbegin(), v.rend(), output); 

还有一个copy_backwards,但我不相信它会做你想做的。

编辑:另一种可能性考虑:如果添加所需的头不起作用,并且您确实需要反向迭代器,则可以考虑使用STLPort代替本机库(至少对于较早的编译器)。

+1

添加“#include ”不会改变行为。 – 2010-01-25 20:40:59

2

由于迭代器需要是相同类型的可比较,和一个非const容器产生非const迭代器,为什么不同时声明和初始化结束迭代器。

for (vector<char>::const_reverse_iterator r = v.rbegin(), end_it = v.rend(); r != end_it; ++r) 
    cout << *r; 

对于较旧的编译器,这甚至可能会带来很小的性能优势。