У меня есть первый класс A, который содержит вложенный класс итератора с виртуальными методами:
template <typename T >
class A {
public:
class iterator {
public:
virtual ~iterator() {};
virtual T& operator++();
};
virtual iterator begin() const = 0;
};
У меня есть второй класс B, который переопределяет виртуальные методы:
template <typename T >
class B : public A<T> {
public:
class iterator : A<T>::iterator {
T& operator++() override {
iterator p(*this);
return p; //for exemple
}
};
iterator begin() const override {
return iterator(this);// for exemple
}
};
Но когда я использую класс B:
B<int> test;
У меня что-то вроде этого, ошибка компиляции:
error: invalid covariant return type for 'B<T>::iterator B<T>::begin() const [with T = int]'
error: overriding 'B<T>::iterator V<T>::begin() const [with T = int]'
Как реализовать итератор в классе B?
Совместные варианты возврата имеют пару ограничений, которым они должны соответствовать в соответствии с [Class.virtual] / 8.
Тип возврата переопределяющей функции должен быть идентичным
тип возврата переопределенной функции или ковариантный с
классы функций. Если функция D :: f переопределяет функцию
B :: f, возвращаемые типы функций ковариантны, если они
удовлетворяют следующим критериям:
- оба являются указателями на классы, оба являются lvalue ссылками на классы, или оба являются rvalue ссылками на классы
класс в возвращаемом типе B :: f является тем же классом, что и класс в возвращаемом типе D :: f, или является однозначным и
доступный прямой или косвенный базовый класс класса в возвращении
тип D :: f- […]
Ваш не наследуется публично, поэтому база недоступна. И вы не возвращаете указатель или ссылку.
Возвращать тип со семантикой значения — это хорошо! Вы не должны отказываться от этого. Вы можете заменить попытку на ко-вариантный тип возврата идиомой pimpl. Есть iterator
управлять полиморфным классом «реализации итератора» через указатель.
Других решений пока нет …