Можно ли избежать циклической зависимости в итераторах моего класса Matrix? - PullRequest
1 голос
/ 18 мая 2010

У нас есть два класса:

template<typename T, typename Size, typename Stack, typename Sparse>
class Matrix

и

template<typename T, typename Size>
class Iterator

Матрица должна иметь возможность возвращать начальный и конечный итераторы, и Iterator будет сохранять ссылку на Матрицу для доступа к элементам через ее интерфейс. Мы не хотим, чтобы Iterator зависел от внутреннего хранилища Matrix для предотвращения связывания. Как мы можем решить эту проблему циклической зависимости?

(Внутренний класс Storage имеет те же параметры шаблона, что и класс Matrix, и те же процедуры доступа, что и сама матрица)

Ответы [ 5 ]

4 голосов
/ 18 мая 2010

Здесь может также подойти использование вложенного класса, и это может сократить количество необходимых вам параметров шаблона.

template<typename T, typename Size, typename Stack, typename Sparse>
class Matrix{
public:
   class Iterator{
       // define Iterator members here
   };
   // declare Matrix members here
}
4 голосов
/ 18 мая 2010

Во-первых, вперед объявите класс Matrix. Это позволяет классу Iterator видеть имя класса Matrix, а также создавать указатели и ссылки на него. (Он не позволяет классу Iterator получать доступ к данным-членам или вызывать функции-члены.)

template<typename T, typename Size, typename Stack, typename Sparse>
class Matrix;

Затем определите класс Iterator. Все, что он может сделать на этом этапе - это хранить ссылки и указатели на Матрицу. (Нет доступа к членам Matrix.)

template<typename T, typename Size>
class Iterator{
   // don't define any function bodies in here
   //but do put all data members and prototypes in here
};

Затем определите класс Matrix (который может получить доступ к членам Iterator)

template<typename T, typename Size, typename Stack, typename Sparse>
class Matrix{
   // don't define any function bodies in here
   //but do put all data members and prototypes in here
};

Затем определите тела методов для каждого класса. На этом этапе методы обоих классов могут получить доступ к членам друг друга. Обычно эта часть находится в файле .cpp, но для шаблонов она принадлежит файлу .h.

template<typename T, typename Size, typename Stack, typename Sparse>
Matrix<T,Size,Stack,Sparse>::Matrix(){ /*...*/}

template<typename T, typename Size>
Iterator<T,Size>::Iterator(){ /*...*/ }
2 голосов
/ 18 мая 2010

Для итерации итераторам обычно необходимо знать о внутреннем хранилище, по которому они итерируются - такого взаимодействия обычно не избежать. Возьмем, к примеру, итератор карты - он должен знать внутреннюю древовидную структуру карты, чтобы он мог выполнять свою работу.

1 голос
/ 18 мая 2010

Вы можете заранее объявить шаблон. Это выглядит так:

template<typename T> struct Foo;

template <typename T> struct Bar
{
    Foo<T>* foo;
};

template<typename T> struct Foo
{
        T value;
        Bar<T*> foobar;
};

void bla()
{
        Foo<int> grml;
}
0 голосов
/ 18 мая 2010

Форвард-объявление шаблона Matrix перед определением шаблона Iterator.

Имейте в виду, вы столкнетесь с кирпичной стеной, когда поймете, что Iterator<T, Size> не может ссылаться на Matrix<T, Size, Stack, Sparse>.

...