简体   繁体   中英

gcc reverse_iterator comparison operators missing?

I am having a problem using const reverse iterators on non-const containers with gcc. Well, only certain versions of gcc.

#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;
}

This program compiles OK and runs with gcc 4.2.1 (Mac Leopard) and with Visual Studio 8 and 9 (Windows), and with gcc 4.1.2 (Linux).

However, there is a compile error with gcc 3.4.4 (cygwin) and with 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>]()'

Is this a bug in earlier versions of gcc?

Due to other problems with gcc 4.2.1 on Mac, we need to use gcc 4.0.1 on Mac, so simply using the newer compiler is not a perfect solution for me. So I guess I need to change how I use reverse iterators. Any suggestions?

It is a defect in the current standard: http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#280

Edit : Elaborating a bit: The issue is that, in the current standard:

  • vector::reverse_iterator is specified as std::reverse_iterator<vector::iterator> , and vector::const_reverse_iterator as std::reverse_iterator<vector::const_iterator> .
  • The relational operators on std::reverse_iterator are defined with a single template parameter, making reverse_iterator<iterator> and reverse_iterator<const_iterator> non-comparable.

In your code, you compare a const_reverse_iterator with the result of calling "rend()" on a non-const vector, which is a (non-const) reverse_iterator .

In C++0x, two related changes are made to fix issues like this:

  • Relational operators on reverse_iterator now take two template parameters
  • Containers like vector have extra methods to explicitely request a const_iterator: cbegin(), cend(), crbegin() and crend().

In your case, a workaround would be to explicitely request the const_reverse_iterator for rend():

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

Random things I would try:

Cast the return from rend() to a const_reverse_iterator to see if the issue is in comparing a regular to a const iterator:

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

If that doesn't work, how about changing r from a const_reverse_iterator to a regular reverse iterator.

No clue if these work, but that's what I'd try in this situation.

Since the iterators need to be the same type to be comparable, and a non-const container yields non-const iterators, why not declare and initialize the end iterator at the same time.

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

With an older compiler this might even give a small performance benefit.

It could be a bug in the old vesion of gcc, but my guess is that the bug is in your code -- you've failed to #include <iterator> . It's probably only worth looking further if fixing that doesn't fix the problem.

On the other hand, if you're using the reverse_iterator as shown (ie the body of the loop is cout << *r; ) you should probably just use 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);

There is also a copy_backwards , but I don't believe it'll do what you want.

Edit: One other possibility to consider: if adding the required header doesn't work, and you really need the reverse iterator, you might consider using STLPort in place of the native library (at least for the older compilers).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM