У меня есть два класса. Я хочу создать класс Convert, который бы умел делать конвертацию между объектами моих двух классов. Помоги мне, пожалуйста, правильно его реализовать:
Класс PersistentArray:
template <typename T>
class PersistentArray
{
private:
    // Используем вектор указателей на элементы
    using Ptr = std::shared_ptr<T>;
    std::vector<std::vector<Ptr>> versions; // Все версии будут храниться здесь

    // std::vector<std::vector<T>>

    int current_version;

public:
    // Конструктор, принимает массив и его размер
    PersistentArray(T* arr, int size)
        : current_version(0)
    {
        std::vector<Ptr> base;
        for (int i = 0; i < size; ++i)
        {
            base.push_back(std::make_shared<T>(arr[i])); // Копируем элементы в shared_ptr
        }
        versions.push_back(base); // Сохраняем базовую версию
    }

    PersistentArray(std::vector<T> vec)
        : current_version(0)
    {
        std::vector<Ptr> base;
        for (const auto& val : vec)
        {
            base.push_back(std::make_shared<T>(val)); // Копируем элементы в shared_ptr
        }
        versions.push_back(base); // Сохраняем базовую версию
    }

    // Метод для добавления новой версии массива
    void addVersion(int root_position, int change_index, T new_value)
    {
        // Проверка корректности индексов
        if (current_version < 0 || current_version >= versions.size() ||
            root_position < 0 || root_position >= versions.size() ||
            change_index < 0 || change_index >= versions[root_position].size())
        {
            throw std::out_of_range("Invalid root position");
        }

        std::vector<Ptr> new_version = versions[root_position]; // Копируем указатели из предыдущей версии
        new_version[change_index] = std::make_shared<T>(new_value); // Заменяем значение на новое

        versions.push_back(new_version); // Сохраняем новую версию
        current_version++;
    }

    // Метод для отмены последнего действия
    void undo()
    {
        if (current_version <= 0)
        {
            std::cout << "No actions to undo!" << std::endl;
            return;
        }

        current_version--;
        versions.push_back(versions[current_version]);
    }

    // Метод для возврата действия
    void redo()
    {
        if (current_version >= versions.size() - 1)
        {
            std::cout << "No actions to redo!" << std::endl;
            return;
        }

        current_version++;
        versions.push_back(versions[current_version]);
    }

    // Метод для вывода всех версий
    void printAllVersions()
    {
        for (size_t i = 0; i < versions.size(); i++)
        {
            std::cout << "Version [" << i << "]: \t{";
            for (size_t j = 0; j < versions[i].size(); j++)
            {
                std::cout << *(versions[i][j]) << " (" << versions[i][j].get() << ")";
                if (j < versions[i].size() - 1)
                {
                    std::cout << ", ";
                }
            }
            std::cout << "}\n";
        }
    }

    const std::vector<Ptr>& getVersion(size_t idx) const
    {
        if (idx < versions.size())
        {
            return versions[idx];
        }
        throw std::out_of_range("Invalid version index");
    }
};

Класс PersistentDoublyLinkedList:
template <typename T>
struct DL_node {
    T value;
    std::shared_ptr<DL_node<T>> prev;
    std::shared_ptr<DL_node<T>> next;

    DL_node(T data) : value(data), prev(nullptr), next(nullptr) {}
};

template <typename T>
class PersistentDoublyLinkedList {
private:
    std::vector<std::shared_ptr<DL_node<T>>> versions; // Храним версии головы списка
    //std::unordered_map<T, std::shared_ptr<DL_node<T>>> node_map; // Для хранения уже созданных узлов

    int current_version;

public:
    // Конструктор, который принимает массив и его размер
    PersistentDoublyLinkedList(T* arr, int size) {
        if (size <= 0) {
            return; // Если массив пуст, просто возвращаем
        }

        // Создаем голову списка
        auto head = std::make_shared<DL_node<T>>(arr[0]);
        std::shared_ptr<DL_node<T>> current = head; // Храним указатель на текущий узел

        // Сохраняем первый узел в мапе
        //node_map[arr[0]] = head;

        // Проходим по массиву и создаем двусвязный список
        for (int i = 1; i < size; ++i) {
            auto new_node = std::make_shared<DL_node<T>>(arr[i]);
            current->next = new_node; // Присоединяем новый узел к текущему
            new_node->prev = current;  // Устанавливаем ссылку на предыдущий узел
            current = new_node; // Переходим к новому узлу

            // Сохраняем узел в мапе
            //node_map[arr[i]] = new_node;
        }

        // Сохраняем голову списка в вектор версий
        versions.push_back(head);
        current_version = 0;
    }

    // Метод для добавления нового узла в голову списка
    void push_front(T value) {
        auto new_head = std::make_shared<DL_node<T>>(value);
        new_head->next = versions.back(); // Новый узел указывает на текущую голову

        // Обновляем указатель на предыдущий узел новой головы, если он существует
        if (versions.back() != nullptr) {
            versions.back()->prev = new_head;
        }

        // Сохраняем новую версию (голову) списка
        versions.push_back(new_head);
        current_version++;
    }

    // Метод для печати всех версий списка без использования PrintList
    void printAllVersions() {
        for (int i = 0; i < versions.size(); ++i) {
            std::cout << "Version " << i << ": ";
            auto current = versions[i];

            // Проходим по всем узлам текущей версии и выводим их значения
            while (current) {
                std::cout << current->value << " (" << &(current->value) << ") ";
                current = current->next;
            }
            std::cout << std::endl; // Переход на новую строку после печати одной версии
        }
    }

    // Method to make UNDO-action
    void undo()
    {
        if (current_version <= 0)
        {
            std::cout << "No actions to undo!" << std::endl;
            return;
        }

        current_version--;
        versions.push_back(versions[current_version]);
    }

    // Method to make REDO-action
    void redo()
    {
        if (current_version >= versions.size() - 1) {
            std::cout << "No actions to redo!" << std::endl;
            return;
        }

        current_version++;  // Переход к следующей версии
        versions.push_back(versions[current_version]);
    }

    // Метод для добавления нового узла в конец списка
    void push_back(T value) {
        auto new_node = std::make_shared<DL_node<T>>(value);

        // Если это первая версия списка, то новый узел станет головой
        if (versions.empty()) {
            versions.push_back(new_node);
            current_version = 0;
            return;
        }

        auto last = versions.back(); // Получаем текущую версию (голову)

        // Находим последний узел (хвост) в текущей версии
        while (last->next) {
            last = last->next;
        }

        last->next = new_node; // Присоединяем новый узел к хвосту
        new_node->prev = last; // Устанавливаем ссылку на предыдущий узел

        // Сохраняем новую версию (голову) списка
        versions.push_back(versions.back());
        current_version++;
    }

};

Класс Convert:
template <typename T>
class Convert {
public:
    // Конвертация из PersistentArray в PersistentDoublyLinkedList
    static PersistentDoublyLinkedList<T> convertArrayToList(const PersistentArray<T>& array, size_t idx = 0) {
        // Получаем базовую версию массива
        const auto& base_version = array.getVersion(idx);
        return PersistentDoublyLinkedList<T>(base_version, base_version.size());
    }

    // Конвертация из PersistentDoublyLinkedList в PersistentArray
    static PersistentArray<T> convertListToArray(const PersistentDoublyLinkedList<T>& list, size_t idx = 0) {
        // Получаем базовую версию списка
        const auto head = list.getVersion(idx);

        std::vector<T> array;
        auto current = head;
        while (current) {
            array.push_back(current->value);
            current = current->next;
        }

        return PersistentArray<T>(array.data(), array.size());
    }
};