Информация об изменениях

Сообщение Re[7]: Приведение типов итераторов для контейнера с базовым от 17.01.2024 9:04

Изменено 17.01.2024 9:05 rg45

Re[7]: Приведение типов итераторов для контейнера с базовым
Здравствуйте, drVanо, Вы писали:

R>>Да, еще один момент: адапторы итераторов, на самом деле, классная штука, с помощью которой можно адаптировать разного рода коллекции под конкретные нужды. Например, ты можешь подпилить этот адаптор так, чтоб он возвращал не указатели, а сразу ссылки на объекты.


V>Можно какой-нибудь простой пример такого адаптора к std::vector<std::unique_ptr<T>>?


Ну это уже зависит от потребностей — смотря, что нужно получить на выходе. Вообще, этих всяких адаптеров можно напридумывать вагон и маленькую тележку (что собственно уже и сделано в boost). И имеет смысл, вместо сложных мотолитных адаптеров, делать маленькие простые, а потом их комбинировать как конструктор лего. В примере ниже определены два простых адаптора: IndirectIterator и StaticCastIterator. Эти два адаптора комбинируются (StaticCastIterator поверх IndirectIterator) и применяются к инкапсулированному контейнеру std::vector<std::unique_ptr<T>>. В примере присутствует избыточный копи-пастинг — это ради того, чтоб не перегружать пример дополнительными сущностями и не подключать boost. По-хорошему, такого быть не должно, конечно же.

http://coliru.stacked-crooked.com/a/8764c68363edc011

#include <vector>
#include <iostream>
#include <memory>
#include <type_traits>
#include <utility>

template <typename BaseIterator>
class IndirectIterator
{
public:

   using TargetType = decltype(**std::declval<BaseIterator>());

   IndirectIterator() = default;
   IndirectIterator(const BaseIterator& i) : m_baseIterator(i) {}

   TargetType operator*() const { return **m_baseIterator; }

   bool operator == (const IndirectIterator& rhs) const { return m_baseIterator == rhs.m_baseIterator; }
   bool operator != (const IndirectIterator& rhs) const { return !(*this == rhs); }

   IndirectIterator& operator++() { ++m_baseIterator; return *this; }
   IndirectIterator operator++(int) { return m_baseIterator++; }

private:
   BaseIterator m_baseIterator;
};


template <typename BaseIterator, typename TargetType>
class StaticCastIterator
{
public:

   StaticCastIterator() = default;
   StaticCastIterator(const BaseIterator& i) : m_baseIterator(i) {}

   TargetType operator*() const { return static_cast<TargetType>(*m_baseIterator); }

   bool operator == (const StaticCastIterator& rhs) const { return m_baseIterator == rhs.m_baseIterator; }
   bool operator != (const StaticCastIterator& rhs) const { return !(*this == rhs); }

   StaticCastIterator& operator++() { ++m_baseIterator; return *this; }
   StaticCastIterator operator++(int) { return m_baseIterator++; }

private:
   BaseIterator m_baseIterator;
};


template <typename T>
class BaseList
{
   using Items_ = std::vector<std::unique_ptr<T>>;
public:

   using iterator = IndirectIterator<typename Items_::iterator>;
   using const_iterator = IndirectIterator<typename Items_::const_iterator>;

   iterator begin() { return items_.begin(); }
   iterator end() { return items_.end(); }

   const_iterator begin() const { return items_.begin(); }
   const_iterator end() const { return items_.end(); }

protected:
   Items_ items_;
};

class BaseImport {};

template <typename T>
class ImportList : public BaseList<BaseImport>
{
public:

   // Use concepts instead of the static_assert on C++20
   static_assert(std::is_base_of_v<BaseImport, T>);

   using BaseList = BaseList<BaseImport>;
   using iterator = StaticCastIterator<typename BaseList::iterator, T&>;
   using const_iterator = StaticCastIterator<typename BaseList::const_iterator, const T&>;

   iterator begin() { return BaseList::begin(); }
   iterator end() { return BaseList::end(); }

   const_iterator begin() const { return BaseList::begin(); }
   const_iterator end() const { return BaseList::end(); }

   template <typename... CreationParams>
   void CreateItem(CreationParams&&... params) {
      BaseList::items_.emplace_back(std::make_unique<T>(std::forward<CreationParams>(params)...));
   }
};

struct MacImport : BaseImport
{
   int id{};
   std::string name;

   MacImport(int id, const std::string& name) : id(id), name(name){}
};

int main()
{
   using MacImportList = ImportList<MacImport>;

   MacImportList l;

   l.CreateItem(101, "Mac Item 101");
   l.CreateItem(102, "Mac Item 102");
   l.CreateItem(103, "Mac Item 103");

   for (const MacImport& item : l)
   {
      std::cout << "[" << item.id << "]: " << item.name << std::endl;
   }
}


