Операторы сравнения gcc reverse_iterator отсутствуют? - PullRequest
5 голосов
/ 25 января 2010

У меня проблема с использованием константных обратных итераторов в неконстантных контейнерах с gcc. Ну, только определенные версии 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;
}

Эта программа компилируется нормально и работает с gcc 4.2.1 (Mac Leopard) и с 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?

Из-за других проблем с gcc 4.2.1 на Mac нам нужно использовать gcc 4.0.1 на Mac, поэтому простое использование более нового компилятора не является для меня идеальным решением. Думаю, мне нужно изменить способ использования обратных итераторов. Есть предложения?

Ответы [ 4 ]

10 голосов
/ 25 января 2010

Это дефект в текущем стандарте: http://www.open -std.org / jtc1 / sc22 / wg21 / docs / lwg-дефектов.

Редактировать : Немного проработать: Проблема в том, что в текущем стандарте:

  • vector::reverse_iterator указан как std::reverse_iterator<vector::iterator>, а vector::const_reverse_iterator как std::reverse_iterator<vector::const_iterator>.
  • Реляционные операторы в std::reverse_iterator определены с одним параметром шаблона, что делает reverse_iterator<iterator> и reverse_iterator<const_iterator> несопоставимыми.

В вашем коде вы сравниваете const_reverse_iterator с результатом вызова "rend ()" для неконстантного вектора, который является (неконстантным) reverse_iterator.

В C ++ 0x внесены два связанных изменения для исправления таких проблем:

  • Реляционные операторы на reverse_iterator теперь принимают два параметра шаблона
  • Контейнеры, такие как vector, имеют дополнительные методы для явного запроса const_iterator: cbegin (), cend (), crbegin () и crend ​​().

В вашем случае для обхода этой проблемы можно явно запросить const_reverse_iterator для 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;

2 голосов
/ 26 января 2010

Поскольку итераторы должны быть одного типа, чтобы быть сопоставимыми, а неконстантный контейнер дает неконстантные итераторы, почему бы не объявить и инициализировать конечный итератор одновременно.

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

С более старым компилятором это может даже дать небольшое преимущество в производительности.

2 голосов
/ 25 января 2010

Случайные вещи, которые я бы попробовал:

Приведите возврат из rend () к const_reverse_iterator, чтобы увидеть, заключается ли проблема в сравнении регулярного с константным итератором:

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

Если это не сработает, как насчет замены r с const_reverse_iterator на обычный обратный итератор.

Понятия не имею, работают ли они, но я бы попробовал в этой ситуации.

1 голос
/ 25 января 2010

Это может быть ошибкой в ​​старой версии gcc, но я предполагаю, что ошибка в вашем коде - вы не смогли #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 вместо собственной библиотеки (по крайней мере старые компиляторы).

...