Дайте унаследованному вложенному классу отдельный тип данных в C++

Я пытаюсь имитировать способ объявления итераторов STL с помощью наследования и вложенных классов.

У меня есть родительский класс Iterable с вложенным классом iterator,

class Iterable
{
public:
    class iterator
    { };
};

У меня есть два класса, List а также Vectorкоторые наследуют от Iterable чтобы получить вложенный класс iterator,

class List : public Iterable
{ };

class Vector : public Iterable
{ };

Это позволяет объявлять итераторы подобным образом.

   List::iterator lIte;
   Vector::iterator vIte;

Однако я хотел бы иметь ошибки времени компиляции при попытке смешать итераторы из разных производных классов. Например

lIte = vIte; // throw a compile error

Но, так как iterators происходят из того же базового класса, Iterable, заявление выше будет скомпилировано просто отлично.

Примером обходного решения может быть определение нового вложенного класса iterator который унаследует от Iterable::iterator в каждом классе, который наследует от Iterable (List а также Vector). Например

class List : public Iterable
{
public:
    class iterator : Iterable::iterator // This "specializes" the datatype of iterator
    { };
};

class Vector : public Iterable
{
public:
    class iterator : Iterable::iterator
    { };  
};

Выполнение вышеупомянутого успешно вызовет ошибку времени компиляции при попытке:

   List::iterator lIte;
   Vector::iterator vIte;
   lIte = vIte;

Однако это неоптимальная работа:

  1. Это включает в себя дублирование кода в каждом классе, который наследует от Iterable,
  2. Требуется C++11 для дублирования iterator классы для наследования соответствующих конструкторов Iterable::iterator,

Мой вопрос, как я могу сделать List::iterator а также Vector::iterator различные типы без дублирования кода или использования наследования конструктора C++11?

1 ответ

Решение

Вы можете использовать шаблон класса для генерации разных классов из одного общего шаблона:

template<typename T>
struct Iterable
{
    class iterator
    { };
};

class List : public Iterable<List>
{ };

class Vector : public Iterable<Vector>
{ };

Однако, хотя это решает вашу непосредственную проблему, это не выглядит как правильное решение.
На самом деле не имеет смысла давать Iterable класс итератора вообще, если это не (потенциально полиморфный) базовый класс. В конце концов, перебирая vector работает не так, как перебирать list,

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

Другие вопросы по тегам