Output:
[101]: Mac Item 101
[102]: Mac Item 102
[103]: Mac Item 103
Re[7]: Приведение типов итераторов для контейнера с базовым
Здравствуйте, drVanо, Вы писали:

R>>Да, еще один момент: адапторы итераторов, на самом деле, классная штука, с помощью которой можно адаптировать разного рода коллекции под конкретные нужды. Например, ты можешь подпилить этот адаптор так, чтоб он возвращал не указатели, а сразу ссылки на объекты.


V>Можно какой-нибудь простой пример такого адаптора к std::vector<std::unique_ptr<T>>?


Ну это уже зависит от потребностей — смотря, что нужно получить на выходе. Вообще, этих всяких адаптеров можно напридумывать вагон и маленькую тележку (что собственно уже и сделано в boost). И имеет смысл, вместо сложных монолитных адаптеров, делать маленькие простые, а потом их комбинировать как конструктор лего. В примере ниже определены два простых адаптора: IndirectIterator и StaticCastIterator. Эти два адаптора комбинируются (StaticCastIterator поверх IndirectIterator) и применяются к инкапсулированному контейнеру std::vector<std::unique_ptr<T>>. В примере присутствует избыточный копи-пастинг — это ради того, чтоб не перегружать пример дополнительными сущностями и не подключать boost. По-хорошему, такого быть не должно, конечно же.

http://coliru.stacked-crooked.com/a/8764c68363edc011

#include <vector>
#include <iostream>
#include <memory>
#include <type_traits>
#include <utility>

template <typename BaseIterator>
class IndirectIterator
{
public:

   using TargetType = decltype(**std::declval<BaseIterator>());

   IndirectIterator() = default;
   IndirectIterator(const BaseIterator& i) : m_baseIterator(i) {}

   TargetType operator*() const { return **m_baseIterator; }

   bool operator == (const IndirectIterator& rhs) const { return m_baseIterator == rhs.m_baseIterator; }
   bool operator != (const IndirectIterator& rhs) const { return !(*this == rhs); }

   IndirectIterator& operator++() { ++m_baseIterator; return *this; }
   IndirectIterator operator++(int) { return m_baseIterator++; }

private:
   BaseIterator m_baseIterator;
};


template <typename BaseIterator, typename TargetType>
class StaticCastIterator
{
public:

   StaticCastIterator() = default;
   StaticCastIterator(const BaseIterator& i) : m_baseIterator(i) {}

   TargetType operator*() const { return static_cast<TargetType>(*m_baseIterator); }

   bool operator == (const StaticCastIterator& rhs) const { return m_baseIterator == rhs.m_baseIterator; }
   bool operator != (const StaticCastIterator& rhs) const { return !(*this == rhs); }

   StaticCastIterator& operator++() { ++m_baseIterator; return *this; }
   StaticCastIterator operator++(int) { return m_baseIterator++; }

private:
   BaseIterator m_baseIterator;
};


template <typename T>
class BaseList
{
   using Items_ = std::vector<std::unique_ptr<T>>;
public:

   using iterator = IndirectIterator<typename Items_::iterator>;
   using const_iterator = IndirectIterator<typename Items_::const_iterator>;

   iterator begin() { return items_.begin(); }
   iterator end() { return items_.end(); }

   const_iterator begin() const { return items_.begin(); }
   const_iterator end() const { return items_.end(); }

protected:
   Items_ items_;
};

class BaseImport {};

template <typename T>
class ImportList : public BaseList<BaseImport>
{
public:

   // Use concepts instead of the static_assert on C++20
   static_assert(std::is_base_of_v<BaseImport, T>);

   using BaseList = BaseList<BaseImport>;
   using iterator = StaticCastIterator<typename BaseList::iterator, T&>;
   using const_iterator = StaticCastIterator<typename BaseList::const_iterator, const T&>;

   iterator begin() { return BaseList::begin(); }
   iterator end() { return BaseList::end(); }

   const_iterator begin() const { return BaseList::begin(); }
   const_iterator end() const { return BaseList::end(); }

   template <typename... CreationParams>
   void CreateItem(CreationParams&&... params) {
      BaseList::items_.emplace_back(std::make_unique<T>(std::forward<CreationParams>(params)...));
   }
};

struct MacImport : BaseImport
{
   int id{};
   std::string name;

   MacImport(int id, const std::string& name) : id(id), name(name){}
};

int main()
{
   using MacImportList = ImportList<MacImport>;

   MacImportList l;

   l.CreateItem(101, "Mac Item 101");
   l.CreateItem(102, "Mac Item 102");
   l.CreateItem(103, "Mac Item 103");

   for (const MacImport& item : l)
   {
      std::cout << "[" << item.id << "]: " << item.name << std::endl;
   }
}


Output:
[101]: Mac Item 101
[102]: Mac Item 102
[103]: Mac Item 103