Иерархия классов в шаблонных типах в C ++

Я работаю над простым проектом, в котором есть издатели, которые читают из одного источника данных и создают события для подписчиков.

Событие будет иметь уникальный ptr для данных, а подписчики будут иметь общий ptr для этого события.

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

#include <memory>
#include <iostream>

class Data
{

};

class ChildData : public Data
{
};

template<typename T>
class Event
{
    std::unique_ptr<T> _data;
};

void someFunc(Event<Data> event)
{
    std::cout << "hello Word" << std::endl;
}

int main()
{
    Event<ChildData> event();
    someFunc(event);
    return 0;
}

но я получаю следующую ошибку компилятора

/home/rory/dev/cpp_sandbox/main.cpp: In function ‘int main()’:
/home/rory/dev/cpp_sandbox/main.cpp:27:19: error: could not convert ‘event’ from ‘Event<ChildData> (*)()’ to ‘Event<Data>’
     someFunc(event);
                   ^
CMakeFiles/example.dir/build.make:62: recipe for target 'CMakeFiles/example.dir/main.cpp.o' failed
make[2]: *** [CMakeFiles/example.dir/main.cpp.o] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/example.dir/all' failed
make[1]: *** [CMakeFiles/example.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

Это возможно в C ++?

Всего 1 ответ


Проблемная линия такова:

Event<ChildData> event();

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

Event<ChildData> event{};

Кроме того, вам, вероятно, придется использовать std::move для передачи event someFunc , так как Event не может быть скопирован из-за члена данных std::unique_ptr . Также вам нужно будет выполнить преобразование из Event<ChildData> в Event<Data> , что необходимо для someFunc .

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

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

Чтобы различать разные типы событий, вы можете использовать перечисление.

enum class EventType
{
    A,
    B,
    C
};

class Data
{
private:
    const EventType m_type;

protected:
    explicit Data(EventType type) : m_type(type) {}

public:
    virtual ~Data() = default;

    // Prohibit copying to avoid accidental slicing
    Data(Data const&) = delete;
    Data& opreator= (Data const&) = delete;

    EventType get_type() const { return m_type; }
};

class ChildData :
    public Data
{
public:
    ChildData() : Data(EventType::A) {}
};

void receive(std::unique_ptr< Data > event)
{
    switch (event->get_type())
    {
    case EventType::A:
        {
            std::unique_ptr< ChildData > child_event{ static_cast< ChildData* >(event.release()) };
            // Process ChildData
        }
        break;

    case EventType::B:
        // ...
    case EventType::C:
        // ...
    }
}

void publish(std::unique_ptr< Data > event);

int main()
{
    std::unique_ptr< ChildData > event{ new ChildData() };
    // Fill ChildData event
    publish(std::move(event));
}

Есть идеи?

10000