Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 204
Christopher Bruns Avatar asked Jan 25 '10 19:01

Christopher Bruns


1 Answers

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;
like image 161
Éric Malenfant Avatar answered Oct 13 '22 20:10

Éric Malenfant