Размер производного шаблонного класса во время компиляции в базовом классе - PullRequest
0 голосов
/ 05 января 2019

У меня есть существующая архитектура, которая использует полиморфные контейнеры для хранения экземпляров производных шаблонных классов. Теперь мне нужно переопределить оператор в базовом классе и объявить тип с размером производных классов во время компиляции.
Архитектура выглядит следующим образом: enter image description here

Я уже попробовал предварительное объявление шаблонных классов в заголовке базового класса, но безуспешно. И я также попытался сделать шаблон из базового класса, чтобы получить тип класса, но это не работает с полиморфными контейнерами.

заранее спасибо

1 Ответ

0 голосов
/ 05 января 2019

Проблема вашего дизайна в том, что класс Model не может знать размер своих производных классов, если он не знает, какой класс его выводит. Как вы правильно сказали, создание Model шаблона класса само по себе не позволит вам создать динамический контейнер Models.

Чтобы решить эту проблему, вы можете добавить слой статического полиморфизма (a.k.a CRTP) для достижения того, что вы хотите.

Идея состоит в том, чтобы получить Model из шаблонного базового класса ModelCRTPBase, который затем делегирует функциональные возможности интерфейса фактическим реализациям.

Очевидно, что по-прежнему не класс Model знает размер своих детей, а ModelCRTPBase. Но поскольку Model служит только полиморфным классом интерфейса, и все общие функциональные возможности моделей находятся в ModelCRTPBase (который знает размер во время компиляции), что не должно быть проблемой.

#include <iostream>
#include <vector>
#include <memory>


class Model {

public:
    virtual ~Model() {}
    virtual void print() = 0;
};

template<typename Derived>
class ModelCRTPBase : public Model {

    Derived& derived() {
        return static_cast<Derived&>(*this);
    }

public:

    static size_t  size() {
        return sizeof(Derived);
    }

    void print() override  {
        std::cout << "print Base, size = " << size() << '\n';
        derived().print_impl();
    }

};

template <typename T>
class ModelA : public ModelCRTPBase<ModelA<T>> {

public:

    void print_impl() {
        std::cout << "ModelA<" << typeid(T{}).name() << ">\n";
    }
};

template <typename T>
class ModelB : public ModelCRTPBase<ModelB<T>> {

    int payload;

public:

    void print_impl() {
        std::cout << "ModelB<" << typeid(T{}).name() << ">\n";
    }
};
int main() {

    std::vector<std::shared_ptr<Model>> vec;
    vec.push_back(std::make_shared<ModelA<int>>());
    vec.push_back(std::make_shared<ModelB<float>>());

    vec[0]->print();
    vec[1]->print();

}

Выходы:

print Base, size = 8
ModelA<i>
print Base, size = 16
ModelB<f>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...