Итератор C++ и const_iterator проблема для собственного контейнерного класса

Я пишу собственный контейнерный класс и столкнулся с проблемой, я не могу получить голову вокруг. Вот базовый образец, который показывает проблему.

Это состоит из контейнерного класса и двух тестовых классов: один тестовый класс с помощью std:vector, который компилирует приятно и второй тестовый класс, который пытается использовать мой собственный контейнерный класс в точном тот же путь, но не удается компилировать.

#include <vector>
#include <algorithm>
#include <iterator>

using namespace std;

template <typename T>
class MyContainer
{
public:

  class iterator
  {
  public:
    typedef iterator self_type;
    inline iterator() { }
  };

  class const_iterator
  {
  public:
    typedef const_iterator self_type;
    inline const_iterator() { }
  };

  iterator begin() {
    return iterator();
  }

  const_iterator begin() const {
    return const_iterator();
  }
};

// This one compiles ok, using std::vector
class TestClassVector
{
public:
  void test() {
    vector<int>::const_iterator I=myc.begin();
  }

private:
  vector<int> myc;
};

// this one fails to compile. Why?
class TestClassMyContainer
{
public:
  void test(){
    MyContainer<int>::const_iterator I=myc.begin();
  }

private:
  MyContainer<int> myc;
};


int main(int argc, char ** argv)
{
  return 0;
}

gcc говорит мне:

test2. C: В функции членства ‘освобождают TestClassMyContainer:: тест ()’:

test2. C:51: ошибка: преобразование из ‘MyContainer:: итератор’ к нескалярному типу ‘MyContainer:: const_iterator’ требуют

Я не уверен, где и почему компилятор хочет преобразовать итератор в const_iterator для моего собственного класса, но не для класса вектора STL. Что я делаю неправильно?

14
задан BaCh 16 May 2010 в 15:44
поделиться

3 ответа

Когда вы вызываете begin () , компилятор по умолчанию создает вызов неконстантной функции begin () . Поскольку myc не является const, он не может узнать, что вы собираетесь использовать const begin () , а не неконстантную begin () .

Итератор STL содержит оператор приведения, который позволяет незаметно преобразовать итератор в const_iterator . Если вы хотите, чтобы это работало, вам нужно добавить еще один такой же пример:

class iterator
{
public:
    typedef iterator self_type;
    inline iterator() { }

    operator const_iterator() { return const_iterator(); }
};

или разрешить создание const_iterator из итератора следующим образом:

class const_iterator
{
public:
    typedef const_iterator self_type;

    const_iterator(iterator& ) {}
    inline const_iterator() { }
};
10
ответ дан 1 December 2019 в 14:10
поделиться

В контейнерах тип итератора должен быть преобразован в const_iterator . Это необходимо в тех случаях, когда вы перебираете изменяемый контейнер с использованием неизменяемого (константного) итератора, поскольку это имеет смысл. В вашем случае myc является изменяемым (неконстантным), но вы создаете для него константный итератор.

3
ответ дан 1 December 2019 в 14:10
поделиться

Вам следует взглянуть на библиотеку Boost.Iterators, особенно на разделы iterator_facade и iterator_adaptor . Они содержат построение итератора «с нуля».

Он покажет вам, как писать итераторы без особого дублирования, потому что в большинстве случаев код константной и неконстантной версий примерно одинаков, за исключением самой квалификации const . Используя шаблоны, можно написать его один раз, а затем объявить два разных типа, и это иллюстрирует документация библиотеки.

2
ответ дан 1 December 2019 в 14:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: