Как получить доступ к базовому классу `polymorphic` для любого потомка` std :: variable`? - PullRequest
4 голосов
/ 06 октября 2019

Давайте предположим, что несколько дочерних классов для базового класса:

class Base 
{
public:
    void printHello() const { cout << "Hello" << endl; }
};

class Child1: public Base {};
class Child2: public Base {};
class Child3: public Base {};
..
class ChildN: public Base {};

Предположим, что вариант содержит любой из содержащихся классов:

using MyVariant = std::variant<Base, Child1, Child2, Child3, ... ChildN>;

Примечание: Интерес этого (по сравнению с простым вектором полиморфных указателей) состоит в том, чтобы все данные были в одном и том же массиве памяти, потому что они будут передаваться на устройство. В этом случае реальное содержимое каждого объекта находится в векторе, а не только указатель на некоторую heap позицию.

Наконец, давайте предположим, что я хочу работать с полиморфной версией Baseкаждого элемента vector<MyVariant>.

std::vector<MyVariant> myVariantList;
... // Initialization

for (const MyVariant& elem: myVariantList)
{
    const Base* baseElem = get_if_polymorph<Base>(elem); //HOW TO?
    baseElem->printHello();
}

Примечание: Очевидно, тривиальное решение иметь оператор if для каждого типа not намерение, потому что новые дочерние классы могут быть добавлены к MyVariant без необходимости изменять все дальнейшие использования. (Расширяемость)

Итак, еще один способ задать вопрос:

Как управлять полиморфизмом в std :: option?

1 Ответ

6 голосов
/ 06 октября 2019

Использование std::visit с общей лямбдой:

const Base& baseElem = std::visit(
    [](const auto& x) -> const Base& { return x; },
    elem);

Минимальный воспроизводимый пример:

#include <iostream>
#include <variant>
#include <vector>

struct Base {
    virtual void hi() const
    {
        std::cout << "Base\n";
    }
};

struct Derived1 : Base {
    void hi() const override
    {
        std::cout << "Derived1\n";
    }
};

struct Derived2 : Base {
    void hi() const override
    {
        std::cout << "Derived2\n";
    }
};

int main()
{
    using Var = std::variant<Base, Derived1, Derived2>;
    std::vector<Var> elems;
    elems.emplace_back(std::in_place_type<Base>);
    elems.emplace_back(std::in_place_type<Derived1>);
    elems.emplace_back(std::in_place_type<Derived2>);
    for (const auto& elem : elems) {
        const Base& x = std::visit(
            [](const auto& x) -> const Base& { return x; },
            elem);
        x.hi();
    }
}

Вывод:

Base
Derived1
Derived2

( live демо )

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...