Как обеспечить ковариацию типов во время выполнения в C ++? - PullRequest
0 голосов
/ 06 декабря 2018

Допустим, у меня есть класс интерфейса и шаблонный подкласс

struct IPort {
    virtual bool can_connect_to(std::shared_ptr<IPort> p) = 0;
    std::shared_ptr<IPort> receiver;
};

template <class T>
struct Port : IPort {
    bool can_connect_to(std::shared_ptr<IPort> p) override {
        // what goes here?
    }

    void send(T* t) {
        auto p = std::static_pointer_cast<Port>(receiver);
        p->on_recv(t);
    }

    std::function<void(T*)> on_recv;
};

Параметр шаблона может быть любого типа.У меня есть несколько базовых типов (Base и Other ниже), а также производный тип (Derived).

struct Base {
    virtual const char* get_data() = 0;
    virtual size_t get_size() = 0;
};

struct Derived : public Base {
    std::string str;
    const char* get_data() override { return str.c_str(); }
    size_t get_size() override { return str.size(); }
};

struct Other {
    double x, y, z;
};

В идеале я должен иметь возможность отправлять производный тип из порта вдругой порт, который принимает базовый тип (например, Port<Derived> должен иметь возможность подключения к Port<Base>).С другой стороны, я не должен иметь возможность отправлять несовместимые типы (Port<Other> не должен иметь возможность подключаться к Port<Base>).

auto sender1 = std::make_shared<Port<Derived>>();
auto sender2 = std::make_shared<Port<Other>>();
auto receiver = std::make_shared<Port<Base>>([](Base* t) {
    // do something with t
});

sender1->can_connect_to(receiver); // should return true
sender2->can_connect_to(receiver); // should return false

Что можно вставить в can_connect_to, чтобы убедиться, чтопереданный порт имеет шаблонный тип, который является суперклассом шаблона отправляющего порта?

Кроме того, почему работает static_pointer_cast in send?Кажется, что это правильно, но я не понимаю, как это вообще допустимо в c ++, поскольку нет параметра шаблона для Port.

1 Ответ

0 голосов
/ 06 декабря 2018

Основной способ проверить, является ли объект "А" определенным классом или нет во время выполнения, равен dynamic_cast.Поэтому я думаю, что вам нужно:

template <class T>
bool Port<T>::can_connect_to(std::shared_ptr<IPort> p) {
    return dynamic_cast<T*>(p.get());
}

Это также вернет false, если p - нулевой указатель, что, вероятно, то, что вы хотите.

Кроме того, почемуstatic_pointer_cast в send работают?Кажется, что это правильно, но я не понимаю, как это вообще допустимо в c ++, поскольку нет параметра шаблона для Port.

Внутри определения шаблона класса или определениялюбое из его членов (или членов его вложенных членов класса и т. д.), имя шаблона может использоваться в качестве псевдонима для типа класса, который использует параметры шаблона этого определения.То есть, поскольку это использование Port появляется внутри определения template <class T> struct Port { ... };, имя Port без списка аргументов шаблона означает то же самое, что и Port<T>.Это называется «введенное имя класса».

...