Сообщение Re: Приведение типов итераторов для контейнера с базовым тип от 12.01.2024 12:16
Изменено 12.01.2024 12:31 rg45
Re: Приведение типов итераторов для контейнера с базовым типом
Здравствуйте, drVanо, Вы писали:
V>Есть контейнер, который хранит указатели на объекты:
V> . . .
V>Есть некий базовый класс:
V>
V>И есть потомок, который хранит в контейнере предка от BaseImport:
V>
V>Вопрос, как вытащить "std::vector" из ObjectList для приведения типов итератора чтобы больше никогда не зависеть от типа контейнера в базовом классе?
К сожалению, в C++ нет ковариантности контейнеров и не предвидится в обозримом будущем. Но в данном случае в ней (в ковариантности) нет и ососбой нужды. Насколько я могу судить по дизайну, класс MacImportList сам по себе имеет семантику контейнера, а значит, нет особого смысла выставлять наружу инкапсулированый контейнер, которые является деталью реализации класса. Достаточно просто предоставить адаптор итератора, который будет брать на себя преобразование к нужному типу. Схематично так:
V>Есть контейнер, который хранит указатели на объекты:
V> . . .
V>Есть некий базовый класс:
V>
V>class BaseImportList : public ObjectList<BaseImport>
V>{
V>...
V>}
V>
V>И есть потомок, который хранит в контейнере предка от BaseImport:
V>
V>class MacImport : public BaseImport
V>{
V>...
V>}
V>class MacImportList : public BaseImportList
V>{
V> typedef typename std::vector<MacImport *> list;
V> list::const_iterator begin() const { return reinterpret_cast<const list &>(items_).begin(); }
V> list::const_iterator end() const { return reinterpret_cast<const list &>(items_).end(); }
V>}
V>
V>Вопрос, как вытащить "std::vector" из ObjectList для приведения типов итератора чтобы больше никогда не зависеть от типа контейнера в базовом классе?
К сожалению, в C++ нет ковариантности контейнеров и не предвидится в обозримом будущем. Но в данном случае в ней (в ковариантности) нет и ососбой нужды. Насколько я могу судить по дизайну, класс MacImportList сам по себе имеет семантику контейнера, а значит, нет особого смысла выставлять наружу инкапсулированый контейнер, которые является деталью реализации класса. Достаточно просто предоставить адаптор итератора, который будет брать на себя преобразование к нужному типу. Схематично так:
template <typename> struct BaseImportListIterator_;
template <typename T> struct BaseImportListIterator_<T*> { using type = BaseImportList::iterator; };
template <typename T> struct BaseImportListIterator_<T* const> { using type = BaseImportList::const_iterator; };
template <typename T>
using BaseImportListIterator = typename BaseImportListIterator_<T>::type;
template <typename T>
struct BaseImportListIteratorAdaptor : boost::iterator_adaptor<BaseImportListIteratorAdaptor<T>, BaseImportListIterator<T>, T>
{
// Use concepts instead of the static_assert on C++20
static_assert(std::is_base_of_v<BaseImport, std::remove_pointer_t<std::decay_t<T>>>);
using BaseIterator = BaseImportListIterator<T>;
using BaseAdaptor = boost::iterator_adaptor<BaseImportListIteratorAdaptor, BaseIterator, T>;
BaseImportListIteratorAdaptor() = default;
BaseImportListIteratorAdaptor(const BaseIterator& i) : BaseAdaptor(i) {}
T dereference() const { return static_cast<T>(*BaseAdaptor::base()); }
};
class MacImportList : public BaseImportList
{
public:
using iterator = BaseImportListIteratorAdaptor<MacImport*>;
using const_iterator = BaseImportListIteratorAdaptor<MacImport* const>;
iterator begin() { return items_.begin(); }
iterator end() { return items_.end(); }
const_iterator begin() const { return items_.begin(); }
const_iterator end() const { return items_.end(); }
};
Re: Приведение типов итераторов для контейнера с базовым тип
Здравствуйте, drVanо, Вы писали:
V>Есть контейнер, который хранит указатели на объекты:
V> . . .
V>Есть некий базовый класс:
V>
V>И есть потомок, который хранит в контейнере предка от BaseImport:
V>
V>Вопрос, как вытащить "std::vector" из ObjectList для приведения типов итератора чтобы больше никогда не зависеть от типа контейнера в базовом классе?
К сожалению, в C++ нет ковариантности контейнеров и не предвидится в обозримом будущем. Но в данном случае в ней (в ковариантности) нет и ососбой нужды. Насколько я могу судить по дизайну, класс MacImportList сам по себе имеет семантику контейнера, а значит, нет особого смысла выставлять наружу инкапсулированый контейнер, которые является деталью реализации класса. Достаточно просто предоставить адаптор итератора, который будет брать на себя преобразование к нужному типу. Схематично так:
Ну а формирование инкапсулированного контейнера и его модификация должны проиводиться какими-то специализированными функциями. Прямого доступа на модификацию икапсулированного контейнера давать не следует.
V>Есть контейнер, который хранит указатели на объекты:
V> . . .
V>Есть некий базовый класс:
V>
V>class BaseImportList : public ObjectList<BaseImport>
V>{
V>...
V>}
V>
V>И есть потомок, который хранит в контейнере предка от BaseImport:
V>
V>class MacImport : public BaseImport
V>{
V>...
V>}
V>class MacImportList : public BaseImportList
V>{
V> typedef typename std::vector<MacImport *> list;
V> list::const_iterator begin() const { return reinterpret_cast<const list &>(items_).begin(); }
V> list::const_iterator end() const { return reinterpret_cast<const list &>(items_).end(); }
V>}
V>
V>Вопрос, как вытащить "std::vector" из ObjectList для приведения типов итератора чтобы больше никогда не зависеть от типа контейнера в базовом классе?
К сожалению, в C++ нет ковариантности контейнеров и не предвидится в обозримом будущем. Но в данном случае в ней (в ковариантности) нет и ососбой нужды. Насколько я могу судить по дизайну, класс MacImportList сам по себе имеет семантику контейнера, а значит, нет особого смысла выставлять наружу инкапсулированый контейнер, которые является деталью реализации класса. Достаточно просто предоставить адаптор итератора, который будет брать на себя преобразование к нужному типу. Схематично так:
template <typename> struct BaseImportListIterator_;
template <typename T> struct BaseImportListIterator_<T*> { using type = BaseImportList::iterator; };
template <typename T> struct BaseImportListIterator_<T* const> { using type = BaseImportList::const_iterator; };
template <typename T>
using BaseImportListIterator = typename BaseImportListIterator_<T>::type;
template <typename T>
struct BaseImportListIteratorAdaptor : boost::iterator_adaptor<BaseImportListIteratorAdaptor<T>, BaseImportListIterator<T>, T>
{
// Use concepts instead of the static_assert on C++20
static_assert(std::is_base_of_v<BaseImport, std::remove_pointer_t<std::decay_t<T>>>);
using BaseIterator = BaseImportListIterator<T>;
using BaseAdaptor = boost::iterator_adaptor<BaseImportListIteratorAdaptor, BaseIterator, T>;
BaseImportListIteratorAdaptor() = default;
BaseImportListIteratorAdaptor(const BaseIterator& i) : BaseAdaptor(i) {}
T dereference() const { return static_cast<T>(*BaseAdaptor::base()); }
};
class MacImportList : public BaseImportList
{
public:
using const_iterator = BaseImportListIteratorAdaptor<MacImport* const>;
const_iterator begin() const { return items_.begin(); }
const_iterator end() const { return items_.end(); }
};
Ну а формирование инкапсулированного контейнера и его модификация должны проиводиться какими-то специализированными функциями. Прямого доступа на модификацию икапсулированного контейнера давать не следует.