Сложности множественного наследования QObject для вывода типа шаблона - PullRequest
0 голосов
/ 19 декабря 2018

Фон

Мне кажется, я нашел решение печально известной проблемы шаблонных сигналов и слотов в Qt.Для начала я определил пустой базовый класс Message, единственное назначение которого - наследоваться и создавать конкретные реализации TMessage.В Qt, хотя можно подключить сигнал к функтору (в отличие от слота Qt), сигнал не может быть функцией шаблона, поэтому я решил также смоделировать отношение класса Message, создавабстрактный Messenger класс, с сигналом void signal_Message(Message) и template <typename T> void slot_T(TMessage<T>).Затем я наткнулся на этот вопрос и этот вопрос, и понял, что это было гораздо более приемлемым решением, и я создал, по сути, мешок Messenger с.При использовании неподдерживаемого типа четный код завершается с ошибкой во время компиляции с хорошим читаемым сообщением об ошибке: invalid initialization of reference of type Messenger<double>& from expression of type MessengerBag<int, char>

Проблема

Предположим, что мы используем 6 различных типов, int, float, char, double, некоторые enum и struct.Это дает sizeof 96 байт!Однако, учитывая, что желаемое использование предназначено для мест с более чем 50 пользовательскими типами, каждый из которых имеет свои собственные отдельно поддерживаемые контейнеры сигналов и слотов, похоже, что мое решение может выполнить ту же задачу примерно с теми же издержками, но рядом снет затрат на техническое обслуживание.Помимо очевидных преимуществ, связанных с отсутствием необходимости поддерживать 24 отдельных функции, возможно, даже больше в случае схем с запутанным наследованием, есть ли недостатки этого подхода?После некоторого начального тестирования я обнаружил, что MessengerBag по сути является противоположностью ромбовидного узора.Каждый деструктор называется соответствующим образом, поэтому я не вижу практически никаких недостатков по сравнению с составной структурой, которая потребовала бы другого уровня (который я считаю ненужным и запутывающим) косвенности.Qt по существу презирает виртуальное наследование и запрещает его в классе, который непосредственно наследует QObject: поэтому я не могу сделать Mock виртуальным, как я бы предпочел.

Пример

// Message.h
struct Message {};
template <typename T> struct TMessage {
    T t
};

// Messenger.h
struct Messenger : public QObject {
    Q_OBJECT
public:
    template <typename T> void slot_doSomethingWithMsg(const Message& msg){
        const auto& tmsg = static_cast<const TMessage<T>&>(msg);
        qDebug() << tmsg.t;
        // do something else... this is just example usage
    }
signals:
    void signal_sendMsg(const BaseMsg& msg);

// MessengerBag.h

template <typename T, typename... Args>
struct MessengerBag : TMessenger<T>, MessengerBag<Args...>{};

template <typename T> struct MessengerBag<T> : TMessenger<T>{};

// Manager.h

MessengerBag<int, char> messengerBag;

Manager(){
    QObject::connect(static_cast<TMock<int>*>(messengerBag),
                     &Mock::signal_sendMsg, 
                     static_cast<TMock<int>*>(messengerBag),
                     &Mock::slot_doSomethingWithMsg<int>);

    QObject::connect(static_cast<TMock<char>*>(messengerBag),
                     &Mock::signal_sendMsg, 
                     static_cast<TMock<char>*>(messengerBag),
                     &Mock::slot_doSomethingWithMsg<char>);

template <typename T> void slot_sendMsg(const TMessage<T>& msg){
    TMessenger<T>& messenger = messengerBag;
    messenger.signal_sendMsg(msg);
}

// main.cpp

auto* manager = new Manager();

TMessage<int> imsg{5};
TMessage<char> cmsg{'f'};

manager->slot_sendMsg(imsg);
manager->slot_sendMsg(cmsg);

Как и ожидалось,Приведенный выше пример печатает 5 и 'f', тем самым устраняя проблему с шаблонными сигналами и слотами.Однако у меня возникли небольшие проблемы с рассмотрением возможных проблем в будущем.Одна проблема, конечно, заключается в том, что QObject недоступен, потому что QObject остается неизвестным, который может потенциально обеспечить посредничество композиционного решения (заставить TMessenger делегировать Messenger, а MessengerBag наследовать QObject в пустом ArgsСпециализация. Я не решаюсь принять это решение, предварительно не поняв его возможные недостатки. Также не стесняйтесь оставлять комментарии к самому коду.

tl; dr

Сигналы Qt вызывают функторы, но сигналыне может быть шаблонами. Есть ли какие-либо недостатки в том, что объект наследует несколько шаблонных классов, полученных из QObject, для создания сигналов стиля шаблона с использованием базового класса Message? Этот Message является параметром для сигнала(чтобы функтор сигналов и шаблонов имел базовую версию (после чего функтор приводил ее к правильному типу T). Структура будет служить пакетом этих шаблонных классов, унаследовав их все для того, чтобы разрешить передачу вправильный шаблон класса в любое время.

1 Ответ

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

Просто выстрелил в это ...

template<typename _Tb>
class _Ts : public _Tb 
{

public:
_Ts() {

// your connects

}

// any extensions to the qobject classes you are using
// note that you will need a common interface in your qobject subclasses... 
// meaning same named slots with different implementations 

};
...